Understanding allocated memory addresses in array elements in C (gcc in Windows 10)












2















I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:



#include <stdio.h>

int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };

printf("sizeof(int) = %un-----n", sizeof(int));

printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);

printf("sizeof(ar) = %un-----n", sizeof(ar));

printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);

printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));

printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);

printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));

printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);

printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));

return 0;
}


The output I get on my system is:



sizeof(int)      = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30

sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28

sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30

sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C

sizeof(ar[0][0]) = 4
-----


I understand why ar is 16 bytes in size; it should be able to hold 4 ints, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1 and &ar is (hex) 30 - 20 = 16.



What I don't understand is why the difference between ar + 1 and ar is only 8 bytes. This would mean that the array can only hold 2 ints á 4 bytes.



I have the same problem understanding ar[0] and ar[1] as you can see in my code.



Shouldn't ar + 1 and &ar + 1 produce the same result?










share|improve this question

























  • You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]

    – SPlatten
    Nov 26 '18 at 10:44













  • Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?

    – Jens M.
    Nov 26 '18 at 11:12


















2















I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:



#include <stdio.h>

int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };

printf("sizeof(int) = %un-----n", sizeof(int));

printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);

printf("sizeof(ar) = %un-----n", sizeof(ar));

printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);

printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));

printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);

printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));

printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);

printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));

return 0;
}


The output I get on my system is:



sizeof(int)      = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30

sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28

sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30

sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C

sizeof(ar[0][0]) = 4
-----


I understand why ar is 16 bytes in size; it should be able to hold 4 ints, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1 and &ar is (hex) 30 - 20 = 16.



What I don't understand is why the difference between ar + 1 and ar is only 8 bytes. This would mean that the array can only hold 2 ints á 4 bytes.



I have the same problem understanding ar[0] and ar[1] as you can see in my code.



Shouldn't ar + 1 and &ar + 1 produce the same result?










share|improve this question

























  • You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]

    – SPlatten
    Nov 26 '18 at 10:44













  • Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?

    – Jens M.
    Nov 26 '18 at 11:12
















2












2








2








I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:



#include <stdio.h>

int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };

printf("sizeof(int) = %un-----n", sizeof(int));

printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);

printf("sizeof(ar) = %un-----n", sizeof(ar));

printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);

printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));

printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);

printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));

printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);

printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));

return 0;
}


The output I get on my system is:



sizeof(int)      = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30

sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28

sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30

sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C

sizeof(ar[0][0]) = 4
-----


I understand why ar is 16 bytes in size; it should be able to hold 4 ints, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1 and &ar is (hex) 30 - 20 = 16.



What I don't understand is why the difference between ar + 1 and ar is only 8 bytes. This would mean that the array can only hold 2 ints á 4 bytes.



I have the same problem understanding ar[0] and ar[1] as you can see in my code.



Shouldn't ar + 1 and &ar + 1 produce the same result?










share|improve this question
















I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. Here's my example code:



#include <stdio.h>

int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };

printf("sizeof(int) = %un-----n", sizeof(int));

printf("ar = %pn", ar);
printf("ar + 1 = %pn", ar + 1);
printf("&ar = %pn", &ar);
printf("&ar + 1 = %pnn", &ar + 1);

printf("sizeof(ar) = %un-----n", sizeof(ar));

printf("ar[0] = %pn", ar[0]);
printf("ar[0] + 1 = %pn", ar[0] + 1);
printf("&ar[0] = %pn", &ar[0]);
printf("&ar[0] + 1 = %pnn", &ar[0] + 1);

printf("sizeof(ar[0]) = %un-----n", sizeof(ar[0]));

printf("ar[1] = %pn", ar[1]);
printf("ar[1] + 1 = %pn", ar[1] + 1);
printf("&ar[1] = %pn", &ar[1]);
printf("&ar[1] + 1 = %pnn", &ar[1] + 1);

printf("sizeof(ar[1]) = %un-----n", sizeof(ar[1]));

printf("&ar[0][0] = %pn", &ar[0][0]);
printf("&ar[0][0] + 1 = %pn", &ar[0][0] + 1);
printf("&ar[1][0] = %pn", &ar[1][0]);
printf("&ar[1][0] + 1 = %pnn", &ar[1][0] + 1);

