一篇介绍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),那三行数据的地址就丢了,变成内存泄漏。

相关推荐
Frank_refuel6 小时前
C++11之一场名为“搬家”的 C++ 之旅
开发语言·c++
Wang's Blog7 小时前
Java 项目实战: 外卖平台优化-Nginx配置文件结构与块层级
java·开发语言·nginx
2601_962071577 小时前
类变量和全局变量的查找路径有什么区别?
开发语言·python
\光辉岁月/8 小时前
5.java-数组
java·开发语言
Java后端的Ai之路8 小时前
Python进阶探索29_eval内置函数
开发语言·python·探索·eval·内置函数
谢亮_vipxieliang8 小时前
Spring 事务失效的常见场景
java·开发语言·数据库·spring boot
时间的拾荒人9 小时前
Qt 多线程详解:从 QThread 到实战
开发语言·qt·面试
郑州光合科技余经理9 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
2601_962071579 小时前
类变量和全局变量的生命周期有什么区别?
java·开发语言·jvm
Wang's Blog9 小时前
Java 项目实战: 外卖平台优化-前后端分离开发模式与工程拆分
java·开发语言