I have these two statements:
printf("%u",a+1);
and
printf("%u",(int *)a+1);
Actually I was working on this code when I came across this confusion.
#include<stdio.h>
int main()
{
int a[2][2]={1,2,3,4};
int i,j;
int *p[] = { (int*)a, (int*)a+1, (int*)a+2 };
for(i=0; i<2; i++){
for(j=0; j<2; j++){
printf("%d %d %d %d",* (*(p+i)+j), *(*(j+p)+i), *(*(i+p)+j), *(*(p+j)+i));
}
}
return 0;
}
Output:
1 1 1 1
2 2 2 2
2 2 2 2
3 3 3 3
In order to understand the output of the above program I came to know that the difference that's making this output can be solved if I know the difference between above two statements.
My current understanding: (a+1)
will give me the address of 2nd element of array. In this case a 2-d array can be visualized as 2 1-d arrays, each with 2 elements. So (a+1)
will give me the address of a[1][0]
, but then why is (int *)a+1
giving me the address of a[0][1]
?
Please explain the difference and the output of the program.
Thanks.
The idiom (int*)a+1
is interpreted as ((int*)a) + 1)
. That is, the cast takes precedence over the addition. So this evaluates to (int*) a)
, which is the address of the array as ptr-to-int, offset by 1, which returns the second element in the array ( 2
).
Two critical rules of programming:
Rule 1: When you write code, make the layout reflect the functionality.
Rule 2: When you read code, read the functionality, not the layout. (Corollary: debug the code , not the comments .)
Conceptually, when you declare
int a[2][2]={1,2,3,4};
you envision a 2 dimensional array like this:
1 2
3 4
But C actually stores the data in a contiguous block of memory, like this:
1 2 3 4
It "remembers" that the data represents a 2×2 array when it calculates the indices. But when you cast a
from its original type to int *
, you're telling the compiler to forget about its original declaration, effectively losing its 2-dimensionality and becoming a simple vector of int
s.
Here's how to understand the declaration of p
:
int *p[] = { (int*) a, (int*) a+1, (int*) a+2 }; // As written
int *p[] = { (int*) a, ((int*) a) + 1, ((int*) a) + 2 }; // As interpreted
int *p[] = { &a[0][0], &a[0][1], &a[1][0] }; // Resulting values
From this, you can see that p
is a one-dimensional array of vectors:
p[0] = { 1, 2, 3 }
p[1] = { 2, 3 }
p[2] = { 3 }
If you recognize that (p+i) == (i+p)
, then the last two items are the same as the first two in the line
printf("%d %d %d %d\n",* (*(p+i)+j), *(*(j+p)+i), *(*(i+p)+j), *(*(p+j)+i));
which is equivalent to this:
printf("%d %d %d %d\n", p[i+j], p[j+i], p[i+j], p[j+i]);
It's interesting to note that, since the following are all equivalent:
a[i]
*(a+i)
*(i+a)
then it's perfectly legal to write i[a]
to represent the same value. In other words, the compiler allows you to write
printf("%d %d %d %d\n", p[i], i[p], p[1], 1[p]);
Of course, your tech lead had better not allow you to write that. If you write that in my group, you're fired. ;-)
None, both produce undefined behavior. The correct format to print a pointer value is %p
. Cast your pointer to void*
when sending it to printf
.
Multidimensional C arrays behave like single-dimensional arrays laid out next to each other. So if you cast a
(normally (int **)
) to (int *)
you get the same thing you would get from a[0]
. Thus (int *) a + 1
is &a[0][1]
. Otherwise your understanding is correct, which is why a + 1
gets you &a[1][0]
.
(This behavior is specified by the standard; but that does not make it good programming practice.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.