一:一维数组int a[5]
数组名a代表数组首元素的地址,其类型为int *类型.
注意:和sizeof搭配使用,a表示整个数组整体,sizeof(a) = 5 * 4.
&a:
对一维数组名取地址,其指向整个数组,所以其类型为int (*)[5],指向整个一维数组的指针,如果你将它赋值给一个指针变量时只能赋值给一个 int(*p)[5];否则一般的编译器都会给出警告.所以sizeof(&a) = 4.
*a:
对数组第0个元素的解引用,就是a[0],所以sizeof(*a) = 1 * 4.
补充:对 a,&a 用%p打印,得到的值是相同的,因为它们所指向的空间的起始地址是相同的,但是它们所指向的空间大小不同.
二:二维数组名 int b[3][4]
数组名b代表数组首元素的地址,但是这里的首元素地址指的是第0行一维数组的地址,b = &b[0],其类型为int (*)[4],表示指向一维数组的指针.
注意:和sizeof搭配使用,a表示整个数组整体,sizeof(b) = 3 * 4 * 4.
&b:
对二维数组名取地址,其指向整个数组(对数组名使用&得到指向范围更大的指针),所以其类型为int (*)[3][4],但本身仍是一个指针,sizeof(&b) = 4,
&b指向整个二维数组,所以&b+1表示指向下个二维数组
*b:难点
b是指向一维数组的指针,对于二维数组而言这个一个行指针,解引用*一下表示列指针(对数组名使用*得到指向范围更小的指针),指向二维数组的单个元素,所以*b的本质上也是个指针,其类型int *.
但是当与sizeof搭配使用时,表示一维数组本身,可以这样理解:
b是指向一维数组的指针,*b就表示这个一维数组本身,所以sizeo(*b) = 4 * 4;b[0]:表示指向第0行的一维数组的数组名,所以b[0]指向这个一维数组首元素b[0][0]b[0] = *(b + 0) = *b, b表示指向第0行数组的行指针,*(b + 0)对行指针解引用为列指针,表示指向第0行第0列的元素的指针,其指针类型为int *.反过来&b[0] = b + 0,对列指针&为行指针(对数组指针&得到范围更大的指针)但是sizeof(b[0]) == 4 * 4, b[0]表示第0行的一维数组名,对数组名用sizeof表示一维数组整体的大小
补充:
对 b,&b, *b 用%p打印,得到的值是相同的,因为它们所指向的空间的起始地址是相同的,但是它们所指向的空间大小不同.
数组名a代表数组首元素的地址,其类型为int *类型.
注意:和sizeof搭配使用,a表示整个数组整体,sizeof(a) = 5 * 4.
&a:
对一维数组名取地址,其指向整个数组,所以其类型为int (*)[5],指向整个一维数组的指针,如果你将它赋值给一个指针变量时只能赋值给一个 int(*p)[5];否则一般的编译器都会给出警告.所以sizeof(&a) = 4.
*a:
对数组第0个元素的解引用,就是a[0],所以sizeof(*a) = 1 * 4.
补充:对 a,&a 用%p打印,得到的值是相同的,因为它们所指向的空间的起始地址是相同的,但是它们所指向的空间大小不同.
二:二维数组名 int b[3][4]
数组名b代表数组首元素的地址,但是这里的首元素地址指的是第0行一维数组的地址,b = &b[0],其类型为int (*)[4],表示指向一维数组的指针.
注意:和sizeof搭配使用,a表示整个数组整体,sizeof(b) = 3 * 4 * 4.
&b:
对二维数组名取地址,其指向整个数组(对数组名使用&得到指向范围更大的指针),所以其类型为int (*)[3][4],但本身仍是一个指针,sizeof(&b) = 4,
&b指向整个二维数组,所以&b+1表示指向下个二维数组
*b:难点
b是指向一维数组的指针,对于二维数组而言这个一个行指针,解引用*一下表示列指针(对数组名使用*得到指向范围更小的指针),指向二维数组的单个元素,所以*b的本质上也是个指针,其类型int *.
但是当与sizeof搭配使用时,表示一维数组本身,可以这样理解:
b是指向一维数组的指针,*b就表示这个一维数组本身,所以sizeo(*b) = 4 * 4;b[0]:表示指向第0行的一维数组的数组名,所以b[0]指向这个一维数组首元素b[0][0]b[0] = *(b + 0) = *b, b表示指向第0行数组的行指针,*(b + 0)对行指针解引用为列指针,表示指向第0行第0列的元素的指针,其指针类型为int *.反过来&b[0] = b + 0,对列指针&为行指针(对数组指针&得到范围更大的指针)但是sizeof(b[0]) == 4 * 4, b[0]表示第0行的一维数组名,对数组名用sizeof表示一维数组整体的大小
补充:
对 b,&b, *b 用%p打印,得到的值是相同的,因为它们所指向的空间的起始地址是相同的,但是它们所指向的空间大小不同.
例题:
#include <stdio.h>
#include <string.h>
int main(void)
{ char a[3][20] = {0};
strcpy(a[0], "hello");
strcpy(a[1], "world");
printf("%d\n", sizeof(&a)); //4
printf("%d\n", sizeof(a)); //60
printf("%d\n", sizeof(*a)); //20 * 1 //a为一维数组 20
printf("%c\n", *(*a + 1)); //e
printf("%s\n", *(a + 1)); //world
printf("%d\n", sizeof('s')); //4
return 0;
}
int main(void)
{
char a[2][3] = { {0, 1, 2}, {3, 4, 5}};
int b[3] = {10, 11, 12};
//char c[2][3] = {{'a','b','c'},{'d','e','f'}};
printf("%d\n", sizeof(&b)); //4
printf("%d\n", sizeof(&a)); //4
printf("%d\n", sizeof(a)); //6
printf("%d\n", sizeof(*a)); //3
printf("%c\n", *(*a + 1)); //显示乱码,因为字符数组存放的是整数,所以不能用%c打印,要用%d
printf("%s\n", *(a + 1)); //显示乱码,因为字符数组存放的是整数,所以不能用%s打印 ,只有存放的是字符才可以这样使用
//printf("%d\n", sizeof('s')); //4
return 0;
}
int main(void)
{
int a[2][3] = { {0, 1, 2}, {3, 4, 5}};
int b[3] = {10, 11, 12};
printf("%d\n", sizeof(&b)); //4
printf("%d\n", sizeof(&a)); //4
printf("%d\n", sizeof(a)); //4 * 6
printf("%d\n", sizeof(*a)); //3 * 4
printf("%d\n", sizeof(b)); //3 * 4
printf("%d\n", sizeof(*b)); //1 * 4
printf("\n");
printf("%d\n", sizeof(a[0])); //3 *4
printf("%d\n", *a[0]); //0
#if 0
printf("%p\n", a);
printf("%p\n", &a);
printf("%p\n", *a);
printf("%p\n", b);
printf("%p\n", &b);
#endif
printf("%d\n", (**(&a + 1))[-1]); //&a + 1指向下个二维数组,(&a + 1))[-1]往上移动移动一个地址,得到的是指向起始地址空间内容为5,大小为二维数组大小的空间
//解引用*一下得到的是指向起始地址空间内容为5,大小为一维数组大小的空间,再解引用*一下得到的就是指向起始地址空间内容为,大小为一个元素大小的空间
return 0;
}