多重指针变量(n重指针变量)实例分析

0 前言

指针之于C语言,就像子弹于枪械。没了子弹的枪械虽然可以用来肉搏,却失去了迅速解决、优雅解决战斗的能力。但上了膛的枪械也非常危险,时刻要注意是否上了保险,使用C语言的指针也是如此,要万分小心,一着不慎就可能灰飞烟灭。
对于一重指针,熟悉C语言的已经烂熟于心,但很多人对于双重指针甚至n重指针仍然抱有恐惧的心理。本文从实例出发,讲解多重指针背后的意义和使用方法。

1 n重指针介绍

1.0 什么是指针?什么是指针变量?什么是解引用?

很多人经常习惯性将指针变量说成指针,实际上指针和指针变量不是同一个东西。指针和指针变量的区别如下:

指针:内存地址
指针变量:存放内存地址的变量
解引用:*运算符获取指针(内存地址)指向(表示的)对象的值(也就是获取内存地址上存储的值,获取大小和指针类型有关)
指针和指针变量的大小都是CPU寻址的位数大小,假如使用32位MCU则大小为32位。

有关指针变量的定义和解引用及指针的解引用操作实例如下:

int main(void)
{int val = 0x1234;int *p = &val;                                    // 指针变量,初值为变量val的内存地址printf("*p            : 0x%x\r\n", *p);           // 解引用指针变量printf("*(int *)&val  : 0x%x\r\n", *(int *)&val); // 将val地址强制转换成int型指针,然后解引用return 0;
}

打印结果如下:
在这里插入图片描述

1.1 n重指针解引用

下面是1-4重指针的解引用,简单来说n重指针存储的是n-1重指针的地址,如果n=1(一重指针)则存储的就是对象地址:

#include "stdio.h"int main(void)
{int val = 0x1234;int *p1 = &val;int **p2 = &p1;int ***p3 = &p2;int ****p4 = &p3;printf("****(int ****)p4 : 0x%x\r\n", ****(int ****)p4);printf("***(int ***)p3   : 0x%x\r\n", ***(int ***)p3);printf("**(int **)p2     : 0x%x\r\n", **(int **)p2);printf("*(int *)p1       : 0x%x\r\n", *(int *)p1);return 0;
}

打印结果:
在这里插入图片描述

1.2 n重指针变量的定义及解引用

下面是1-4重指针变量的解引用,简单来说n重指针变量存储的是n-1重指针变量的地址,如果n=1(一重指针变量)则存储的就是对象地址:

int main(void)
{int val = 0x1234;int *p1 = &val;int **p2 = &p1;int ***p3 = &p2;int ****p4 = &p3;printf("****p4 : 0x%x\r\n", ****p4);printf("***p3  : 0x%x\r\n", ***p3);printf("**p2   : 0x%x\r\n", **p2);printf("*p1    : 0x%x\r\n", *p1);return 0;
}

打印结果:
在这里插入图片描述
我们定义n重指针变量,可以将它拆开成2个部分看:
在这里插入图片描述
解引用的赋值也可以看成2个部分:
在这里插入图片描述

1.3 多重指针变量的用途

1.3.1 修改指针变量的值

实际上,假如我们定义多重指针变量只是为了获取对象的值,那多重指针变量相当于绕远路到达终点而不是直接使用一重指针变量直达终点。绕远路到达终点的好处在于可以修改中间指针变量的值,甚至修改我们的目的地。假如我们需要在子函数内修改父函数的指针变量的值,就可以用到双重指针,例子如下:

/*** @brief 将p的值修改为0x12345678* * @param p 双重指针*/
void set_p(int **p)
{*p = (int *)0x12345678;
}int main(void)
{int *p1;set_p(&p1);printf("p1 val : 0x%X\r\n", p1);
}

打印结果如下:
在这里插入图片描述
说明:
我们通过&操作符取一重指针p1的内存地址传递给形参(二重指针,避免编译器警告),形参内对p1的内存地址进行一次解引用然后赋值,将p1的值修改为0x12345678。

1.3.2 避免编译器警告

对我们来说指针就是地址,n重指针存储的也是地址,那么我们为什么不可以全部使用一重指针去解引用指针呢?这主要是为了让编译器理解我们的意图,避免告警。下面的例子就会出现一个警告:

/*** @brief 将p的值修改为0x12345678* * @param p 双重指针*/
void set_p(int *p)
{*p = (int)0x12345678;
}int main(void)
{int *p1;set_p(&p1);printf("p1 val : 0x%X\r\n", p1);
}

