What are the differences between a+i and &a[i] for pointer arithmetic in C++?Does the 'offsetof' macro...

Why is working on the same position for more than 15 years not a red flag?

What is the wife of a henpecked husband called?

Intern applicant asking for compensation equivalent to that of permanent employee

Blindfold battle as a gladiatorial spectacle - what are the tactics and communication methods?

How to say "Brexit" in Latin?

Is there any other number that has similar properties as 21?

Why do stocks necessarily drop during a recession?

Can a hotel cancel a confirmed reservation?

Porting Linux to another platform requirements

If I delete my router's history can my ISP still provide it to my parents?

How to escape the null character in here-document?(bash and/or dash)

It took me a lot of time to make this, pls like. (YouTube Comments #1)

Why did other German political parties disband so fast when Hitler was appointed chancellor?

Can a person refuse a presidential pardon?

Why exactly do action photographers need high fps burst cameras?

Difference between `vector<int> v;` and `vector<int> v = vector<int>();`

Why do no American passenger airlines still operate dedicated cargo flights?

Is there any differences between "Gucken" and "Schauen"?

Who is this Ant Woman character in this image alongside the Wasp?

A starship is travelling at 0.9c and collides with a small rock. Will it leave a clean hole through, or will more happen?

How do Chazal know that the descendants of a Mamzer may never marry into the general populace?

Cookies - Should the toggles be on?

What is 6÷2×(1+2) =?

Early credit roll before the end of the film



What are the differences between a+i and &a[i] for pointer arithmetic in C++?


Does the 'offsetof' macro from <stddef.h> invoke undefined behaviour?The nullptr and pointer arithmeticWhat is the difference between #include <filename> and #include “filename”?What are the differences between a pointer variable and a reference variable in C++?What is a smart pointer and when should I use one?What is the difference between g++ and gcc?Difference between 'struct' and 'typedef struct' in C++?What is the effect of extern “C” in C++?What is the difference between const int*, const int * const, and int const *?What is the “-->” operator in C++?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?What is the difference between 'typedef' and 'using' in C++11?













6















Supposing we have:



char* a;
int i;


Many introductions to C++ (like this one) suggest that the rvalues a+i and &a[i] are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:




in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.




In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i] (within the offsetof macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i] causes undefined behavior in the case where a=null and i=0. This behavior is different from a+i (at least in C++, in the a=null, i=0 case).



This leads to at least 2 questions about the differences between a+i and &a[i]:



First, what is the underlying semantic difference between a+i and &a[i] that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i] might generate a memory access to a[i]? Or the spec author wasn't happy with null dereferences that day? Or something else?



Second, besides the case where a=null and i=0, are there any other cases where a+i and &a[i] behave differently? (could be covered by the first question, depending on the answer to it.)










share|improve this question

























  • You may want to add "language-lawyer" tag to this.

    – P.W
    4 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    4 hours ago













  • according to the answers here, a+i is undefined if a=null, though your 4th link says it is defined if i=0, hmmm

    – kmdreko
    4 hours ago













  • @kmdreko. That's a good point. I've tweaked the difference description to focus on the a=null, i=0 case for establishing that there is a difference between a+i and &a[i]... Again, leading one to wonder if there are any other differences between them.

    – personal_cloud
    4 hours ago






  • 2





    The intent of the standard never was to disallow &*a when a is a null pointer. This is a subject of issue 232.

    – n.m.
    4 hours ago
















6















Supposing we have:



char* a;
int i;


Many introductions to C++ (like this one) suggest that the rvalues a+i and &a[i] are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:




in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.




In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i] (within the offsetof macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i] causes undefined behavior in the case where a=null and i=0. This behavior is different from a+i (at least in C++, in the a=null, i=0 case).



This leads to at least 2 questions about the differences between a+i and &a[i]:



First, what is the underlying semantic difference between a+i and &a[i] that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i] might generate a memory access to a[i]? Or the spec author wasn't happy with null dereferences that day? Or something else?



Second, besides the case where a=null and i=0, are there any other cases where a+i and &a[i] behave differently? (could be covered by the first question, depending on the answer to it.)










