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

What is this metal M-shaped device for?

How do you funnel food off a cutting board?

Can I string the D&D Starter Set campaign into another module, keeping the same characters?

How would an AI self awareness kill switch work?

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

Publishing research using outdated methods

One Half of Ten; A Riddle

What is the wife of a henpecked husband called?

Am I a Rude Number?

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

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

Avoiding morning and evening handshakes

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

Why "Points exist" is not an axiom in Geometry

Why avoid shared user accounts?

What happens to output if OPAMP its supply is tweaked?

Program that converts a number to a letter of the alphabet

Intern applicant asking for compensation equivalent to that of permanent employee

We are very unlucky in my court

What are "industrial chops"?

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

In Linux what happens if 1000 files in a directory are moved to another location while another 300 files were added to the source directory?

What's a good word to describe a public place that looks like it wouldn't be rough?

Dilemma of explaining to interviewer that he is the reason for declining second interview



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
    3 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    3 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
    3 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
    3 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.
    3 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
    3 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    3 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
    3 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
    3 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.
    3 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 2 hours ago







personal_cloud

















asked 3 hours ago









personal_cloudpersonal_cloud

826615




826615













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

    – P.W
    3 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    3 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
    3 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
    3 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.
    3 hours ago



















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

    – P.W
    3 hours ago













  • @P.W good idea. Done.

    – personal_cloud
    3 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
    3 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
    3 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.
    3 hours ago

















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

– P.W
3 hours ago







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

– P.W
3 hours ago















@P.W good idea. Done.

– personal_cloud
3 hours ago







@P.W good idea. Done.

– personal_cloud
3 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
3 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
3 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
3 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
3 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.
3 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.
3 hours ago












2 Answers
2






active

oldest

votes


















4














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
      1 hour 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









    4














    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






























      4














      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




























        4












        4








        4







        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 20 mins ago

























        answered 1 hour ago









        cpplearnercpplearner

        5,16521937




        5,16521937

























            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
              1 hour 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
              1 hour 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
              1 hour ago





















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

              – cpplearner
              1 hour ago



















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

            – cpplearner
            1 hour ago







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

            – cpplearner
            1 hour 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

            Benedict Cumberbatch Contingut Inicis Debut professional Premis Filmografia bàsica Premis i...

            Monticle de plataforma Contingut Est de Nord Amèrica Interpretacions Altres cultures Vegeu...

            Escacs Janus Enllaços externs Menú de navegacióEscacs JanusJanusschachBrainKing.comChessV