深入理解指针初阶:从概念到实践
一、引言
在 C 语言的学习旅程中,指针无疑是一座必须翻越的高峰。它强大而灵活,掌握指针,能让我们更高效地操作内存,编写出更优化的代码。但指针也常常让初学者望而生畏,觉得它复杂难懂。别担心,本文将用通俗易懂的语言,结合丰富的代码示例,带你逐步揭开指针初阶的神秘面纱,让你从入门到熟练掌握指针的基础概念与应用
二、指针是什么
2.1 概念剖析
指针是编程语言中的一个特殊对象,它的值是内存中另一个数据的地址。在计算机的内存世界里,每一个存储单元都有一个唯一的编号,就像我们住的房子都有门牌号一样,这个编号就是地址。而指针变量,就是专门用来存放这些地址的变量。
想象一下,内存是一个巨大的仓库,里面有无数个小格子(内存单元),每个小格子都存放着不同的数据。指针就像是一把带有格子编号(地址)的钥匙,通过这把钥匙,我们就能快速找到并访问对应的格子里的数据
2.2 代码示例

这段代码中,int *p声明了一个指针变量p,它的类型是int *,表示它可以存放int类型变量的地址。&a获取了变量a的地址,然后将这个地址赋值给p。此时,p就指向了变量a所在的内存单元
2.3 内存编址与指针大小
计算机的内存编址方式与机器的位数密切相关。对于 32 位机器,假设有 32 根地址线,每根地址线在寻址时能产生一个电信号(正电或负电,对应 1 或 0),那么 32 根地址线产生的地址数量就是2^32个。由于每个地址标识一个字节(1Byte),所以 32 位机器可以编址的内存空间大小2^32,换算后就是 4GB(2^32/1024/1024/1024 GB)。
在 32 位机器上,地址是由 32 个 0 或 1 组成的二进制序列,这样的地址需要用 4 个字节的空间来存储,因此一个指针变量的大小就是 4 个字节。同理,64 位机器有 64 根地址线,能产生2^64个地址,可以编址的内存空间更大,而一个指针变量的大小为 8 个字节,才能存放一个地址。
总结来说,指针是用来存放地址的变量,地址唯一标识一块内存空间,指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8个字节
三、指针和指针类型
3.1 指针类型的定义
变量有不同的类型,如整形int、浮点型float等,指针也有类型。指针的定义方式是type + *,例如:

这里,char*类型的指针用于存放char类型变量的地址,short*类型的指针用于存放short类型变量的地址,以此类推。NULL是一个特殊的指针常量,表示空指针,即不指向任何有效内存地址
3.2 指针类型的意义
指针类型在指针运算中起着关键作用,主要体现在两个方面:指针加减整数和指针解引用
3.2.1 指针加减整数

在这段代码中,pc是char*类型的指针,pi是int*类型的指针,它们都指向变量n。当pc + 1时,指针向前移动 1 个字节;而pi + 1时,指针向前移动 4 个字节(假设在 32 位机器上,int类型占 4 个字节)。这表明指针的类型决定了指针向前或向后移动一步的距离
3.2.2 指针解引用

在调试这段代码时可以发现,*pc = 0只修改了n所在内存空间的 1 个字节,而*pi = 0则修改了n所在内存空间的 4 个字节(假设int类型占 4 个字节)。这说明指针的类型决定了对指针解引用时的权限,即能操作几个字节。char*的指针解引用只能访问 1 个字节,而int*的指针解引用能访问 4 个字节
四、野指针
4.1 野指针的概念
野指针是指指针指向的位置不可知(随机、不正确、没有明确限制)的指针。当指针变量在定义时未初始化,其值是随机的,此时去解引用这个指针,就相当于访问了一个不确定的地址,结果是不可预测的,可能导致程序崩溃或产生其他未定义行为。
4.2 野指针的成因
4.2.1 指针未初始化

在这段代码中,p是一个未初始化的指针,它的值是随机的,对其进行解引用操作*p = 20,会访问一个不确定的内存地址,这是非常危险的
4.2.2 指针越界访问

这里,数组arr有 10 个元素,合法的下标范围是 0 到 9。但在for循环中,i的值可以达到 11,当i为 10 和 11 时,指针p超出了数组arr的范围,成为野指针,此时对p进行解引用操作会访问到不属于数组的内存区域,可能导致程序出错
4.2.3 指针指向的空间释放(动态内存开辟时讲解,此处简单提示)
在使用动态内存分配函数(如malloc)时,如果释放了指针指向的内存空间,但没有及时将指针置为NULL,那么该指针就会变成野指针。例如:

4.2.4返回局部变量的指针
局部变量在函数内部定义,其作用域仅限于函数内部。当函数执行结束,局部变量所占用的内存空间会被系统自动释放。若在函数中返回指向局部变量的指针,函数结束后,该指针指向的内存空间已无效,但指针本身依然存在,进而成为野指针