share|improve this question

























  • You may want to add "language-lawyer" tag to this.

    – P.W
    4 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    4 hours ago













  • according to the answers here, a+i is undefined if a=null, though your 4th link says it is defined if i=0, hmmm

    – kmdreko
    4 hours ago













  • @kmdreko. That's a good point. I've tweaked the difference description to focus on the a=null, i=0 case for establishing that there is a difference between a+i and &a[i]... Again, leading one to wonder if there are any other differences between them.

    – personal_cloud
    4 hours ago






  • 2





    The intent of the standard never was to disallow &*a when a is a null pointer. This is a subject of issue 232.

    – n.m.
    4 hours ago














6












6








6


1






Supposing we have:



char* a;
int i;


Many introductions to C++ (like this one) suggest that the rvalues a+i and &a[i] are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:




in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.




In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i] (within the offsetof macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i] causes undefined behavior in the case where a=null and i=0. This behavior is different from a+i (at least in C++, in the a=null, i=0 case).



This leads to at least 2 questions about the differences between a+i and &a[i]:



First, what is the underlying semantic difference between a+i and &a[i] that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i] might generate a memory access to a[i]? Or the spec author wasn't happy with null dereferences that day? Or something else?



Second, besides the case where a=null and i=0, are there any other cases where a+i and &a[i] behave differently? (could be covered by the first question, depending on the answer to it.)










share|improve this question
















Supposing we have:



char* a;
int i;


Many introductions to C++ (like this one) suggest that the rvalues a+i and &a[i] are interchangeable. I naively believed this for several decades, until I recently stumbled upon the following text (here) quoted from [dcl.ref]:




in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by dereferencing a null pointer, which causes undefined behavior.




In other words, "binding" a reference object to a null-dereference causes undefined behavior. Based on the context of the above text, one infers that merely evaluating &a[i] (within the offsetof macro) is considered "binding" a reference. Furthermore, there seems to be a consensus that &a[i] causes undefined behavior in the case where a=null and i=0. This behavior is different from a+i (at least in C++, in the a=null, i=0 case).



This leads to at least 2 questions about the differences between a+i and &a[i]:



First, what is the underlying semantic difference between a+i and &a[i] that causes this difference in behavior. Can it be explained in terms of any kind of general principles, not just "binding a reference to a null dereference object causes undefined behavior just because this is a very specific case that everybody knows"? Is it that &a[i] might generate a memory access to a[i]? Or the spec author wasn't happy with null dereferences that day? Or something else?



Second, besides the case where a=null and i=0, are there any other cases where a+i and &a[i] behave differently? (could be covered by the first question, depending on the answer to it.)







c++ language-lawyer pointer-arithmetic






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 3 hours ago







personal_cloud

















asked 4 hours ago









personal_cloudpersonal_cloud

826615




826615













  • You may want to add "language-lawyer" tag to this.

    – P.W
    4 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    4 hours ago













  • according to the answers here, a+i is undefined if a=null, though your 4th link says it is defined if i=0, hmmm

    – kmdreko
    4 hours ago













  • @kmdreko. That's a good point. I've tweaked the difference description to focus on the a=null, i=0 case for establishing that there is a difference between a+i and &a[i]... Again, leading one to wonder if there are any other differences between them.

    – personal_cloud
    4 hours ago






  • 2





    The intent of the standard never was to disallow &*a when a is a null pointer. This is a subject of issue 232.

    – n.m.
    4 hours ago



















  • You may want to add "language-lawyer" tag to this.

    – P.W
    4 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    4 hours ago













  • according to the answers here, a+i is undefined if a=null, though your 4th link says it is defined if i=0, hmmm

    – kmdreko
    4 hours ago













  • @kmdreko. That's a good point. I've tweaked the difference description to focus on the a=null, i=0 case for establishing that there is a difference between a+i and &a[i]... Again, leading one to wonder if there are any other differences between them.

    – personal_cloud
    4 hours ago






  • 2





    The intent of the standard never was to disallow &*a when a is a null pointer. This is a subject of issue 232.

    – n.m.
    4 hours ago

















