1

I am studying the basics in C and I am confused about the strings and arrays.

    #include<stdio.h>
    int main()
    {
      char arr[2][4] = {1,2,3,4,5,6,7,8};
      printf("%u %u\n",arr,arr+1);
      printf("%d",*(*(arr+1)+2) );
      return 0;
    }

Here arr and arr+1 are adjacent locations, but in the second printf arr+1 goes straight to the zero index element of the second array. How is this legal? I have thought that to go to the second array it should be &arr+1.


What i learned is --> for one dimensional array:

  arr[7]={1,2,3,4,5,6,7};

here arr and &arr should not be considered same(although they print same value, but the sense of this information is completely different) . Thats why arr+1 and &arr+1 will not be same too. &arr gives the address of a data type that is a container of 7 integers thats why &arr+1 goes to the subsequent array type that is also a container of 7 integers . so

arr = 5796 , &arr = 5796    (both are base address but arr is the address of    
                   1st element while &arr is the address of the whole array)
arr+1 = 5800 ,&arr+1 = (5796+(7X4))=5797+28 = 5825(this is address of some 
new array)

for two dimensional array the concept is same:

arr[2][4]={1,2,3,4,5,6,7,8};

now arr is here is also a pointer that points to array individual elements so arr and arr+1 are the addresses of its successive elements (and those elements are {1,2,3,4} and {5,6,7,8})_ and in the same way &arr and &arr+1 gives the base addresses of two arrays that have 2x4=8 elements so to &arr and &arr+1 are addresses of two similar sized arrays one after another. So

 arr = 5796 , arr+1 = 5796+(4*3)=5796+12 = 5808 
 &arr = 5796 , &arr+1 = 5796+(4*7)=5796+ 28= 5824

Now we can see in 2 dimensional array to reach an individual element there are two addresses associated.