printf("sizeof(ar[0][0]) = %un-----n", sizeof(ar[0][0]));

return 0;
}


The output I get on my system is:



sizeof(int)      = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30

sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28

sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30

sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C

sizeof(ar[0][0]) = 4
-----


I understand why ar is 16 bytes in size; it should be able to hold 4 ints, which on my system is 4x4 = 16 bytes. This, I guess, is also why the difference in bytes between &ar + 1 and &ar is (hex) 30 - 20 = 16.



What I don't understand is why the difference between ar + 1 and ar is only 8 bytes. This would mean that the array can only hold 2 ints á 4 bytes.



I have the same problem understanding ar[0] and ar[1] as you can see in my code.



Shouldn't ar + 1 and &ar + 1 produce the same result?







c arrays memory pointer-arithmetic






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 26 '18 at 10:47









Sourav Ghosh

111k15132191




111k15132191










asked Nov 26 '18 at 10:30









Jens M.Jens M.

132




132













  • You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]

    – SPlatten
    Nov 26 '18 at 10:44













  • Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?

    – Jens M.
    Nov 26 '18 at 11:12





















  • You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]

    – SPlatten
    Nov 26 '18 at 10:44













  • Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?

    – Jens M.
    Nov 26 '18 at 11:12



















You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]

– SPlatten
Nov 26 '18 at 10:44







You need to use () to set the order of precedence, has the highest precedence after (), your expressions will not be what you expect as they are currently written. eg. *ar[0] is not the same as (*ar)[0]

– SPlatten
Nov 26 '18 at 10:44















Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?

– Jens M.
Nov 26 '18 at 11:12







Good point, thanks. However, in my code, I want the address of ar[0], is it not sufficient with &ar[0] or should I use &(ar[0])?

– Jens M.
Nov 26 '18 at 11:12














3 Answers
3






active

oldest

votes


















2














In your case, ar is an array. Hence, first of all, remember





  • ar is type of int [2][2], which is an array of array of ints


  • &ar is of type int (*)[2][2], i.e., pointer to an array of array of 2 ints.


That said, array type, in cases, decay to the pointer to the first element of the array.Note



So, in case of an expression like



ar + 1


is just the same as



(&(ar[0])) + 1;


which basically points to ar[1].




What I don't understand is why the difference between ar + 1 and ar is only 8 bytes




So, the "difference" here, is by the size occupied by the elements of ar[0], which is , 2 ints, which is, in your platform, 8 bytes. Result checks out.



On the other hand, for an expression like



&ar + 1;


it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 ints each, hence (2*2*4) = 16 bytes.





Note:



Quoting C11, chapter §6.3.2.1




Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]







