跳到主要内容

C 指针和数组

1. 基本概念

虽然指针和数组关系密切,但数组绝对不是指针,它们只是很像而已。

  • 指针和数组的区别

指针变量可以做左值,数组名是指针常量,不可做左值。

2. 数组名含义

表示整个数组或者首元素地址。

  • 数组名:在数组定义中,在 sizeof 运算表达中,在取地址符**&**中。

  • 首元素地址:在其他情况下,数组名就代表首元素地址,数组名就是一个指向首元素的指针。

  • C 语言数组只有在第一含义的场合下表现为数组,其他大部分场合都表现为首元素的地址,当数组表现为首元素的地址时,实际上它就是一个指向首元素的指针。

int a[3];                    // 此处,a 代表整个数组
printf("%d\n", sizeof(a)); // 此处,a 代表整个数组
printf("%p\n", &a); // 此处,a 代表整个数组,此处为整个数组的地址

int *p = a; // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]
p = a + 1; // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]
function(a); // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]
scanf("%d\n", a); // 此处,a 代表首元素 a[0] 的地址,等价于 &a[0]

3. 数组下标

  • 数组下标实际上是编译系统的一种简写,其等价形式是:
a[i] = 100;  等价于   *(a+i) = 100;
  • 根据加法交换律,下面所有的语句都是等价的。
  a[i] = 100;
i[a] = 100;
*(a+i) = 100;
*(i+a) = 100;
  • 数组运算,等价于指针运算。
int a[5] = {1, 2, 3, 4, 5};  // 数组名为首元素地址
int *p = a; // 不用加取地址符 & 等价于 p = &a[0];
a == &a[0]; a[0] == *(a+0);
a+1 == &a[0]+1; a[1] == *(a+1);
a+1 == &a[1];

4. 一维数组地址的偏移

int a[10] = {1 ,2, 3, 4, 5, 6, 7, 8, 9, 10}; 

printf("&a = %p\n", &a); // int (*)[10]
printf("&a+1 = %p\n", &a+1); // 将整个整型数组的地址向后移40个字节

printf("a = %p\n", a); // int *
printf("a+1 = %p\n", a+1); // 将整型数组元素的地址向后移4个字节

printf("&a[0] = %p\n", &a[0]); // int *
printf("&a[0]+1 = %p\n", &a[0]+1); // 将整型数组元素的地址向后移4个字节

5. 二维数组含义

int a[2][3];   // 拆解为a[2] int [3]
  • a[2]是数组的定义,表示有两个元素。
  • int [3],表示一个有三个元素的整型数组。

6. 二维数组和指针

  • 数组下标实际上是编译系统的一种简写,其等价形式是:
a[0][0] == *(a[0]+0) == *(*(a+0)+0);
a[i][j] == *(a[i]+j) == *(*(a+i)+j);
  • 二维数组名和一维数组名一样代表首元素地址
a == &a[0];
a[0] == &a[0][0];
*a == a[0];
*a == &a[0][0];

也就是说 a 存放的是 a[0] 的地址,a[0] 存放的是 a[0] [0] 的地址,所以通过对 a 进行解引用来访问 a[0] 的地址来获取到 a[0] 所存放的值,也就是 a[0] [0] 的地址。

7. 二维数组地址的偏移

int a[2][3] = {1, 2, 3, 6, 5};

printf("&a = %p\n", &a); // int (*)[2][3]
printf("&a+1 = %p\n", &a+1); // 将整个整型二维数组的地址向后偏移24个字节

printf("a = %p\n", a); // a == &a[0] int (*)[3]
printf("a+1 = %p\n", a+1); // 将二维数组元素的地址向后偏移12位

printf("&a[0] = %p\n", &a[0]); // int (*)[3]
printf("&a[0]+1 = %p\n", &a[0]+1); // 将二维数组元素的地址向后偏移12个字节

printf("a[0] = %p\n", a[0]); // a[0] == &a[0][0] int *
printf("a[0]+1 = %p\n", a[0]+1); // 将二维数组元素的地址向后偏移4个字节

printf("&a[0][0] = %p\n", &a[0][0]); // int *
printf("&a[0][0]+1 = %p\n", &a[0][0]+1); // 将二维数组元素的地址向后偏移4个字节