在上述代码中,test函数返回了指向局部变量num的指针。当test函数执行完毕,num所在内存空间被释放,p就变成了野指针。此时对p进行解引用操作,程序行为未定义,可能输出看似正确的值(若释放的内存未被覆盖),也可能导致程序崩溃
4.3 规避野指针的方法
4.3.1 指针初始化
在定义指针变量时,尽量给它一个初始值,可以是NULL,也可以是指向合法内存地址的值。例如:

4.3.2 小心指针越界
在使用指针访问数组或其他内存区域时,要确保指针不会超出其合法范围。在访问数组元素时,要注意下标的边界条件。
4.3.3 指针指向空间释放及时置NULL
当释放了指针指向的内存空间后,立即将指针置为NULL,这样可以避免误操作。例如:

4.3.4 指针使用之前检查有效性
在使用指针之前,检查指针是否为NULL,以确保指针指向的是有效内存地址。例如:

4.3.5 避免返回局部变量的地址
五、指针运算
指针运算主要包括指针加减整数、指针减指针和指针的关系运算
5.1 指针加减整数
指针加减整数的运算规则与指针类型密切相关。前面已经介绍过,指针的类型决定了指针移动一步的距离。下面通过一个示例来进一步理解:

在这段代码中,vp是float*类型的指针,for循环中vp++每次使vp向后移动 4 个字节(假设float类型占 4 个字节),从而遍历整个values数组,并将数组元素初始化为 0
5.2 指针减指针
指针减指针的结果是两个指针之间元素的个数(前提是两个指针指向同一块连续内存区域)。下面是一个计算字符串长度的函数示例:

在这个函数中,p和s都是char*类型的指针,p从字符串的起始位置开始,逐个字符向后移动,直到遇到字符串结束标志'\0'。最后返回p - s,即字符串的长度(不包括'\0')
5.3 指针的关系运算
指针的关系运算允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但不允许与指向第一个元素之前的那个内存位置的指针进行比较。例如:

在第一个for循环中,vp从数组最后一个元素后面的位置开始,向前移动并初始化数组元素。虽然在大部分编译器上第二个简化的for循环也能正常工作,但从标准角度来看,不建议这样写,因为标准并不保证其可行性
六、指针和数组
6.1 数组名与指针的关系
数组名在很多情况下表示的是数组首元素的地址。通过下面的代码可以验证:

6.2 用指针访问数组元素
由于数组名可以当成地址存放到一个指针中,因此我们可以使用指针来访问数组元素。例如:

在这段代码中,p指向数组arr的首元素,p + i计算的是数组arr下标为i的元素的地址。通过这种方式,我们可以直接用指针遍历数组并访问元素:

这里,*(p + i)就相当于arr[i],通过指针间接访问数组元素并输出其值
七、二级指针
7.1 二级指针的概念
指针变量也是变量,既然是变量就有地址。二级指针就是用来存放一级指针变量地址的指针。例如:

在这个例子中,a是一个普通的int类型变量,pa是指向a的一级指针,ppa是指向pa的二级指针
7.2 二级指针的运算
二级指针的运算主要涉及解引用操作

在这段代码中,*ppa通过对ppa中的地址进行解引用,找到的是pa,因此*ppa = &b就相当于pa = &b,使pa指向了变量b。而**ppa先通过*ppa找到pa,然后对pa进行解引用操作*pa,找到的是a,所以**ppa = 30就相当于*pa = 30,最终相当于a = 30
八、指针数组
8.1 指针数组的定义
指针数组是一个数组,数组中的每个元素都是一个指针。例如:

这里,arr3是一个指针数组,它有 5 个元素,每个元素都是一个int*类型的指针。
8.2 指针数组的应用场景
指针数组在处理多个相同类型的指针时非常方便。在处理多个字符串时,可以使用指针数组来存储每个字符串的首地址:

在这个例子中,strs是一个指针数组,每个元素都是一个指向char类型的指针,分别指向不同的字符串。通过遍历指针数组,可以方便地访问每个字符串。
九、总结
本文详细介绍了指针初阶的各个重要知识点,包括指针的基本概念、指针类型、野指针、指针运算、指针与数组的关系、二级指针以及指针数组。指针作为 C 语言的核心特性之一,虽然具有一定的复杂性,但通过深入理解其原理,并结合大量的代码实践,我们能够逐步掌握它,并在编程中充分发挥其强大的功能。希望读者在学习指针的过程中,多思考、多实践,不断积累经验,为后续更深入的 C 语言学习和编程开发打下坚实的基础
相关文章:
深入理解指针初阶:从概念到实践
一、引言 在 C 语言的学习旅程中,指针无疑是一座必须翻越的高峰。它强大而灵活,掌握指针,能让我们更高效地操作内存,编写出更优化的代码。但指针也常常让初学者望而生畏,觉得它复杂难懂。别担心,本文将用通…...
《手札·行业篇》开源Odoo MES系统与SKF Observer Phoenix API在化工行业的双向对接方案
一、项目背景 化工行业生产过程复杂,设备运行条件恶劣,对设备状态监测、生产数据采集和质量控制的要求极高。通过开源Odoo MES系统与SKF Observer Phoenix API的双向对接,可以实现设备状态的实时监测、生产数据的自动化采集以及质量数据的同步…...
oracle11g搭建主从集群
安装oracle11g参考:centos安装oracle11g数据库-CSDN博客 一、主库操作 sqlplus / as sysdba 1、开启归档模式和强制日志模式 shutdown immediate startup mount #开启归档模式和强制日志模式 alter database archivelog; alter database force logging; #开启补…...
暂未整理啊
测码学院 python的数据类型 不可变数据类型:字符串/数字/元组/ type(变量名) 获得数据的类型 str:字符串 int:整数 float:浮点数 bool:true/false 布尔类型 list:列表 dict&…...
重庆西站公路桥梁自动化监测
1.项目概述 重庆西站属于渝黔铁路的配套工程,是承担兰渝、川黔、渝昆等多条铁路的特级客运站,未来重庆铁路三大客运站之一。作为我国西部地区规模最大的火车站、重庆西站于2014年在沙坪坝区上桥开工建设,该站东临内环高速,西靠中梁山&#x…...
JavaScript系列(70)--响应式编程进阶详解
JavaScript响应式编程进阶详解 🔄 今天,让我们深入探讨JavaScript响应式编程的进阶内容。响应式编程是一种强大的编程范式,它能够帮助我们更好地处理异步数据流和状态管理。 响应式编程进阶概念 🌟 💡 小知识&#x…...
安装指定版本的pnpm
要安装指定版本的 pnpm,可以使用以下方法: 方法 1: 使用 pnpm 安装指定版本 你可以通过 pnpm 的 add 命令来安装指定版本: pnpm add -g pnpm<版本号>例如,安装 pnpm 的 7.0.0 版本: pnpm add -g pnpm7.0.0方法…...
Dockerfiles 的 Top 10 常见 DevOps/SRE 面试问题及答案
1. RUN 和 CMD 之间有什么区别? RUN : 在镜像构建过程中执行命令,创建一个新的层。通常用于安装软件包。 示例: RUN apt-get update && apt-get install -y curlCMD : 指定容器启动时默认运行的命令。它在运行时执行,而不是在构建过程…...
头条百度批量采集软件说明文档
旧版说明文档《头条号文章批量采集软件4.0版本说明文档!头条/微头条文章批量采集》 头条的采集软件已经更新了好多个版本了,一直没有做详细的介绍文档,最近更新了一些功能进去,一块来写一下说明文档。 1、主界面 2、头条作者采集…...
36.日常算法
1.最小栈 题目来源 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取堆…...
计算机考研复试上机04
目录 6、向量 1)完数与盈数(清华大学复试上机题) 7、队列 1)约瑟夫问题 No. 2 8、栈 1)简单计算器(浙江大学复试上机题) 2)堆栈的使用(吉林大学复试上机题…...
【面试】面试常见的智力题
引言 在技术面试中,除了考察编程能力和算法知识外,智力题也是常见的考察方式。智力题不仅能够测试候选人的逻辑思维能力,还能反映其解决问题的创造力和应变能力。本文将整理一些常见的面试智力题,并详细分析解题思路,…...
【动态规划】风扫枯杨,满地堆黄叶 - 9. 完全背包问题
本篇博客给大家带来的是完全背包问题之动态规划解法技巧. 🐎文章专栏: 动态规划 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺…...
BGP基础协议详解
BGP基础协议详解 一、BGP在企业中的应用二、BGP概述2.1 BGP的特点2.2 基本配置演示2.3 抓包观察2.4 BGP的特征三、BGP对等体关系四、bgp报文4.1 BGP五种报文类型(重点)4.2 BGP报文格式-报文头格式4.3 Open报文格式4.4 Update报文格式4.5 Notification报文格式4.6 Route-refre…...
LeetCode刷题---数组---840
矩阵中的幻方 https://leetcode.cn/problems/magic-squares-in-grid/submissions/598584907/ 题目: 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成…...
Visual Studio踩过的坑
统计Unity项目代码行数 编辑-查找和替换-在文件中查找 查找内容输入 b*[^:b#/].*$ 勾选“使用正则表达式” 文件类型留空 也有网友做了指定,供参考 !*\bin\*;!*\obj\*;!*\.*\*!*.meta;!*.prefab;!*.unity 打开Unity的项目 注意:只是看࿰…...
【深度学习入门实战】基于Keras的手写数字识别实战(附完整可视化分析)
本人主页:机器学习司猫白 ok,话不多说,我们进入正题吧 项目概述 本案例使用经典的MNIST手写数字数据集,通过Keras构建全连接神经网络,实现0-9数字的分类识别。文章将包含: 关键概念图解完整实现代码训练过程可视化模型效果深度分析环境准备 import numpy as np impo…...
SkyWalking 10.1.0 实战:从零构建全链路监控,解锁微服务性能优化新境界
文章目录 前言一、集成SkyWalking二、SkyWalking使用三、SkyWalking性能剖析四、SkyWalking 告警推送4.1 配置告警规则4.2 配置告警通知地址4.3 下发告警信息4.4 测试告警4.5 慢SQL查询 总结 前言 在传统监控系统中,我们通过进程监控和日志分析来发现系统问题&…...
计算机毕业设计——Springboot的旅游管理
🎉**欢迎来到琛哥的技术世界!**🎉 📘 博主小档案: 琛哥,一名来自世界500强的资深程序猿,毕业于国内知名985高校。 🔧 技术专长: 琛哥在深度学习任务中展现出卓越的能力&a…...
【通俗易懂说模型】反向传播(附多元分类与Softmax函数)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀深度学习_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …...
Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统
Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统 需求 在实际生成操作过程中,一般会遇到物理服务器存在多块盘的情况。 安装过程中,磁盘的标签是随机分配的,并不是空间较小的盘,就会使用较小的磁盘标签 而需求往往需要…...
128,【1】buuctf [极客大挑战 2019]PHP
进入靶场 提示了备份文件 抓包,扫描 扫描出了两个有反应的 访问index.php没反应,但www.zip成功下载了文件 index.php里得到如下有用信息 <?phpinclude class.php;$select $_GET[select];$resunserialize($select);?> 所以我们要通过GET 方…...
3.3 学习UVM中的uvm_driver 类分为几步?
文章目录 前言1. 定义2. 核心功能3. 适用场景4. 使用方法5. 完整代码示例5.1 事务类定义5.2 Driver 类定义5.3 Sequencer 类定义5.4 测试平台 6. 代码说明7. 总结 前言 以下是关于 UVM 中 uvm_driver 的详细解释、核心功能、适用场景、使用方法以及一个完整的代码示例ÿ…...
系统思考—双环学习
前几天,一个企业高管向我提到:“我们调整了N次方案,市场策略、团队激励、管理制度,能改的全改了,怎么还是不见起色?” 这让我想到典型的单环学习,简单来说就是:发现问题 → 采取行动…...
QTreeView和QTableView单元格添加超链接
QTreeView和QTableView单元格添加超链接的方法类似,本文仅以QTreeView为例。 在QTableView仿Excel表头排序和筛选中已经实现了超链接的添加,但是需要借助delegate,这里介绍一种更简单的方式,无需借助delegate。 一.效果 二.实现 QHTreeView.h #ifndef QHTREEVIEW_H #def…...
elastic search 的 highlight
Elasticsearch 的 highlight 功能用于在搜索结果中突出显示匹配的文本片段。这对于用户界面上的搜索结果展示非常有用,因为它可以帮助用户快速定位到他们搜索的关键词。 1. 基本用法 在 Elasticsearch 中,highlight 功能通常在查询中使用,并…...
【MySQL篇】行格式详解
MySQL行格式详解 文章目录 MySQL行格式详解🎉 什么是行格式🐱👤 如何查看行格式🐱🚀 InnoDB 行格式有哪些?🐱🏍 Compact 行格式🚩 额外信息🚀 变长字段…...
嵌入式知识点总结 操作系统 专题提升(五)-内存
针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。 目录 1.在1G内存的计算机能否malloc(1.2G)?为什么? 2.malloc能申请多大的空间? 3.内存管理有哪几种方式? 4.什…...
动手学深度学习---深层神经网络
目录 一、神经网络1.1、模型训练1.2、损失函数1.2.1、分类:hinge loss/合页损失/支持向量机损失1.2.2、分类:交叉熵损失(softmax分类器)1.2.2.1 二分类交叉熵损失1.2.2.2 多分类交叉熵损失 1.2.3、回归:误差平方和(SSE)…...
第9章 城市基础设施更新工程 9.1 道路改造施工
9.1 道路改造施工 9.1.1 道路改造施工内容 沥青、水泥混凝土、砌块路面及人行步道、绿化照明、附属设施、交通标志。沥青路面材料的再生利用。 9.1.2 道路改造施工技术 1.沥青路面病害及微表处理 1.病害处理 裂缝处理 10mm以内 专用灌缝材料、热沥青灌缝、缝内潮湿时采用…...
