一篇介绍C语言中二级指针和二维数组的文章

我们知道C语言中指针也就是内存地址,指针变量是用来存放内存地址的变量。那么二级指针就是存放的指针的内存地址。int **arr 可以理解为一个二维数组的动态表示。它通常用于创建动态分配的二维数组,允许在运行时根据需要分配和管理内存。以下用一个例子和三个疑问来剖析二级指针和二维数组。

示例

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
int main() {
    int rows = 3, cols = 4;
    // Step 1: 分配行指针数组
    int **arr = (int **)malloc(rows * sizeof(int *));
    
    // Step 2: 为每一行分配内存
    for (int i = 0; i < rows; i++) {
        arr[i] = (int *)malloc(cols * sizeof(int));
    }
    // 填充数组
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            arr[i][j] = i * cols + j + 1; // 填充示例数据
        }
    }
    // 打印数组
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
    // 释放内存
    for (int i = 0; i < rows; i++) {
        free(arr[i]); // 释放每一行的内存
    }
    free(arr); // 释放行指针数组
    return 0;
}

一、搞懂:真正的二维数组 vs 二级指针

真正的二维数组(栈上),它本质是:一维数组套一维数组

复制代码
int arr[3][4];

内存是一整块连续的

1\]\[2\]\[3\]\[4\]\[5\]\[6\]\[7\]\[8\]\[9\]\[10\]\[11\]\[12

用 malloc + int** 写的,内存不是连续的,结构是这样:

arr → 指针0 1234

指针1 \] → \[5\]\[6\]\[7\]\[8

指针2 \] → \[9\]\[10\]\[11\]\[12

  • arr 是一个指针,指向3 个指针
  • 这 3 个指针,每个又指向4 个 int
  • 所以可以用 arr[i][j]

二、为啥arrij == *(*(arr + i) + j)

在 C 语言中,数组下标运算 a[b] 被定义为 *(a + b)

在表达式中,数组名通常会退化为指向首元素的指针,因此 a[0] == *a 成立。

但需要注意:数组名本身不是指针,且该规则成立的前提是指针运算合法。

通过一步步运算我们可以得到arrij == *(*(arr+i)+j)

(arri)j --> *(arri +j) --> *(*(arr+i)+j)

含义:

  • arr+i → 找到第 i 行指针
  • *(arr+i) → 拿到第 i 行地址
  • *(arr+i)+j → 第 i 行第 j 列元素地址
  • *(*(arr+i)+j) → 取出元素

三、为啥free先free每行再free掉arr

现在的结构是:

arr → 存了3个指针

指针0 → 一行数据

指针1 → 一行数据

指针2 → 一行数据

所以释放顺序必须是:

  1. 先把3 行数据分别 free 掉
  2. 再 free 掉 arr 自己

如果先 free (arr),那三行数据的地址就丢了,变成内存泄漏

相关推荐
LuminousCPP5 分钟前
C 语言系列终章|编译与链接 + 预处理
c语言·经验分享·笔记·预处理·编译链接
.千余6 分钟前
【C++】 String 常用操作:增删查改 | 查找 | 截取 | IO
java·服务器·开发语言·c++·笔记·学习
十月的皮皮8 分钟前
C语言学习笔记20260607-判断一个数是否为2的n次方(三种方法)
c语言·笔记·学习
码云骑士9 分钟前
【Java基础】JDK安装常见问题教辅-从踩坑到排雷
java·开发语言
c2385613 分钟前
C++ lambda 表达式详细介绍
开发语言·c++
艾莉丝努力练剑20 分钟前
【QT】界面优化:QSS
linux·运维·开发语言·网络·qt·计算机网络·udp
jieyucx22 分钟前
站在云原生高并发天花板:拆解 Go 语言 GMP 模型与 I/O 多路复用的神级配合
开发语言·云原生·golang
caimouse22 分钟前
Reactos 第 3 章 内存管理 — 【下篇】换出、Section、池
c语言·开发语言·windows·架构
San813_LDD25 分钟前
[量化]《多线程数据同步精讲:std::mutex 的底层原理与最佳实践》
c语言·数据结构
无忧.芙桃26 分钟前
debug实例与分析(一)
开发语言·c++·算法