You may want to add "language-lawyer" tag to this.

– P.W
4 hours ago







You may want to add "language-lawyer" tag to this.

– P.W
4 hours ago















@P.W good idea. Done.

– personal_cloud
4 hours ago







@P.W good idea. Done.

– personal_cloud
4 hours ago















according to the answers here, a+i is undefined if a=null, though your 4th link says it is defined if i=0, hmmm

– kmdreko
4 hours ago







according to the answers here, a+i is undefined if a=null, though your 4th link says it is defined if i=0, hmmm

– kmdreko
4 hours ago















@kmdreko. That's a good point. I've tweaked the difference description to focus on the a=null, i=0 case for establishing that there is a difference between a+i and &a[i]... Again, leading one to wonder if there are any other differences between them.

– personal_cloud
4 hours ago





@kmdreko. That's a good point. I've tweaked the difference description to focus on the a=null, i=0 case for establishing that there is a difference between a+i and &a[i]... Again, leading one to wonder if there are any other differences between them.

– personal_cloud
4 hours ago




2




2





The intent of the standard never was to disallow &*a when a is a null pointer. This is a subject of issue 232.

– n.m.
4 hours ago





The intent of the standard never was to disallow &*a when a is a null pointer. This is a subject of issue 232.

– n.m.
4 hours ago












2 Answers
2






active

oldest

votes


















5














TL;DR: a+i and &a[i] are both well-formed and produce a null pointer when a is a null pointer and i is 0, according to (the intent of) the standard, and all compilers agree.





a+i is obviously well-formed per [expr.add]/4 of the latest draft standard:




When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.




  • If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

  • [...]




&a[i] is tricky. Per [expr.sub]/1, a[i] is equivalent to *(a+i), thus &a[i] is equivalent to &*(a+i). Now the standard is not quite clear about whether &*(a+i) is well-formed when a+i is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.





Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.



Here's the demo, if the compilers think the constant expression in static_assert is UB, or if they think the result is not true, then they must produce a diagnostic (error or warning) per standard:



(note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)



static_assert(nullptr == [](char* a=nullptr, int i=0) {
return a+i;
}());

static_assert(nullptr == [](char* a=nullptr, int i=0) {
return &a[i];
}());


From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).





However, this is different from the offset case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&), and thus is subject to the requirements on references.






