Except when it is the operand of the sizeof
or unary &
operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T
" will be converted ("decay") to an expression of type "pointer to T
", and the value of the expression will be the address of the first element of the array.
Assuming the declaration
char ma[5][30];
then all of the following are true:
The expression ma
has type "5-element array of 30-element array of char
". Unless ma
is an operand to either sizeof
or unary &
, it will be converted to an expression of type "pointer to 30-element array of char
", or char (*)[30]
, and its value will be the address of the first element in the array, or &ma[0]
.
The expression ma[i]
has type "30-element array of char
". Unless ma[i]
is an operand to either sizeof
or unary &
, it will be converted to an expression of type "pointer to char
", or char *
, and its value will be the address of the first element in the array, or &ma[i][0]
.
The expression ma[i][j]
has type char
.
The expression &ma
has type "pointer to 5-element array of 30-element array of char
, or char (*)[5][30]
.
The expression &ma[i]
has type char (*)[30]
.
The expression &ma[i][j]
has type char *
.
The values of the expressions ma
, &ma
, ma[0]
, &ma[0]
, and &ma[0][0]
are all the same; the address of the array is the same as the address of the first element of the array.
Note that the types char (*)[30]
and char (*)[5][30]
are not compatible with char *
, or with each other; if you want to assign a value of those types to a variable of type char *
, you will need to use an explicit cast, such as char *p = (char *) ma;
.
Edit
Types matter; pointer arithmetic is based on the pointed-to type, so an expression like ptr+1
will give different results based on the type that ptr
points to. For example:
#include <stdio.h>
int main( void )
{
char ma[5][30] = {{0}};
char (*p0)[5][30] = &ma;
char (*p1)[30] = &ma[0];
char *p2 = &ma[0][0];
printf("%5s%-15s%-15s\n"," ","ptr","ptr+1");
printf("%5s%-15s%-15s\n"," ","-----","-----");
printf("%-5s%-15p%-15p\n","p0", (void *) p0, (void *) (p0+1));
printf("%-5s%-15p%-15p\n","p1", (void *) p1, (void *) (p1+1));
printf("%-5s%-15p%-15p\n","p2", (void *) p2, (void *) (p2+1));
return 0;
}
I create three pointers of different types; p0
is of type char (*)[5][30]
and takes the result of &ma
, p1
is of type char (*)[30]
and takes the result of &ma[0]
, and p2
is of type char *
and takes the result of &ma[0][0]
. I then print the value of each pointer, than the value of each pointer plus 1. Here are the results:
ptr ptr+1
----- -----
p0 0x7fff36670d30 0x7fff36670dc6
p1 0x7fff36670d30 0x7fff36670d4e
p2 0x7fff36670d30 0x7fff36670d31
Each pointer starts out with the same value, but adding 1 to the pointer gives different results based on the type. p0
points to a 5x30-element array of char
, so p0 + 1
will point to the beginning of the next 5x30-element array of char
. p1
points to a 30-element array of char
, so p1 + 1
points to the next 30-element array of char
(ma[1]
). Finally, p2
points to a single char
, so p2 + 1
points to the next char (ma[0][1]
).