1)arr (that gives which element to choose between the two inside arrays)
2)*arr (that gives which element in that particular element(array)

so we need to dereference two times if we want to reach to the data.

arr=5796(first array), *arr=5796(first element address), **arr = 1 (1st element)
arr+1=5812(second array), *(arr+1) = 5812(first element address), *(*(arr+1))=5(first element)
arr=5796,*arr=5796, *arr+1=5796+1(second element), *(*arr+1)=2 (second element)

now the syntax for arrays:

   *arr = arr[0]
   **arr = arr[0][0]
   *arr+1 = arr[0]+1
   **arr+1 = arr[0][0]+1
   *(*arr+1) = *(arr[0]+1) = arr[0][1]
   *(*(arr+1)+1) = *(arr[1]+1) = arr[1][1]

there are some other ways to write arrays

      3[arr[1]] = arr[1][3]
      -3[arr[1]] = -arr[1][3]
      *(1[arr]+2) = *(arr[1]+2) = arr[1][2]

the concept can be expanded to 3 dimensional array too , but this is the minimum every beginner should understand.Correct me if I am wrong anywhere conceptually or syntactically.

haccks
  • 104,019
  • 25
  • 176
  • 264
mrigendra
  • 1,472
  • 3
  • 19
  • 33
  • 1
    Read [Why is the same value outputted for `A[0]`, `&A`, and `*A`?](http://stackoverflow.com/questions/17623556/why-is-the-same-value-outputted-for-a0-a-and-a/17623640#17623640) – Grijesh Chauhan Oct 03 '13 at 11:31
  • 1
    *`Here arr and arr+1 are adjacent locations`* No..`arr` and `arr + 1` are adjacent **rows** address. Note `arr` is not decays into address of int, not `&arr[0][0]`, but address of complete row. – Grijesh Chauhan Oct 03 '13 at 11:43
  • you are right .. i did not saw the results correcly and misinterpreted it. arr and arr+1 are not adjacent and arr= *arr = *(arr+0) and arr+1 = *(arr+1) in this case – mrigendra Oct 03 '13 at 11:50
  • Try this code `printf(" %p %p %p", (void*)&arr, (void*)arr, (void*)*arr);` you will find same output, So value wise all are equal but semantically all are diffrent. Give it a try. – Grijesh Chauhan Oct 03 '13 at 11:52
  • 1
    Read: [What does sizeof(&array) return?](http://stackoverflow.com/questions/15177420/what-does-sizeofarray-return/15177499#15177499) I explained for one dimensional array. and in that answer given link for two dimensional array. – Grijesh Chauhan Oct 03 '13 at 11:54
  • @mrigendra; `arr+1 != *(arr+1)` – haccks Oct 03 '13 at 11:57
  • @haccks i printed it and values are same. – mrigendra Oct 03 '13 at 12:02
  • @mrigendra; Do you think that `2` and `2.0` both are equal/same? – haccks Oct 03 '13 at 12:03
  • @mrigendra I said value wise same but semantically all are different! – Grijesh Chauhan Oct 03 '13 at 12:04
  • yes i got your point.. i was reading your answer – mrigendra Oct 03 '13 at 12:05
  • @mrigendra; Try to print out tha values for `arr`, `&arr`, `arr[0]`, `&arr[0]`, `*arr` and `&arr[0][0]`! – haccks Oct 03 '13 at 12:20
  • 2
    @mrigendra: you should also consider the data type. `arr` is `char[2][4]`, whilst `&arr` is `char (*)[2][4]`. Now they will both point to the same address but their types during compilation are very different ... also see http://stackoverflow.com/a/3925968/1117740 – Keldon Alleyne Oct 03 '13 at 18:06
  • @mrigendra instead of edit question add an answer and accept that +1 for self study... – Grijesh Chauhan Oct 03 '13 at 18:36
  • valuable suggestions. i'll keep them in my mind.. – mrigendra Oct 04 '13 at 09:37

6 Answers6

2

Because arr is a two dimensional array.

*(*(arr+1)+2)) is equivalent to arr[1][2].

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • what address arr+1 contain? – mrigendra Oct 03 '13 at 11:13
  • 1
    @mrigendra In pointer arithmetic, `+1` will add to the address the length of one element. In the case of `arr`, its element is an array of 4 `char`. So `arr+1` is the start of the second array. – Yu Hao Oct 03 '13 at 11:16
  • when does the compiler know that the syntax actually tries to print the value of the next array element? as when it gets to print arr+1 it prints just next address of the oth element, but when it gets to print *(*(arr+1)+2) it understands that its the next element.. getting me? – mrigendra Oct 03 '13 at 11:27
  • @mrigendra The compiler knows from the type of `arr`, which is `int arr[2][4]`. So the compiler knows that it's a two dimensional array and the size of each dimensional. – Yu Hao Oct 03 '13 at 11:33
1
printf("%d",*(*(arr+1)+2) );

break this it into two statements

*(arr+1) means arr[1]

like this

*(arr[1] + 2) means arr[1][2]
Sohil Omer
  • 1,171
  • 7
  • 14
1

Declaration

char arr[2][4] = {1,2,3,4,5,6,7,8};  

means

char arr[2][4] = { 
                     {1,2,3,4},   // row 0
                     {5,6,7,8}    // row 1
                  };  

Passing the array name arr to printf means it decays to pointer to the first element (row 0) of the array arr[2] and is of type int (*)[4] (thought 2D array as 1D array of 2 elements which are array of 4 elements each).

I have thought that to go to the second array it should be &arr+1.

arr + 1 points to the second element (row 1) of the array arr[2] (and not the second element of row 1 of array arr[2][4]). By doing arr + 1, you are not adding just 1 to the pointer arr (after decay) but you are adding total number of bytes needed to store the elements in a row.
Let's understand this by a simple example: Consider arr refernce to the address 100 and size of int is 4. Then arr + 1 means your doing 100 + (4-1)*4 = 112.
Hence dereferencing (arr + 1) will give entire row 1 while dereferencing (*(arr+1)+2) will give the 3rd element of row 1, i.e, 7.
And also, %u is used for unsigned integer. To print address (pointer value) use %p specifier in your first printf statement.

haccks
  • 104,019
  • 25
  • 176
  • 264
0

arr+1 and &arr+1 in this context are exactly the same thing, because arr is an array which implicitly degrades to a pointer, or have its address taken explicitly, which amounts to the same thing.

Adding 1 to the array goes to its second element, as you know. And arr is an array of arrays, so its second element is the second sub-array.

If you want the second element of the first sub-array, try arr[0]+1, which is equivalent to &arr[0][1].

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
0

When accessing char arr[ROW_COUNT][COLUMN_COUNT], arr[row][col] is equivalent to address_of_arr[col + (row * ROW_COUNT)]. Once you've wrapped your head around that it will all make a lot more sense.

arr and arr+1 should not be adjacent, there should be a difference of 4 bytes. Exactly what result are you seeing?

Keldon Alleyne
  • 2,103
  • 16
  • 23
0

array you using is character so each field take 1 byte. arr and arr+1 will not be in adjacent location.

I think when you checking output of arr and arr+1 difference is 4 so you keep the integer in mind and telling it was in adjacent location.

&arr[0] = address of 1st element of 1st row

&arr[1] = address of 1st element of 2nd row

change your datatype from char to int you will understand more.

Check the output of below program.

#include<stdio.h>
int main()
{
 char arr[2][4] = { 1,2,3,4,
                    5,6,7,8 };

 printf("%u\n", &arr[0][0]);
 printf("%u\n", &arr[0][4]);

 printf("%u\n", &arr[1][0]);
 printf("%u\n", &arr[1][4]);

 printf("%d\n",*(*(arr+1)+2) ); // equal to arr[1][2]
 printf("%d\n", *(arr[1] + 2) );
 printf("%d\n", arr[1][2]);

 return 0;
}

output :

3214594184
3214594188
3214594188
3214594192
7
7
7

above program will give some warning, replace %u with %p.

sujin
  • 2,813
  • 2
  • 21
  • 33