看一下这个C代码输出什么?

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={{1,2,3,4},{11,12,13,14},{21,22,23,24},{31,32,33,34},{41,42,43,44}};
  5. int** p = array;
  6. printf("%d\n",*p);
  7. printf("%d\n",array[0][0]);
  8. return 0;
  9. }

先简单思考下,然后我们再一起分析分析

  • array 是一个二级数组
  • p 是一个指针
  • C二维数组和二级指针 - 图1

二级指针和一级指针的图示

array 从数值上来说是一个地址,这个地址是二维数组的首地址。

  • p = array

可以认为把 array 数组的首地址赋值给指针变量 p。

二级指针的示例代码

  1. int b = 120;
  2. int *p1 = &b;
  3. int** p = &p1;
  4. printf("%d\n",**p);

这个示例就是我上面耳机指针的图示对应。

那如果是二级指针呢?

我们编译上面的代码

  1. zhizhen.c: In function main’:
  2. zhizhen.c:5:15: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
  3. int** p = array;
  4. ^
  5. zhizhen.c:6:12: warning: format ‘%d expects argument of type int’, but argument 2 has type int *’ [-Wformat=]
  6. printf("%d\n",*p);

第一个警告是类型不匹配,第二个警告是我们输出的p 类型是 int 但是我们却使用 %d 来输出。

再说回前面的题目,二级指针和二维数组

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={{1,2,3,4},{11,12,13,14},{21,22,23,24},{31,32,33,34},{41,42,43,44}};
  5. int** p = array;
  6. printf("%d\n",*p);
  7. printf("%d\n",array[0][0]);
  8. return 0;
  9. }

这个程序输出多少呢?
我们知道array 我们就把它当成一个地址
那么 p 就是把p这个地址的值给取出来,array是数组的首地址,那么p 应该就可以取到二维数组首元素的值。
所以输出应该是
1
1
我们执行下程序试试
C二维数组和二级指针 - 图2
如我所料

既然你这么厉害,我把代码修改一下

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={{1,2,3,4},{11,12,13,14},{21,22,23,24},{31,32,33,34},{41,42,43,44}};
  5. int** p = array;
  6. printf("%d\n",*(p+1));
  7. printf("%d\n",array[0][0]);
  8. return 0;
  9. }

这个代码输出什么?
直接分析一下,p 的类型是 int ,p +1 ,它跳过的地址大小应该是
`sizeof(int
)<br />学指针的同学把这个记清楚,一定会有所收获。<br />所以<br />(p+1)<br />其实就是<br />(&array + sizeof(int))
sizeof(int
) = 8<br />那就应该是输出<br />3
1`
为了验证上面,我们的代码修改如下

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={{1,2,3,4},{11,12,13,14},{21,22,23,24},{31,32,33,34},{41,42,43,44}};
  5. int** p = array;
  6. printf("sizeof(int**):%d\n",sizeof(int**));
  7. printf("%d\n",*(p+1));
  8. printf("%d\n",array[0][0]);
  9. return 0;
  10. }

640.webp


那怎么用一个指针来指向一个二维数组呢?

其实不管是多少维度的数组,它都是直尺,一直变长的直尺,我们把二维数组说成长宽之类的,都是为了方便我们理解。
我们可以这样声明一个二维数组

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44};
  5. int** p = array;
  6. printf("sizeof(int**):%d\n",sizeof(int**));
  7. printf("%d\n",*(p+1));
  8. printf("%d\n",array[0][0]);
  9. return 0;
  10. }


所以,我们如果想用一个二维数组,可以用一个一维指针指向一个二维数组

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44};
  5. int* p = array;
  6. printf("%d\n",*(p+1));
  7. printf("%d\n",array[0][0]);
  8. return 0;
  9. }

C二维数组和二级指针 - 图4

当然,也可以用二维指针来指向二维数组

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44};
  5. int(*p)[4]= &array[0];
  6. printf("%d\n",*(*(p+0)+0));
  7. printf("%d\n",*(*(p+0)+1));
  8. printf("%d\n",*(*(p+1)+0));
  9. printf("%d\n",*(*(p+1)+1));
  10. printf("%d\n",array[0][0]);
  11. return 0;
  12. }

C二维数组和二级指针 - 图5

还可以这样的

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44};
  5. int(*p)[4]= &array[0];
  6. printf("%d\n",(*p)[0]);
  7. printf("%d\n",(*p)[1]);
  8. printf("%d\n",(*p)[2]);
  9. printf("%d\n",(*p)[3]);
  10. p++;
  11. printf("%d\n",(*p)[0]);
  12. printf("%d\n",(*p)[1]);
  13. printf("%d\n",(*p)[2]);
  14. printf("%d\n",(*p)[3]);
  15. printf("%d\n",array[0][0]);
  16. return 0;
  17. }


C二维数组和二级指针 - 图6

还可以改成这样

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int array[5][4] ={1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34,41,42,43,44};
  5. int(*p)[4]= &array[0];
  6. printf("%d\n",(*p)[0]);
  7. printf("%d\n",(*p)[1]);
  8. printf("%d\n",(*p)[2]);
  9. printf("%d\n",(*p)[3]);
  10. printf("%d\n",(*p)[4]);
  11. printf("%d\n",(*p)[5]);
  12. printf("%d\n",(*p)[6]);
  13. printf("%d\n",(*p)[7]);
  14. printf("%d\n",array[0][0]);
  15. return 0;
  16. }

C二维数组和二级指针 - 图7