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

目录

[1. 多级指针的核心原理](#1. 多级指针的核心原理)

[1. 多级指针的定义](#1. 多级指针的定义)

[2. 内存结构示意图](#2. 内存结构示意图)

[3. 多级指针的用途](#3. 多级指针的用途)

[2. 编程实例](#2. 编程实例)

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

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

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

[3. 多级指针的常见陷阱](#3. 多级指针的常见陷阱)

[4. 总结](#4. 总结)


1. 多级指针的核心原理

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

1. 多级指针的定义

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

2. 内存结构示意图

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

3. 多级指针的用途

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

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

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

2. 编程实例

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

cpp 复制代码
#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;
}

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

cpp 复制代码
Before: *p = 10
After: *p = 20

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

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

cpp 复制代码
#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;
}

输出

cpp 复制代码
 0  1  2  3 
 4  5  6  7 
 8  9 10 11 

内存示意图

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

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

cpp 复制代码
#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;
}

输出

cpp 复制代码
 0  1  2 
 1  2  3 

3. 多级指针的常见陷阱

1. 野指针风险

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

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

2. 内存泄漏

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

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

3. 越级解引用

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

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

4. 总结

核心规则

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

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

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

相关推荐
code_pgf5 小时前
C++11 / C++14 / C++17 / C++20 新特性总结
c++·c++20
魔力女仆5 小时前
分享一个 JS 鼠标跟随贪吃蛇背景库
开发语言·javascript·计算机外设
2401_894915536 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
麻瓜老宋6 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十二步,分号赋值链式修复、TOKEN_ASSIGN
c语言·开发语言·atomcode
颜x小8 小时前
[C#] C++与c#语法对比
开发语言·c++·c#
Freak嵌入式8 小时前
MCU 低功耗模式解析:时钟门控、电源门控、深度休眠
人工智能·python·单片机·嵌入式硬件·开源·依赖倒置原则·micropython
weixin_423652139 小时前
C#使用JObject
开发语言·c#
国科安芯9 小时前
FreeRTOS RISC-V 浮点上下文切换移植:在 IAR 工程中完整保存 FPU 寄存器
java·开发语言·单片机·嵌入式硬件·算法·系统架构·risc-v
躺不平的理查德9 小时前
STM32时钟树(Clock Tree)
stm32·单片机·嵌入式硬件
小poop9 小时前
轮转数组:从暴力到最优,一题掌握算法复杂度分析
数据结构·算法·leetcode