int a[3][4] = {
1,2,3,4,
5,6,7,8,
9,10,11,12,
};
printf("%u %u %u \n", a[0]+1, *(a[0]+1), *(*(a+0)+1));
Time for a crash course on arrays in C.
First of all, let's fix the initializer for the array:
int a[3][4] = {
{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9, 10, 11, 12}
};
This defines a 3-element array of 4-element arrays of int
. The type of the expression a
is "3-element array of 4-element arrays of int
".
Now for the headache-inducing part. Except when it's the operand of the sizeof
or unary &
operators, or if it's a string literal being used to initialize another array in a declaration, an expression of array type will have its type implicitly converted ("decay") to a pointer type.
If the expression a
appears by itself in the code (such as in a statement like printf("%p", a);
, its type is converted from "3-element array of 4-element array of int
" to "pointer to 4-element array of int
", or int (*)[4]
. Similarly, if the expression a[i]
appears in the code, its type is converted from "4-element array of int
" (int [4]
) to "pointer to int
" (int *
). If a
or a[i]
are operands of either sizeof
or &
, however, the conversion doesn't happen.
In a similar vein, array subscripting is done through pointer arithmetic: the expression a[i]
is interpreted as though it were written *(a+i)
. You offset i
elements from the base of the array and dereference the result. Thus, a[0]
is the same as *(a + 0)
, which is the same as *a
. a[i][j]
is the same as writing *(*(a + i) + j)
.
Here's a table summarizing all of the above:
Expression Type Decays To Resulting Value ---------- ---- --------- ----- a int [3][4] int (*)[4] Address of the first element of the array &a int (*)[3][4] n/a Same as above, but type is different *a int [4] int * Same as above, but type is different a[0] int [4] int * Same as above *(a+0) int [4] int * Same as above a[i] int [4] int * Address of the first element of the i'th subarray *(a+i) int [4] int * Same as above &a[i] int (*)[4] n/a Same as above, but type is different *a[i] int n/a Value of the 0'th element of the i'th subarray a[i][j] int Value of the j'th element of the i'th subarray *(a[i]+j) int Same as above *(*(a+i)+j) int Same as above
Hopefully, that should give you everything you need to figure out what the output should be. However, the printf
statement should be written as
printf("%p %d %d\n", (void *) a[0]+1, *(a[0]+1), *(*(a+0)+1));
$ gcc -Wall -o output output.c
output.c: In function ‘main’:
output.c:5:5: warning: missing braces around initializer [-Wmissing-braces]
output.c:5:5: warning: (near initialization for ‘a[0]’) [-Wmissing-braces]
output.c:9:5: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
because the 2-dimensional array is initialized as though it had only one dimension.
Complete program, for reference:
#include <stdio.h>
int main()
{
int a[3][4] = {1,2,3,4,
5,6,7,8,
9,10,11,12,
};
printf ("%u %u %u \n", a[0]+1, *(a[0]+1), *(*(a+0)+1));
return 0;
}
First of all, your initialization is wrong: your initializer it for one-dimensional array, whereas you declare a two-dimensional one.
Second, let's see what does your code do.
a
is a two-dimensional array, so a[0]
is of type int[4]
(one-dimensional array), and represents the 0-th column of the multidimensional array, and is (mostly) the same as a pointer to the column's leading element. Now you use address arithmetics: a[0] + 1
is the pointer to element after the leading one in the 0-th column (represented as a pointer to it), that is, pointer to the 1-st element in the 0-th column. That's where the second warning appears, saying that your argument to printf
is int*
and not unsigned int
.
Next, *(a[0]+1)
dereferences the pointer to the 1-st element of the 0-st column. This is (as usually) equivalent to a[0][1]
.
Next, *(*(a+0)+1))
is the same, because *(a+0)
is the same as a[0]
.
(In order to understand this all, you need to know some basics: that in C *(x + y)
is the same as x[y]
, and that the 1-dimensional array is essentially the same as the pointer to its leading element.)
About the difference between your book and the reality: the first output value is just a pointer, so it can be an arbitrary value, depending on where your array happened to be in the memory. About the other two values, the question depends on how the array was filled by the wrong initializer.
精彩评论