You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何二维数组的行指针地址与该行首个元素地址相同?

动态二维数组与静态二维数组的内存结构差异解析

你的代码运行后会呈现这样的输出特征:

  • 动态分配部分:前两行打印的s+i是一组连续的地址(指针数组的元素地址),后续打印的*(s+i)+j是另一组和前者无关联的地址(每个子数组的元素地址);
  • 静态数组部分:打印的s2+i和对应行的*(s2+i)+0地址完全相同,s2+i之间的地址间隔为12字节(假设int占4字节,对应3个int的长度),*(s2+i)+j之间的地址间隔为4字节。

先看修正后的完整代码(补充了必要的头文件和内存释放):

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int **s = (int**)malloc(3 * sizeof(int*));
    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s+i);
    }

    for (int i = 0; i < 3; i++)
    {
        s[i] = (int*)malloc(3 * sizeof(int));
    }

    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s+i);
    }
    printf("\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d\n", *(s+i)+j);
        }
    }
    printf("\n");
    int s2[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s2+i);
    }
    printf("\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d\n", *(s2+i)+j);
        }
    }

    // 释放动态分配的内存
    for (int i = 0; i < 3; i++)
    {
        free(s[i]);
    }
    free(s);
    return 0;
}

核心差异:两种结构的本质区别

1. 动态分配的int **s:指针数组

  • s是一个指向指针的指针,它指向的是一块malloc分配的内存,这块内存里存储了3个int*类型的指针(即s[0]、s[1]、s[2])。
  • s+i表示的是指针数组中第i个指针变量本身的地址(比如s+0就是s[0]这个指针所在的内存地址)。
  • *(s+i)(等价于s[i])是该指针变量的值,也就是后续单独malloc出来的int数组的首地址。
  • 这两个地址必然不同:指针数组的元素(指针)存放在一块内存区域,每个int子数组是独立分配的另一块区域,两者物理位置不重叠。

2. 静态定义的int s2[3][3]:二维数组

  • s2是一个二维数组,本质是「包含3个元素的数组,每个元素是长度为3的int数组」,在内存中是连续存放的9个int,没有额外的指针存储空间。
  • 当你写s2+i时,数组名s2会自动退化为指向第一个元素(即第一个int[3]子数组)的指针,类型为int (*)[3],s2+i的数值就是第i个int[3]子数组的起始地址。
  • 当你写*(s2+i)时,这里的*(s2+i)是第i个int[3]子数组本身,它作为数组名会再次退化为指向该子数组第一个元素的指针,类型为int*,其数值就是这个子数组的起始地址——和s2+i的数值完全相同。

关键理解:并非同一内存存储两个内容

地址相同只是因为同一块内存的起始位置被不同类型的指针指向:

  • s2+i是int (*)[3]类型,指向的是一个长度为3的int子数组;
  • *(s2+i)退化为int*类型,指向的是这个子数组的第一个int元素。
    它们指向的物理内存位置完全一致,但类型不同,所以指针偏移的步长不同:比如s2+1会跳过3个int(整个子数组的长度),而*(s2+1)+1只会跳过1个int。

内容的提问来源于stack exchange,提问作者M. Saamin Rahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:37:13