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

news2025/3/7 0:14:27

目录

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.coloradmin.cn/o/2289366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习的应用

目录 一、机器视觉 1.1 应用场景 1.2 常见的计算机视觉任务 1.2.1 图像分类 1.2.2 目标检测 1.2.3 图像分割 二、自然语言处理 三、推荐系统 3.1 常用的推荐系统算法实现方案 四、图像分类实验补充 4.1 CIFAR-100 数据集实验 实验代码 4.2 CIFAR-10 实验代码 深…

RabbitMQ 多种安装模式

文章目录 前言一、Windows 安装 RabbitMq1、版本关系2、Erlang2.1、下载安装 Erlang 23.12.2、配置 Erlang 环境变量 3、RabbitMQ3.1、下载安装 RabbitMQ 3.8.93.2、环境变量3.3、启动RabbitMQ 管理插件3.3、RabbitMQ3.4、注意事项 二、安装docker1、更新系统包&#xff1a;2、…

吴恩达深度学习——有效运作神经网络

内容来自https://www.bilibili.com/video/BV1FT4y1E74V&#xff0c;仅为本人学习所用。 文章目录 训练集、验证集、测试集偏差、方差正则化正则化参数为什么正则化可以减少过拟合Dropout正则化Inverted Dropout其他的正则化方法数据增广Early stopping 归一化梯度消失与梯度爆…

DDD - 微服务架构模型_领域驱动设计(DDD)分层架构 vs 整洁架构(洋葱架构) vs 六边形架构(端口-适配器架构)

文章目录 引言1. 概述2. 领域驱动设计&#xff08;DDD&#xff09;分层架构模型2.1 DDD的核心概念2.2 DDD架构分层解析 3. 整洁架构&#xff1a;洋葱架构与依赖倒置3.1 整洁架构的核心思想3.2 整洁架构的层次结构 4. 六边形架构&#xff1a;解耦核心业务与外部系统4.1 六边形架…

数据结构与算法之二叉树: LeetCode LCP 10. 二叉树任务调度 (Ts版)

二叉树任务调度 https://leetcode.cn/problems/er-cha-shu-ren-wu-diao-du/description/ 描述 任务调度优化是计算机性能优化的关键任务之一。在任务众多时&#xff0c;不同的调度策略可能会得到不同的总体执行时间&#xff0c;因此寻求一个最优的调度方案是非常有必要的 通…

玩转大语言模型——配置图数据库Neo4j(含apoc插件)并导入GraphRAG生成的知识图谱

系列文章目录 玩转大语言模型——使用langchain和Ollama本地部署大语言模型 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 玩转大语言模型——使用GraphRAGOllama构建知识图谱 玩转大语言模型——完美解决Gra…

计算机毕业设计Python+CNN卷积神经网络考研院校推荐系统 考研分数线预测 考研推荐系统 考研爬虫 考研大数据 Hadoop 大数据毕设 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

OpenCV:闭运算

目录 1. 简述 2. 用膨胀和腐蚀实现闭运算 2.1 代码示例 2.2 运行结果 3. 闭运算接口 3.1 参数详解 3.2 代码示例 3.3 运行结果 4. 闭运算的应用场景 5. 注意事项 相关阅读 OpenCV&#xff1a;图像的腐蚀与膨胀-CSDN博客 OpenCV&#xff1a;开运算-CSDN博客 1. 简述…

智云-一个抓取web流量的轻量级蜜罐-k8s快速搭建教程

智云-一个抓取web流量的轻量级蜜罐-k8s快速搭建教程 github地址 https://github.com/xiaoxiaoranxxx/POT-ZHIYUN k8s搭建教程 首先下载代码文件 git clone https://github.com/xiaoxiaoranxxx/POT-ZHIYUN.git cd POT-ZHIYUN编译镜像 代码相关文件在github https://github.com/x…

万物皆有联系:驼鸟和布什