share|improve this answer

































    3














    In the C++ standard, section [expr.sub]/1 you can read:




    The expression E1[E2] is identical (by definition) to *((E1)+(E2)).




    This means that &a[i] is exactly the same as &*(a+i). So you would dereference * a pointer first and get the address & second. In case the pointer is invalid (i.e. nullptr, but also out of range), this is UB.



    a+i is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:




    When an expression that has integral type is added to or subtracted
    from a pointer, the result has the type of the pointer operand. If the
    expression P points to element x[i] of an array object x with n
    elements, the expressions P + J and J + P (where J has the value j)
    point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
    n; otherwise, the behavior is undefined. Likewise, the expression P -
    J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
    ≤ n; otherwise, the behavior is undefined.




    So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.






    share|improve this answer
























    • But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

      – cpplearner
      2 hours ago













    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54938610%2fwhat-are-the-differences-between-ai-and-ai-for-pointer-arithmetic-in-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    TL;DR: a+i and &a[i] are both well-formed and produce a null pointer when a is a null pointer and i is 0, according to (the intent of) the standard, and all compilers agree.





    a+i is obviously well-formed per [expr.add]/4 of the latest draft standard:




    When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.




    • If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

    • [...]




    &a[i] is tricky. Per [expr.sub]/1, a[i] is equivalent to *(a+i), thus &a[i] is equivalent to &*(a+i). Now the standard is not quite clear about whether &*(a+i) is well-formed when a+i is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.





    Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.



    Here's the demo, if the compilers think the constant expression in static_assert is UB, or if they think the result is not true, then they must produce a diagnostic (error or warning) per standard:



    (note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)



    static_assert(nullptr == [](char* a=nullptr, int i=0) {
    return a+i;
    }());

    static_assert(nullptr == [](char* a=nullptr, int i=0) {
    return &a[i];
    }());


    From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).





    However, this is different from the offset case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&), and thus is subject to the requirements on references.






    share|improve this answer






























      5














      TL;DR: a+i and &a[i] are both well-formed and produce a null pointer when a is a null pointer and i is 0, according to (the intent of) the standard, and all compilers agree.





      a+i is obviously well-formed per [expr.add]/4 of the latest draft standard:




      When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.




      • If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

      • [...]




      &a[i] is tricky. Per [expr.sub]/1, a[i] is equivalent to *(a+i), thus &a[i] is equivalent to &*(a+i). Now the standard is not quite clear about whether &*(a+i) is well-formed when a+i is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.





      Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.



      Here's the demo, if the compilers think the constant expression in static_assert is UB, or if they think the result is not true, then they must produce a diagnostic (error or warning) per standard:



      (note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)



      static_assert(nullptr == [](char* a=nullptr, int i=0) {
      return a+i;
      }());

      static_assert(nullptr == [](char* a=nullptr, int i=0) {
      return &a[i];
      }());


      From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).





      However, this is different from the offset case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&), and thus is subject to the requirements on references.






      share|improve this answer




























        5












        5








        5







        TL;DR: a+i and &a[i] are both well-formed and produce a null pointer when a is a null pointer and i is 0, according to (the intent of) the standard, and all compilers agree.





        a+i is obviously well-formed per [expr.add]/4 of the latest draft standard:




        When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.




        • If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

        • [...]




        &a[i] is tricky. Per [expr.sub]/1, a[i] is equivalent to *(a+i), thus &a[i] is equivalent to &*(a+i). Now the standard is not quite clear about whether &*(a+i) is well-formed when a+i is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.





        Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.



        Here's the demo, if the compilers think the constant expression in static_assert is UB, or if they think the result is not true, then they must produce a diagnostic (error or warning) per standard:



        (note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)



        static_assert(nullptr == [](char* a=nullptr, int i=0) {
        return a+i;
        }());

        static_assert(nullptr == [](char* a=nullptr, int i=0) {
        return &a[i];
        }());


        From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).





        However, this is different from the offset case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&), and thus is subject to the requirements on references.






        share|improve this answer















        TL;DR: a+i and &a[i] are both well-formed and produce a null pointer when a is a null pointer and i is 0, according to (the intent of) the standard, and all compilers agree.





        a+i is obviously well-formed per [expr.add]/4 of the latest draft standard:




        When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.




        • If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

        • [...]




        &a[i] is tricky. Per [expr.sub]/1, a[i] is equivalent to *(a+i), thus &a[i] is equivalent to &*(a+i). Now the standard is not quite clear about whether &*(a+i) is well-formed when a+i is a null pointer. But as @n.m. points out in comment, the intent as recorded in cwg 232 is to permit this case.





        Since core language UB is required to be caught in a constant expression ([expr.const]/(4.6)), we can test whether compilers think these two expressions are UB.



        Here's the demo, if the compilers think the constant expression in static_assert is UB, or if they think the result is not true, then they must produce a diagnostic (error or warning) per standard:



        (note that this uses single-parameter static_assert and constexpr lambda which are C++17 features, and default lambda argument which is also pretty new)



        static_assert(nullptr == [](char* a=nullptr, int i=0) {
        return a+i;
        }());

        static_assert(nullptr == [](char* a=nullptr, int i=0) {
        return &a[i];
        }());


        From https://godbolt.org/z/hhsV4I, it seems all compilers behave uniformly in this case, producing no diagnostics at all (which surprises me a bit).





        However, this is different from the offset case. The implementation posted in that question explicitly creates a reference (which is necessary to sidestep user-defined operator&), and thus is subject to the requirements on references.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 1 hour ago

























        answered 2 hours ago









        cpplearnercpplearner

        5,17521937




        5,17521937

























            3














            In the C++ standard, section [expr.sub]/1 you can read:




            The expression E1[E2] is identical (by definition) to *((E1)+(E2)).




            This means that &a[i] is exactly the same as &*(a+i). So you would dereference * a pointer first and get the address & second. In case the pointer is invalid (i.e. nullptr, but also out of range), this is UB.



            a+i is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:




            When an expression that has integral type is added to or subtracted
            from a pointer, the result has the type of the pointer operand. If the
            expression P points to element x[i] of an array object x with n
            elements, the expressions P + J and J + P (where J has the value j)
            point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
            n; otherwise, the behavior is undefined. Likewise, the expression P -
            J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
            ≤ n; otherwise, the behavior is undefined.




            So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.






            share|improve this answer
























            • But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

              – cpplearner
              2 hours ago


















            3














            In the C++ standard, section [expr.sub]/1 you can read:




            The expression E1[E2] is identical (by definition) to *((E1)+(E2)).




            This means that &a[i] is exactly the same as &*(a+i). So you would dereference * a pointer first and get the address & second. In case the pointer is invalid (i.e. nullptr, but also out of range), this is UB.



            a+i is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:




            When an expression that has integral type is added to or subtracted
            from a pointer, the result has the type of the pointer operand. If the
            expression P points to element x[i] of an array object x with n
            elements, the expressions P + J and J + P (where J has the value j)
            point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
            n; otherwise, the behavior is undefined. Likewise, the expression P -
            J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
            ≤ n; otherwise, the behavior is undefined.




            So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.






            share|improve this answer
























            • But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

              – cpplearner
              2 hours ago
















            3












            3








            3







            In the C++ standard, section [expr.sub]/1 you can read:




            The expression E1[E2] is identical (by definition) to *((E1)+(E2)).




            This means that &a[i] is exactly the same as &*(a+i). So you would dereference * a pointer first and get the address & second. In case the pointer is invalid (i.e. nullptr, but also out of range), this is UB.



            a+i is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:




            When an expression that has integral type is added to or subtracted
            from a pointer, the result has the type of the pointer operand. If the
            expression P points to element x[i] of an array object x with n
            elements, the expressions P + J and J + P (where J has the value j)
            point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
            n; otherwise, the behavior is undefined. Likewise, the expression P -
            J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
            ≤ n; otherwise, the behavior is undefined.




            So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.






            share|improve this answer













            In the C++ standard, section [expr.sub]/1 you can read:




            The expression E1[E2] is identical (by definition) to *((E1)+(E2)).




            This means that &a[i] is exactly the same as &*(a+i). So you would dereference * a pointer first and get the address & second. In case the pointer is invalid (i.e. nullptr, but also out of range), this is UB.



            a+i is based on pointer arithmetics. At first it looks less dangerous since there is no dereferencing that would be UB for sure. However, it may also be UB (see [expr.add]/4:




            When an expression that has integral type is added to or subtracted
            from a pointer, the result has the type of the pointer operand. If the
            expression P points to element x[i] of an array object x with n
            elements, the expressions P + J and J + P (where J has the value j)
            point to the (possibly-hypothetical) element x[i + j] if 0 ≤ i + j ≤
            n; otherwise, the behavior is undefined. Likewise, the expression P -
            J points to the (possibly-hypothetical) element x[i − j] if 0 ≤ i − j
            ≤ n; otherwise, the behavior is undefined.




            So, while the semantics behind these two expression are slightly different, I would say that the result is the same in the end.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 2 hours ago









            ChristopheChristophe

            40.3k43576




            40.3k43576













            • But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

              – cpplearner
              2 hours ago





















            • But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

              – cpplearner
              2 hours ago



















            But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

            – cpplearner
            2 hours ago







            But see [expr.add]/7 of C++17 DIS, or [expr.add]/(4.1) of the current draft standard.

            – cpplearner
            2 hours ago




















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54938610%2fwhat-are-the-differences-between-ai-and-ai-for-pointer-arithmetic-in-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can't compile dgruyter and caption packagesLaTeX templates/packages for writing a patent specificationLatex...

            Schneeberg (Smreczany) Bibliografia | Menu...

            Hans Bellmer Spis treści Życiorys | Upamiętnienie | Przypisy | Bibliografia | Linki zewnętrzne |...