share|improve this answer

































    2














    ar, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1 gives arithmetic on a pointer of type int (*)[2]. Which points to an int [2] with size 8 bytes.



    This rule of "array decay" is specified in C17 6.3.2.1 §3:




    Except when it is the operand of the sizeof operator, or the unary & operator, or is a
    string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
    converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
    the array object and is not an lvalue




    So when you type &ar, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2] as expected. And therefore &ar + 1 gives 16 bytes.






    share|improve this answer































      0














      So:



      sizeof(int) == 4


      The following:



      int ar[2][2];


      is a 2D array.



      We know that, a[b] is equal to *(a + b). And &* is converted to nothing.



      So:



      &ar[1]


      is equal to



      (ar + 1)


      here ar "decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]. So it's not an int * nor int[2][2] pointer but int (*)[2]. We know that



      sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
      sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
      sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)


      So



      (ar + 1)


      is equal to (to the value):



      (uintptr_t)ar + sizeof(*ar) * 1 == 
      (uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
      (uintptr_t)ar + sizeof(int[2]) * 1) ==
      (uintptr_t)ar + sizeof(int) * 2 * 1)


      ie. it increments the ar pointer value by 2 * sizeof(int).




      What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.




      ar + 1 is equal to



      (uintptr_t)ar + sizeof(*ar) + 1


      As ar is int[2][2], then *ar is int[2], so sizeof(*ar) = sizeof(int) * 2.

      So ar + 1 is equal to



      (uintptr_t)ar + sizeof(int) * 2 * 1


      So (ar + 1) - ar is equal to



      ((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
      sizeof(int[2]) ==
      sizeof(int) * 2



      Shouldn't ar + 1 and &ar + 1 produce the same result?




      In case of arrays like int array[2]; The array pointer value is equal to &array pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array has a type of int[2][2], but &array has the type of int(*)[2][2], ie. it is a pointer to 2d array.



      Because the type changes, the pointer arithmetics changes. Teh typeof(ar) decays to typeof(int(*)[2]) so the ar + 1 is equal to



      `(uintptr_t)ar + sizeof(int[2]) * 1`. 


      But because the typeof(&ar) == typeof(int(*)[2][2]) the &ar + 1 is equal to



      `(uintrpt_t)ar + sizeof(int[2][2]) * 1`.


      hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2]) is equal to sizeof(int) * 2 * 2.



      I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0]) is an array of two int elements.



      Your code has UB, as the %p modifer should be used only with void* pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1); cast your pointers.






      share|improve this answer


























        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%2f53479169%2funderstanding-allocated-memory-addresses-in-array-elements-in-c-gcc-in-windows%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        2














        In your case, ar is an array. Hence, first of all, remember





        • ar is type of int [2][2], which is an array of array of ints


        • &ar is of type int (*)[2][2], i.e., pointer to an array of array of 2 ints.


        That said, array type, in cases, decay to the pointer to the first element of the array.Note



        So, in case of an expression like



        ar + 1


        is just the same as



        (&(ar[0])) + 1;


        which basically points to ar[1].




        What I don't understand is why the difference between ar + 1 and ar is only 8 bytes




        So, the "difference" here, is by the size occupied by the elements of ar[0], which is , 2 ints, which is, in your platform, 8 bytes. Result checks out.



        On the other hand, for an expression like



        &ar + 1;


        it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 ints each, hence (2*2*4) = 16 bytes.





        Note:



        Quoting C11, chapter §6.3.2.1




        Except when it is the operand of the sizeof operator, the _Alignof operator, or the
        unary & operator, or is a string literal used to initialize an array, an expression that has
        type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
        to the initial element of the array object and is not an lvalue. [....]







        share|improve this answer






























          2














          In your case, ar is an array. Hence, first of all, remember





          • ar is type of int [2][2], which is an array of array of ints


          • &ar is of type int (*)[2][2], i.e., pointer to an array of array of 2 ints.


          That said, array type, in cases, decay to the pointer to the first element of the array.Note



          So, in case of an expression like



          ar + 1


          is just the same as



          (&(ar[0])) + 1;


          which basically points to ar[1].




          What I don't understand is why the difference between ar + 1 and ar is only 8 bytes




          So, the "difference" here, is by the size occupied by the elements of ar[0], which is , 2 ints, which is, in your platform, 8 bytes. Result checks out.



          On the other hand, for an expression like



          &ar + 1;


          it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 ints each, hence (2*2*4) = 16 bytes.





          Note:



          Quoting C11, chapter §6.3.2.1




          Except when it is the operand of the sizeof operator, the _Alignof operator, or the
          unary & operator, or is a string literal used to initialize an array, an expression that has
          type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
          to the initial element of the array object and is not an lvalue. [....]







          share|improve this answer




























            2












            2








            2







            In your case, ar is an array. Hence, first of all, remember





            • ar is type of int [2][2], which is an array of array of ints


            • &ar is of type int (*)[2][2], i.e., pointer to an array of array of 2 ints.


            That said, array type, in cases, decay to the pointer to the first element of the array.Note



            So, in case of an expression like



            ar + 1


            is just the same as



            (&(ar[0])) + 1;


            which basically points to ar[1].




            What I don't understand is why the difference between ar + 1 and ar is only 8 bytes




            So, the "difference" here, is by the size occupied by the elements of ar[0], which is , 2 ints, which is, in your platform, 8 bytes. Result checks out.



            On the other hand, for an expression like



            &ar + 1;


            it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 ints each, hence (2*2*4) = 16 bytes.





            Note:



            Quoting C11, chapter §6.3.2.1




            Except when it is the operand of the sizeof operator, the _Alignof operator, or the
            unary & operator, or is a string literal used to initialize an array, an expression that has
            type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
            to the initial element of the array object and is not an lvalue. [....]







            share|improve this answer















            In your case, ar is an array. Hence, first of all, remember





            • ar is type of int [2][2], which is an array of array of ints


            • &ar is of type int (*)[2][2], i.e., pointer to an array of array of 2 ints.


            That said, array type, in cases, decay to the pointer to the first element of the array.Note



            So, in case of an expression like



            ar + 1


            is just the same as



            (&(ar[0])) + 1;


            which basically points to ar[1].




            What I don't understand is why the difference between ar + 1 and ar is only 8 bytes




            So, the "difference" here, is by the size occupied by the elements of ar[0], which is , 2 ints, which is, in your platform, 8 bytes. Result checks out.



            On the other hand, for an expression like



            &ar + 1;


            it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. So, the difference is, for 2 arrays of 2 ints each, hence (2*2*4) = 16 bytes.





            Note:



            Quoting C11, chapter §6.3.2.1




            Except when it is the operand of the sizeof operator, the _Alignof operator, or the
            unary & operator, or is a string literal used to initialize an array, an expression that has
            type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
            to the initial element of the array object and is not an lvalue. [....]








            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 26 '18 at 10:44

























            answered Nov 26 '18 at 10:37









            Sourav GhoshSourav Ghosh

            111k15132191




            111k15132191

























                2














                ar, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1 gives arithmetic on a pointer of type int (*)[2]. Which points to an int [2] with size 8 bytes.



                This rule of "array decay" is specified in C17 6.3.2.1 §3:




                Except when it is the operand of the sizeof operator, or the unary & operator, or is a
                string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
                converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
                the array object and is not an lvalue




                So when you type &ar, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2] as expected. And therefore &ar + 1 gives 16 bytes.






                share|improve this answer




























                  2














                  ar, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1 gives arithmetic on a pointer of type int (*)[2]. Which points to an int [2] with size 8 bytes.



                  This rule of "array decay" is specified in C17 6.3.2.1 §3:




                  Except when it is the operand of the sizeof operator, or the unary & operator, or is a
                  string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
                  converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
                  the array object and is not an lvalue




                  So when you type &ar, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2] as expected. And therefore &ar + 1 gives 16 bytes.






                  share|improve this answer


























                    2












                    2








                    2







                    ar, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1 gives arithmetic on a pointer of type int (*)[2]. Which points to an int [2] with size 8 bytes.



                    This rule of "array decay" is specified in C17 6.3.2.1 §3:




                    Except when it is the operand of the sizeof operator, or the unary & operator, or is a
                    string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
                    converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
                    the array object and is not an lvalue




                    So when you type &ar, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2] as expected. And therefore &ar + 1 gives 16 bytes.






                    share|improve this answer













                    ar, when used in an expression, "decays" to a pointer to the first element. In this case, arr + 1 gives arithmetic on a pointer of type int (*)[2]. Which points to an int [2] with size 8 bytes.



                    This rule of "array decay" is specified in C17 6.3.2.1 §3:




                    Except when it is the operand of the sizeof operator, or the unary & operator, or is a
                    string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
                    converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
                    the array object and is not an lvalue




                    So when you type &ar, you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2] as expected. And therefore &ar + 1 gives 16 bytes.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 26 '18 at 10:40









                    LundinLundin

                    112k17163271




                    112k17163271























                        0














                        So:



                        sizeof(int) == 4


                        The following:



                        int ar[2][2];


                        is a 2D array.



                        We know that, a[b] is equal to *(a + b). And &* is converted to nothing.



                        So:



                        &ar[1]


                        is equal to



                        (ar + 1)


                        here ar "decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]. So it's not an int * nor int[2][2] pointer but int (*)[2]. We know that



                        sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
                        sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
                        sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)


                        So



                        (ar + 1)


                        is equal to (to the value):



                        (uintptr_t)ar + sizeof(*ar) * 1 == 
                        (uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
                        (uintptr_t)ar + sizeof(int[2]) * 1) ==
                        (uintptr_t)ar + sizeof(int) * 2 * 1)


                        ie. it increments the ar pointer value by 2 * sizeof(int).




                        What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.




                        ar + 1 is equal to



                        (uintptr_t)ar + sizeof(*ar) + 1


                        As ar is int[2][2], then *ar is int[2], so sizeof(*ar) = sizeof(int) * 2.

                        So ar + 1 is equal to



                        (uintptr_t)ar + sizeof(int) * 2 * 1


                        So (ar + 1) - ar is equal to



                        ((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
                        sizeof(int[2]) ==
                        sizeof(int) * 2



                        Shouldn't ar + 1 and &ar + 1 produce the same result?




                        In case of arrays like int array[2]; The array pointer value is equal to &array pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array has a type of int[2][2], but &array has the type of int(*)[2][2], ie. it is a pointer to 2d array.



                        Because the type changes, the pointer arithmetics changes. Teh typeof(ar) decays to typeof(int(*)[2]) so the ar + 1 is equal to



                        `(uintptr_t)ar + sizeof(int[2]) * 1`. 


                        But because the typeof(&ar) == typeof(int(*)[2][2]) the &ar + 1 is equal to



                        `(uintrpt_t)ar + sizeof(int[2][2]) * 1`.


                        hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2]) is equal to sizeof(int) * 2 * 2.



                        I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0]) is an array of two int elements.



                        Your code has UB, as the %p modifer should be used only with void* pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1); cast your pointers.






                        share|improve this answer






























                          0














                          So:



                          sizeof(int) == 4


                          The following:



                          int ar[2][2];


                          is a 2D array.



                          We know that, a[b] is equal to *(a + b). And &* is converted to nothing.



                          So:



                          &ar[1]


                          is equal to



                          (ar + 1)


                          here ar "decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]. So it's not an int * nor int[2][2] pointer but int (*)[2]. We know that



                          sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
                          sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
                          sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)


                          So



                          (ar + 1)


                          is equal to (to the value):



                          (uintptr_t)ar + sizeof(*ar) * 1 == 
                          (uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
                          (uintptr_t)ar + sizeof(int[2]) * 1) ==
                          (uintptr_t)ar + sizeof(int) * 2 * 1)


                          ie. it increments the ar pointer value by 2 * sizeof(int).




                          What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.




                          ar + 1 is equal to



                          (uintptr_t)ar + sizeof(*ar) + 1


                          As ar is int[2][2], then *ar is int[2], so sizeof(*ar) = sizeof(int) * 2.

                          So ar + 1 is equal to



                          (uintptr_t)ar + sizeof(int) * 2 * 1


                          So (ar + 1) - ar is equal to



                          ((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
                          sizeof(int[2]) ==
                          sizeof(int) * 2



                          Shouldn't ar + 1 and &ar + 1 produce the same result?




                          In case of arrays like int array[2]; The array pointer value is equal to &array pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array has a type of int[2][2], but &array has the type of int(*)[2][2], ie. it is a pointer to 2d array.



                          Because the type changes, the pointer arithmetics changes. Teh typeof(ar) decays to typeof(int(*)[2]) so the ar + 1 is equal to



                          `(uintptr_t)ar + sizeof(int[2]) * 1`. 


                          But because the typeof(&ar) == typeof(int(*)[2][2]) the &ar + 1 is equal to



                          `(uintrpt_t)ar + sizeof(int[2][2]) * 1`.


                          hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2]) is equal to sizeof(int) * 2 * 2.



                          I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0]) is an array of two int elements.



                          Your code has UB, as the %p modifer should be used only with void* pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1); cast your pointers.






                          share|improve this answer




























                            0












                            0








                            0







                            So:



                            sizeof(int) == 4


                            The following:



                            int ar[2][2];


                            is a 2D array.



                            We know that, a[b] is equal to *(a + b). And &* is converted to nothing.



                            So:



                            &ar[1]


                            is equal to



                            (ar + 1)


                            here ar "decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]. So it's not an int * nor int[2][2] pointer but int (*)[2]. We know that



                            sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
                            sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
                            sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)


                            So



                            (ar + 1)


                            is equal to (to the value):



                            (uintptr_t)ar + sizeof(*ar) * 1 == 
                            (uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
                            (uintptr_t)ar + sizeof(int[2]) * 1) ==
                            (uintptr_t)ar + sizeof(int) * 2 * 1)


                            ie. it increments the ar pointer value by 2 * sizeof(int).




                            What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.




                            ar + 1 is equal to



                            (uintptr_t)ar + sizeof(*ar) + 1


                            As ar is int[2][2], then *ar is int[2], so sizeof(*ar) = sizeof(int) * 2.

                            So ar + 1 is equal to



                            (uintptr_t)ar + sizeof(int) * 2 * 1


                            So (ar + 1) - ar is equal to



                            ((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
                            sizeof(int[2]) ==
                            sizeof(int) * 2



                            Shouldn't ar + 1 and &ar + 1 produce the same result?




                            In case of arrays like int array[2]; The array pointer value is equal to &array pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array has a type of int[2][2], but &array has the type of int(*)[2][2], ie. it is a pointer to 2d array.



                            Because the type changes, the pointer arithmetics changes. Teh typeof(ar) decays to typeof(int(*)[2]) so the ar + 1 is equal to



                            `(uintptr_t)ar + sizeof(int[2]) * 1`. 


                            But because the typeof(&ar) == typeof(int(*)[2][2]) the &ar + 1 is equal to



                            `(uintrpt_t)ar + sizeof(int[2][2]) * 1`.


                            hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2]) is equal to sizeof(int) * 2 * 2.



                            I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0]) is an array of two int elements.



                            Your code has UB, as the %p modifer should be used only with void* pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1); cast your pointers.






                            share|improve this answer















                            So:



                            sizeof(int) == 4


                            The following:



                            int ar[2][2];


                            is a 2D array.



                            We know that, a[b] is equal to *(a + b). And &* is converted to nothing.



                            So:



                            &ar[1]


                            is equal to



                            (ar + 1)


                            here ar "decays" or "shall be adjusted" (read as: magically converts) into a pointer. A pointer to an array of two int elements, ie. int (*)[2]. So it's not an int * nor int[2][2] pointer but int (*)[2]. We know that



                            sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
                            sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
                            sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)


                            So



                            (ar + 1)


                            is equal to (to the value):



                            (uintptr_t)ar + sizeof(*ar) * 1 == 
                            (uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
                            (uintptr_t)ar + sizeof(int[2]) * 1) ==
                            (uintptr_t)ar + sizeof(int) * 2 * 1)


                            ie. it increments the ar pointer value by 2 * sizeof(int).




                            What I don't understand is why the difference between ar + 1 and ar is only 8 bytes.




                            ar + 1 is equal to



                            (uintptr_t)ar + sizeof(*ar) + 1


                            As ar is int[2][2], then *ar is int[2], so sizeof(*ar) = sizeof(int) * 2.

                            So ar + 1 is equal to



                            (uintptr_t)ar + sizeof(int) * 2 * 1


                            So (ar + 1) - ar is equal to



                            ((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
                            sizeof(int[2]) ==
                            sizeof(int) * 2



                            Shouldn't ar + 1 and &ar + 1 produce the same result?




                            In case of arrays like int array[2]; The array pointer value is equal to &array pointer value. It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. Through array has a type of int[2][2], but &array has the type of int(*)[2][2], ie. it is a pointer to 2d array.



                            Because the type changes, the pointer arithmetics changes. Teh typeof(ar) decays to typeof(int(*)[2]) so the ar + 1 is equal to



                            `(uintptr_t)ar + sizeof(int[2]) * 1`. 


                            But because the typeof(&ar) == typeof(int(*)[2][2]) the &ar + 1 is equal to



                            `(uintrpt_t)ar + sizeof(int[2][2]) * 1`.


                            hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2]) is equal to sizeof(int) * 2 * 2.



                            I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. So typeof(ar[0]) is an array of two int elements.



                            Your code has UB, as the %p modifer should be used only with void* pointers. It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1); cast your pointers.







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Nov 26 '18 at 10:59

























                            answered Nov 26 '18 at 10:51









                            Kamil CukKamil Cuk

                            12.7k1529




                            12.7k1529






























                                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%2f53479169%2funderstanding-allocated-memory-addresses-in-array-elements-in-c-gcc-in-windows%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

                                Costa Masnaga

                                Fotorealismo

                                Sidney Franklin