警告内容:
在这里插入图片描述
打印结果:
在这里插入图片描述
说明:
实际上我们通过一重指针也可以修改指针变量的值,但是编译器不知道我们的意图,向我们抛出了警告。因此,多重指针在一些场合下还可以避免警告产生。

1.4 在物理层面看多重指针的意义

指针就是内存地址,是有实际物理意义的。下面打印1-4重指针在内存上的地址,分析物理内存上多重指针解引用的过程。相关程序如下:

int main(void)
{int val = 0x12345678;int *p1 = &val;int **p2 = &p1;int ***p3 = &p2;int ****p4 = &p3;/* 地址 */printf("val addr : 0x%X\r\n", &val);printf("p1 addr  : 0x%X\r\n", &p1);printf("p2 addr  : 0x%X\r\n", &p2);printf("p3 addr  : 0x%X\r\n", &p3);printf("p4 addr  : 0x%X\r\n", &p4);/* 解引用时值变化过程 */printf("*p1    : 0x%x \r\n", *p1);printf("**p2   : 0x%x -> 0x%x\r\n", *p2, **p2);printf("***p3  : 0x%x -> 0x%x -> 0x%x\r\n", *p3, **p3, ***p3);printf("****p4 : 0x%x -> 0x%x -> 0x%x -> 0x%x\r\n", *p4, **p4, ***p4, ****p4);
}

打印结果如下:
在这里插入图片描述
注:本文使用PC运行该程序,CPU寻址位数为64位,因此指针大小为64位。
示意图如下(以p4的解引用为例):
在这里插入图片描述

2 总结

(1)指针就是内存地址,指针变量就是存储了内存地址的变量,指针的大小和CPU支持的寻址位数一致,指针解引用对象的大小和指针类型大小一致。
(2)多重指针可以作为函数形参,来实现对指针变量的修改。
(3)多重指针的解引用可以理解为绕远路获取对象的值,n重指针只有进行n次解引用才能获取到对象的值,1-n-1次解引获取到的都是指针(内存地址)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/427955.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【VUE3.0】动手做一套像素风的前端UI组件库---先导篇

系列文章目录 【VUE3.0】动手做一套像素风的前端UI组件库—Button 目录 系列文章目录引言准备素材字体鼠标手势图 创建vue3项目构建项目1. 根据命令行提示选择如下:2. 进入项目根目录下载依赖并启动。3. 设置项目src路径别名,方便后期应用路径。4. 将素…

solana项目counter,测试过程中执行报错记录分享

