在学习C语言指针时,我被它们复杂的名词绕的稀里糊涂,特别是到了二维数组后,总觉得他们似乎都有些联系、相似,但又说不清到底有什么区别。现在我就用我自己的理解来简单说说,希望能更好的让自己理清思路,也能帮助同样有困惑的小伙伴们。同时,如果有叙述的不准确或是错误的地方,也请您不吝赐教!
二维数组
如果定义一个二维数组,我们通常将他们看做是有行有列的二维数据,但实际在内存中,二维数组的存储却是连续的。例如如果我定义一个字符型数组,并打印输出地址
#include <stdio.h>
int main()
{
char a[2][4] = {{'A','B','C','D'},
{'E','F','G','H'}};
char *p = a[0];
for(int i = 0; i < 8; i++)
printf("%p\n", p++);
return 0;
}
由此我们可以大致画出内存空间的情况:
数组首行地址为0x7fffb1b79b40 ,数组下一行地址为0x7fffb1b79b44。
二级指针
顾名思义,它的本质是一个指针变量,变量内存储一个地址,通过地址指向地址处存储的数据。
而二级指针于指针的区别就在于它指向的不再是一个具体数据,而是一个地址,再由这个地址指向数据。
简单对比一下:一级指针存储地址,指向数据;二级指针存储地址,指向地址。同样,我们通过代码展示。
#include <stdio.h>
int main()
{
int a = 1;
int *p1 = &a;
int **p2 = &p1;
printf(" a:%p %d\n", &a, a);
printf("p1:%p %p %d\n", &p1, p1, *p1);
printf("p2:%p %p %d\n", p2, *p2, **p2);
return 0;
}
现在我们大致画出二级指针的内存空间:(注:为了方便,以下画的都是32位处理器)
二级指针存储一级指针地址,指向数据地址。一级指针存储数据地址,指向数据本身。
指针数组
从它的名字可以知道:首先它是一个数组,其次它的存储元素为指针变量。通常我们用指针数组来模拟实现一个字符串二维数组,将不同字符串首地址存在数组中,就可以通过数组下标快速访问他们了。下面我们用代码来了解一下指针数组。
#include <stdio.h>
int main()
{
char a[] = "hello";
char b[] = "world";
char *arr[] = {a, b};
printf("%p %s\n", a, a);
printf("%p %s\n", b, b);
printf("%p %s\n", arr[0], arr[0]);
printf("%p %s\n", arr[1], arr[1]);
return 0;
}
指针数组的内存空间如下图:
数组每个元素都是一个地址,再由地址内存放的地址指向一个数据。
数组指针
数组指针,也叫行指针,它是一个指针,这个指针像整型指针决定指针访问4字节、字符型指针决定指针访问1字节一样,它由数组类型决定它访问的是一个已知元素个数的数组。代码如下:
#include <stdio.h>
int main()
{
char a[3][2] = {'A','B','C','d','E','F'};
char (*p)[2] = a;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 2; j++){
printf("%p %p %p %c\n", p+i, *(p+i), *(p+i)+j, *(*(p+i)+j));
}
}
return 0;
}
从上面的代码可以看到,p作为一个数组指针,每次偏移一位,都会跳过整个数组,指向下一个数组。对数组指针进行第一次解引用,使其指向行首元素,再进行解引用,得到最终数据。这里值得注意的是,*p 与 p 打印出来虽然看起来都是同一个地址,但他们的含义却不一样,p 指向整个一维数组,代表着一个数组的地址,而 *p 指向数组元素,代表着一维数组首元素地址,所以对他们进行加一操作后,他们跳过的地址长度是不一样的。如果对这里还有困惑,可以参考下面的文章:
所以现在我们用图像来表示的话是这样的:
区别与关系
虽然他们似乎都是由地址指向内容,但从上面的分析可以看出他们之间的区别还是很大的。
其中中有两个数组:指针数组与二维数组, 两个指针:二级指针与数组指针。我们在写代码时不难发现,传参时,二维数组可以用数组指针承接,而指针数组可以用二级指针承接,所以我们可不可以近似理解成:
指针数组 是 二级指针 的集合,指针数组的数组名本质上是一个二级指针
二维数组 是 数组指针 的集合,二维数组的数组名本质上是一个数组指针
到此,我脑内的一团毛线终于解开了! \ ( = ` ~ ' = ) /