布什&#xff1f;一块布十块钱吗&#xff1f;不是&#xff0c;大家都知道&#xff0c;美国有两个总统&#xff0c;叫老布什和小布什&#xff0c;因为两个布什总统&#xff08;父子俩&#xff09;&#xff0c;大家就这么叫来着&#xff0c;目的是为了好区分。 布什总统的布什&a…

< OS 有关 > 阿里云:轻量应用服务器 的使用 :轻量化 阿里云 vpm 主机

原因&#xff1a; &#xff1c; OS 有关 &#xff1e; 阿里云&#xff1a;轻量应用服务器 的使用 &#xff1a;从新开始 配置 SSH 主机名 DNS Tailscale 更新OS安装包 最主要是 清除阿里云客户端这个性能杀手-CSDN博客 防止 I/O 祸害系统 操作&#xff1a; 查看进程&#x…

SOME/IP--协议英文原文讲解3

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 Note: Thi…

unity学习24:场景scene相关生成,加载,卸载,加载进度,异步加载场景等

目录 1 场景数量 SceneManager.sceneCount 2 直接代码生成新场景 SceneManager.CreateScene 3 场景的加载 3.1 用代码加载场景&#xff0c;仍然build setting里先加入配置 3.2 卸载场景 SceneManager.UnloadSceneAsync(); 3.3 同步加载场景 SceneManager.LoadScene 3.3.…

四.4 Redis 五大数据类型/结构的详细说明/详细使用( zset 有序集合数据类型详解和使用)

四.4 Redis 五大数据类型/结构的详细说明/详细使用&#xff08; zset 有序集合数据类型详解和使用&#xff09; 文章目录 四.4 Redis 五大数据类型/结构的详细说明/详细使用&#xff08; zset 有序集合数据类型详解和使用&#xff09;1. 有序集合 Zset(sorted set)2. zset 有序…

S4 HANA税码科目确定(OB40)

本文主要介绍在S4 HANA OP中税码科目确定(OB40)相关设置。具体请参照如下内容&#xff1a; 税码科目确定(OB40) 在以上界面维护“Transaction Key”的记账码。 在以上界面进一步维护“Transaction Key”确定科目的规则。 Chart of Account:用于明确该规则适用于什么科目表。 …

vim的特殊模式-可视化模式

可视化模式&#xff1a;按 v进入可视化模式 选中 y复制 d剪切/删除 可视化块模式: ctrlv 选中 y复制 d剪切/删除 示例&#xff1a; &#xff08;vim可视化模式的进阶使用&#xff1a;vim可视化模式的进阶操作-CSDN博客&#xff09;

UE5制作视差图

双目深度估计开源数据集很多都是用UE制作的&#xff0c;那么我们自己能否通过UE制作自己想要的场景的数据集呢。最近花了点时间研究了一下&#xff0c;分享给需要的小伙伴。 主要使用的是UnrealCV插件&#xff0c;UnrealCV是一个开源项目&#xff0c;旨在帮助计算机视觉研究人…

记忆化搜索(5题)

是什么&#xff1f; 是一个带备忘录的递归 如何实现记忆化搜索 1.添加一个备忘录&#xff08;建立一个可变参数和返回值的映射关系&#xff09; 2.递归每次返回的时候把结果放到备忘录里 3.在每次进入递归的时候往备忘录里面看看。 目录 1.斐波那契数列 2.不同路径 3.最…

【游戏设计原理】96 - 成就感

成就感是玩家体验的核心&#xff0c;它来自完成一件让自己满意的任务&#xff0c;而这种任务通常需要一定的努力和挑战。游戏设计师的目标是通过合理设计任务&#xff0c;不断为玩家提供成就感&#xff0c;保持他们的参与热情。 ARCS行为模式&#xff08;注意力、关联性、自信…

【设计测试用例自动化测试性能测试 实战篇】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 设计测试用例…