跟随HackQuest部署counter项目,使用 Solana 官方提供的 playgroud 。这个平台让我们的部署和测试过程变得更加简便高效。 合约代码 lib.rs中复制以下代码 use anchor_lang::prelude::*; use std::ops::DerefMut;declare_id!("CVQCRMyzWNr8MbNhzjbfPu9YVvr97…

Amoco:一款针对二进制源码的安全分析工具

关于Amoco Amoco是一款功能强大的二进制源码静态分析工具,该工具基于Python 3.8开发,可以帮助广大研究人员轻松对二进制程序执行静态符号分析。 工具特性 1、一个通用的指令解码框架,旨在减少实现对新架构的支持所需的时间。例如&#xff0c…

通过springcloud gateway优雅的进行springcloud oauth2认证和权限控制

代码地址 如果对你有帮助请给个start,本项目会持续更新,目标是做一个可用的快速微服务开发平台,成为接私活,毕设的开发神器, 欢迎大神们多提意见和建议 使用的都是spring官方最新的版本,版本如下&#xff1…

F12抓包11:UI自动化 - Recoder(记录器)

课程大纲 使用场景(导入和导出): ① 测试的重复性工作,本浏览器录制并进行replay; ② 导入/导出录制脚本,移植后replay; ③ 导出给开发进行replay复现bug; ④ 进行前端性能分析。 1、录制脚…

Virtuoso服务在centos中自动停止的原因分析及解决方案

目录 前言1. 问题背景2. 原因分析2.1 终端关闭导致信号12.2 nohup命令的局限性 3. 解决方案3.1 使用 screen 命令保持会话3.2 使用 tmux 作为替代方案3.3 使用系统服务(systemd) 4. 其他注意事项4.1 网络配置4.2 日志监控 结语 前言 在使用Virtuoso作为…

mybatisplus映射与数据库表格不一致问题

1.字段映射与属性名不一致 TableField(value"数据库字段名") 2.entity添加了数据库表格不存在的属性 TableField(existfalse) 3.entity对象查询时,有些字段不想要显示在查询结果上 TableField(selectfalse) 4.表名不一致 TableName("数据库表名&…

爬虫--翻页tips

免责声明:本文仅做分享! 伪线程 from DrissionPage import ChromiumPage import timepage ChromiumPage() page.get("https://you.ctrip.com/sight/taian746.html") # 初始化 第0页 index_page 0# 翻页点击函数 sleep def page_turn():page…

使用API有效率地管理Dynadot域名,为域名进行隐私保护设置

前言 Dynadot是通过ICANN认证的域名注册商,自2002年成立以来,服务于全球108个国家和地区的客户,为数以万计的客户提供简洁,优惠,安全的域名注册以及管理服务。 Dynadot平台操作教程索引(包括域名邮箱&…

八股文-多线程、并发

八股文-多线程、并发 最近学到了一种方法,可以用于简历项目经验编写以及面试题目的回答 STAR法则:在什么背景下,你需要解决什么问题,你做了啥,得到了什么结果 情境(Situation): 描…

电子元件制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

5G智能工厂与物联数字孪生平台的融合应用,不仅为电容器制造业注入了新的活力,更为整个制造业的数字化转型树立了新的标杆。电子元件制造过程中,数字孪生平台通过实时监测生产线的各个环节,实现了生产流程的可视化监控。管理人员可…

苹果M4 MacBook Air被曝2025Q1发布 屏幕面板10月出货

9 月 20 日最新消息屏幕供应链咨询公司 DSCC 首席执行官罗斯・杨(Ross Young)昨日(9 月 19 日)在 X 平台面向其订阅用户发布推文,透露苹果 M4 MacBook Air 与低成本 iPad 的屏幕预估将于今年 10 月开始出货。 苹果正在…

海外盲盒APP为盲盒出海助力,拓展海外市场

潮玩市场是一个具有全球化的行业在全球都具有非常高的发展潜力,随着国内盲盒市场的饱和,拓展海外市场对盲盒企业至关重要。近年来,盲盒已经在海外市场取得了一定的成绩,这为企业拓展海外市场奠定了发展基础。 目前,在…

基于FPGA+GPU异构平台的遥感图像切片解决方案

随着遥感和成像技术的不断进步和普及,获取大量高分辨率的遥感图像已成为可能。这些大规模的遥感图像数据需要进行有效的处理和分析,以提取有用的信息,进行进一步的应用。遥感图像切片技术应运而生,该技术可以将大型遥感图像分割成…

[苍穹外卖]-10WebSocket入门与实战

WebSocket WebSocket是基于TCP的一种新的网络协议, 实现了浏览器与服务器的全双工通信, 即一次握手,建立持久连接,双向数据传输 区别 HTTP是短连接, WebSocket是长连接HTTP单向通信, 基于请求响应模型WebSocket支持双向通信 相同 HTTP和WebSocket底层都是TCP连接 应用场景…

Go语言练习——语法实践

目录 一、数组 1.多维数组的声明和使用 2.数组与切片的转换 3.数组在函数中的使用 二、切片 1.切片的动态扩容机制 2.切片的复制与修改 3.切片在排序算法中的应用 三、结构体 1.结构体的嵌套与方法 2.结构体与JSON的序列化 3.结构体的工厂模式 四、映射 1.映射的并发访问 2.映射…

SEGGERS实时系统embOS推出Linux端模拟器

SEGGER 发布了两个新的 embOS 仿真模拟器:embOS Sim Linux 和 embOS-MPU Sim Linux。 通过模拟 Linux 主机系统上的硬件,取代物理硬件,为开发人员提供了一种无缝的方式来构建原型和测试应用程序。 embOS Sim Linux 端口支持 32 位和 64 位系…

对商品分类系统的若干问题的思考

科学研究的目的就是研究事物的特征,并根据共同的特征加以分类 商品分类是商业,制造业中最普遍的活动,几乎所有的企业,电商平台都要对销售的商品,使用的原材料(BOM)进行分类和编号。 商品分类貌似…

从零开始学习Linux(12)---进程间通信(信号量与信号)

目录 1.信号量 2.信号 1.core功能 2.信号集 3.内核态和用户态 用户态(User Mode) 内核态(Kernel Mode) 4.volatile关键字 1.信号量 信号量是计算机科学中用于同步和互斥的一种抽象数据类型。在并发编程中&#xff…

集群聊天服务器项目【C++】项目介绍和环境搭建

前言:学习一个基于C集群聊天服务器的项目,记录学习的内容和学习的过程。 1.项目介绍 在 Linux 环境下基于 muduo 开发的集群聊天服务器。实现新用户注册、用户登录、添加好友、添加群组、好友通信、群组聊天、保持离线消息等功能。 2.技术栈 Json序列…