当前位置: 首页 > article >正文

C语言指针专题四 -- 多级指针

目录

1. 多级指针的核心原理

1. 多级指针的定义

2. 内存结构示意图

3. 多级指针的用途

2. 编程实例

实例1:二级指针操作(修改一级指针的值)

实例2:动态二维数组(二级指针)

实例3:三级指针操作(修改二级指针的值)

3. 多级指针的常见陷阱

4. 总结


1. 多级指针的核心原理

多级指针(如二级指针、三级指针)本质是 指向指针的指针,用于间接访问或修改其他指针的值。通过多级指针可以构建复杂的内存结构(如动态多维数组、链表中的指针传递等)。

1. 多级指针的定义

  • 二级指针:存储一级指针的地址。
int a = 10;
int *p = &a;     // 一级指针,指向int变量
int **pp = &p;   // 二级指针,指向int*指针
  • 三级指针:存储二级指针的地址。
int ***ppp = &pp;  // 三级指针,指向int**指针

2. 内存结构示意图

栈内存布局:
+------+       +------+       +------+
| ppp  | ----> | pp   | ----> | p    | ----> a (值=10)
+------+       +------+       +------+
地址:0x1000    地址:0x2000    地址:0x3000    地址:0x4000
  • 定义另一个指针变量pps,并且把指针数组的首地址赋予指针pps。char *ps[5]={……}; char ** pps = ps; 如图所示

3. 多级指针的用途

  • 动态创建多维数组:通过二级指针管理动态二维数组。

  • 函数内修改外部指针:通过传递指针的指针,修改原始指针的值。

  • 复杂数据结构:如链表、树结构中管理节点指针的指针。

2. 编程实例

实例1:二级指针操作(修改一级指针的值)

#include <stdio.h>

// 函数:修改外部指针的指向
void changePointer(int **pp) {
    int b = 20;
    *pp = &b;  // 通过二级指针修改一级指针的指向
    // 注意:此处b是栈变量,函数返回后其内存可能被覆盖!
}

int main() {
    int a = 10;
    int *p = &a;
    printf("Before: *p = %d\n", *p); // 输出10

    changePointer(&p);  // 传递指针的地址
    printf("After: *p = %d\n", *p);  // 输出20(实际存在风险,b已失效)
    return 0;
}

 输出(实际可能因编译器优化不同):

Before: *p = 10
After: *p = 20

警告:此示例中,changePointer函数内修改p指向栈变量b,函数返回后b的内存可能被回收,导致p成为野指针。正确做法应动态分配内存。

实例2:动态二维数组(二级指针)

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

int main() {
    int rows = 3, cols = 4;
    int **matrix;  // 二级指针

    // 动态分配行指针数组
    matrix = (int**)malloc(rows * sizeof(int*));
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int*)malloc(cols * sizeof(int));  // 分配每行内存
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;  // 初始化数据
        }
    }

    // 打印二维数组
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    for (int i = 0; i < rows; i++) free(matrix[i]);
    free(matrix);
    return 0;
}

输出

 0  1  2  3 
 4  5  6  7 
 8  9 10 11 

内存示意图

二级指针matrix(堆内存)     各行数据(堆内存)
+--------+                +-----+-----+-----+-----+
| 0x1000 | ------> 行0 -->| 0   | 1   | 2   | 3   |
+--------+                +-----+-----+-----+-----+
| 0x1008 | ------> 行1 -->| 4   | 5   | 6   | 7   |
+--------+                +-----+-----+-----+-----+
| 0x1010 | ------> 行2 -->| 8   | 9   | 10  | 11  |
+--------+                +-----+-----+-----+-----+

实例3:三级指针操作(修改二级指针的值)

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

void createMatrix(int ***ppp, int rows, int cols) {
    *ppp = (int**)malloc(rows * sizeof(int*));  // 分配行指针数组
    for (int i = 0; i < rows; i++) {
        (*ppp)[i] = (int*)malloc(cols * sizeof(int));  // 分配每行内存
        for (int j = 0; j < cols; j++) {
            (*ppp)[i][j] = i + j;  // 初始化数据
        }
    }
}

int main() {
    int **matrix = NULL;  // 二级指针初始化为空
    int rows = 2, cols = 3;

    // 通过三级指针传递,动态创建二维数组
    createMatrix(&matrix, rows, cols);

    // 打印数据
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    for (int i = 0; i < rows; i++) free(matrix[i]);
    free(matrix);
    return 0;
}

输出

 0  1  2 
 1  2  3 

3. 多级指针的常见陷阱

1. 野指针风险

int **pp;
*pp = (int*)malloc(sizeof(int));  // 错误!pp未初始化,指向随机地址。

防御:确保多级指针指向合法内存后再操作。

2. 内存泄漏

int **matrix = malloc(3 * sizeof(int*));
// 忘记释放matrix和每行的内存!

防御:逐层释放内存,顺序为先释放子内存,再释放父指针。

3. 越级解引用

int a = 10;
int **pp = &a;  // 错误!pp应为int**类型,但&a是int*类型。

 防御:严格匹配指针层级和数据类型。

4. 总结

核心规则

  • 层级匹配n级指针需指向(n-1)级指针的地址。

  • 内存管理:动态分配的多级指针必须逐层释放。

  • 类型安全:解引用时需确保层级和数据类型一致,避免未定义行为。


http://www.kler.cn/a/527687.html

相关文章:

  • 离散化C++
  • 创新创业计划书|建筑垃圾资源化回收
  • DeepSeek介绍及使用ollama本地化部署DeepSeek-R1大模型
  • 【C语言】在Windows上为可执行文件.exe添加自定义图标
  • 供应链系统设计-供应链中台系统设计(十)- 清结算中心概念片篇
  • DeepSeek-R1本地部署笔记
  • 在排序数组中查找元素的第一个和最后一个位置(力扣)
  • 一文介绍Hive数据类型
  • 寒假刷题Day18
  • Vue.js组件开发-实现滑块滑动无缝切换和平滑切换动画
  • AI作画提示词:Prompts工程技巧与最佳实践
  • 第11章:根据 ShuffleNet V2 迁移学习医学图像分类任务:甲状腺结节检测
  • Java 9模块开发:Eclipse实战指南
  • Autogen_core源码:_agent_runtime.py
  • FOC核心原理的C语言实现
  • Redis代金卷(优惠卷)秒杀案例-单应用版
  • 如何在数据湖中有效治理和管理“数据沼泽”问题,提高数据的可发现性和利用率?
  • vulkan从小白到专家——RenderPassFramebuffer
  • JavaScript函数中this的指向
  • python 文件操作全知道 | python 小知识
  • 36. printf
  • 团体程序设计天梯赛-练习集——L1-029 是不是太胖了
  • 大模型高频知识汇总:查漏补缺参考大全
  • 【Redis】set 和 zset 类型的介绍和常用命令
  • oracl:多表查询>>表连接[内连接,外连接,交叉连接,自连接,自然连接,等值连接和不等值连接]
  • Docker小游戏 | 使用Docker部署跳一跳经典小游戏