数组指针、指针数组、二级指针、二维数组傻傻分不清楚?内存图解让你不再糊涂< (^ - ^) >

本文详细解释了C语言中指针的概念,包括二维数组、二级指针和指针数组的内存存储方式及差异。通过示例代码展示了它们在内存中的布局,并提供了直观的内存空间图来辅助理解。文章强调了二维数组与指针数组、二级指针与数组指针的区别,并指出在参数传递时两者之间的关联性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在学习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 指向数组元素,代表着一维数组首元素地址,所以对他们进行加一操作后,他们跳过的地址长度是不一样的。如果对这里还有困惑,可以参考下面的文章:

http://t.csdn.cn/6NeHG

所以现在我们用图像来表示的话是这样的:

 区别与关系

虽然他们似乎都是由地址指向内容,但从上面的分析可以看出他们之间的区别还是很大的。

其中中有两个数组:指针数组与二维数组, 两个指针:二级指针与数组指针。我们在写代码时不难发现,传参时,二维数组可以用数组指针承接,而指针数组可以用二级指针承接,所以我们可不可以近似理解成:

指针数组 是 二级指针 的集合,指针数组的数组名本质上是一个二级指针

二维数组 是 数组指针 的集合,二维数组的数组名本质上是一个数组指针

到此,我脑内的一团毛线终于解开了!   \ (  = `  ~  ' =  ) /

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值