C语言基础(八)指针相关内容
C语言指针引言指针是C语言的核心机制之一也是其区别于多数高级语言的关键特性。指针本质上是对内存地址的抽象它提供了直接操作内存的能力使得C语言能够实现高效的系统编程、硬件控制和动态内存管理。本文基于C语言标准系统阐述指针的语法、语义及典型应用场景涵盖从基础定义到函数指针的完整知识体系。一、指针基础1.1 内存、地址与指针的概念计算机内存以字节为单位进行编址每个字节对应一个唯一的数值标识即地址。程序运行时变量被分配在内存的特定位置其起始地址称为该变量的首地址。指针即地址本身而指针变量是用于存储地址的变量其自身也占用内存空间在64位系统中通常为8字节32位系统中为4字节。1.2 指针变量的定义指针变量的定义语法如下基类型*变量名;基类型指明该指针所指向内存单元中存储的数据类型可以是基本数据类型int、char、float、double、构造数据类型或void。*类型说明符表示定义的是指针变量。变量名遵循标识符命名规则通常以p或ptr为前缀以增强可读性。示例int*pint;// 指向int型数据的指针char*pch;// 指向char型数据的指针double*pd;// 指向double型数据的指针指针变量中存储的是其所指向数据的首地址。1.3 指针变量的初始化与赋值指针变量必须在使用前被明确赋值否则其值为随机野指针可能导致不可预料的错误。推荐初始化为NULL即0或已有变量的地址。intnum10;int*pNULL;// 初始化为空指针pnum;// 赋值获取num的地址野指针是指未初始化、已释放或指向无效内存的指针。避免野指针的核心原则定义时初始化为NULL仅将指针指向合法且生命周期可控的变量释放动态内存后将指针置为NULL。1.4 指针运算符取地址运算符获取变量的首地址。只能作用于变量不能用于常量或表达式。间接访问运算符*解引用访问指针所指向的内存单元中的数据。解引用所访问的字节数由指针的基类型决定例如char *解引用访问1字节int *访问4字节。inta5;int*paa;*pa10;// 等价于 a 10;1.5 指针的算术运算指针支持有限的算术运算主要包括自增、自减--、加/减整数pn、p-n以及指针相减仅当指向同一数组时有效。运算的步长由基类型大小决定即p1的地址偏移量为sizeof(基类型)字节。intarr[5]{1,2,3,4,5};int*parr;// 指向arr[0]p;// 现在指向arr[1]地址增加4字节int为4字节指针相减的结果为元素个数差类型为ptrdiff_t有符号整数。二、指针与一维数组2.1 数组名的指针语义在C语言中数组名在绝大多数表达式中被解释为数组首元素的地址即arr等价于arr[0]其类型为基类型 *。例如inta[10];int*pa;// 合法a为int*类型2.2 通过指针访问数组元素利用指针算术和间接访问可以遍历数组for(inti0;i10;i){*(pi)i;// 等价于 a[i] i;}a[i]本质上被编译器转换为*(ai)故指针和数组下标在访问层面等效。2.3 数组作为函数参数当数组作为函数参数传递时实际传递的是首元素的地址形参退化为指针。因此以下两种函数原型等价voidprint_array(intarr[],intlen);voidprint_array(int*arr,intlen);在被调函数中sizeof(arr)获得的是指针本身的大小8字节而非数组总字节数故必须显式传递数组长度。三、指针与一维字符型数组字符型数组C风格字符串以\0作为结束标志。数组名同样退化为字符指针指向字符串首字符。charstr[32]hello;char*pstr;// 等价于 char *p str[0];遍历字符串可通过指针递增直至遇到\0intmystrlen(constchar*s){intlen0;while(*s)len;returnlen;}由于字符串自带终止符函数传参时无需额外传递长度仅需传入指针即可。四、数组指针指向数组的指针数组指针是指向整个数组的指针其定义语法为基类型(*指针名)[数组长度];例如int (*p)[5]定义了一个指针可以指向具有5个int元素的数组。它与普通指针的关键区别在于步长p1将偏移整个数组的大小5 * sizeof(int)。inta[5]{1,2,3,4,5};int(*pa)[5]a;// pa指向数组整体注意以下区别a数组名类型为int *指向首元素a类型为int (*)[5]指向整个数组。数组指针通常用于操作二维数组的行。五、指针与二维数组5.1 二维数组名的指针类型二维数组int a[2][3]的数组名a在表达式中被解释为首元素即第一行一维数组的地址其类型为int (*)[3]即一个数组指针步长为3 * sizeof(int)。5.2 指针访问二维数组元素借助数组指针和偏移可以访问任意元素inta[2][3]{{1,2,3},{4,5,6}};int(*p)[3]a;// p指向第一行intval*(*(p1)2);// 访问a[1][2]值为6通用公式a[i][j]等价于*(*(ai) j)。5.3 二维数组作为函数参数形参可声明为二维数组形式行数可省略列数不可省略或等价的数组指针形式voidprint_2D(intarr[][3],introws);voidprint_2D(int(*arr)[3],introws);// 完全等价调用时传递数组名及行数即可。六、指针数组保存指针的数组指针数组本质是数组其元素均为指针类型。定义语法基类型*数组名[元素个数];例如char *str_arr[5]定义了一个包含5个字符指针的数组每个指针可指向一个字符串常量或字符数组。初始化char*p[3]{hello,world,how};此时p[0]存储字符串常量hello的首地址p[1]存储world的首地址依此类推。指针数组常用于处理多个字符串每个字符串的长度可不同且各元素可独立重新指向。指针数组与二维字符数组的区别特性二维字符数组指针数组存储内容字符串数据本身占全部空间字符串的地址内存分配固定行列浪费或不足灵活各指针独立指向修改内容可修改字符串内容可改变指针指向但字符串常量不可修改典型用途存储固定数量、固定长度的字符串操作多个动态字符串或常量串七、二级指针指向指针的指针二级指针是存储指针变量的地址的指针。定义语法基类型**变量名;例如int **pp表示指向int *类型变量的指针。7.1 主要应用场景在函数中修改主调函数的指针变量若需在被调函数中改变主调函数中指针的指向需传递该指针的地址形参用二级指针接收。voidset_pointer(int**pp,int*new_val){*ppnew_val;// 修改主调中的指针}调用set_pointer(p, some_var);指针数组的数组名char *p_arr[3]在表达式中退化为char **类型可传递给期望二级指针的函数用于遍历或操作指针数组。voidprint_strs(char**arr,intn){for(inti0;in;i){puts(arr[i]);// arr[i]为char*}}八、指针函数返回指针的函数指针函数是指返回值为指针类型的函数。定义时需将*与函数名结合基类型*函数名(形参表);例如char *strcpy(char *dest, const char *src);返回char *。8.1 合法返回的指针类型静态变量或全局变量的地址具有静态生命周期程序结束时才释放。字符串常量地址位于只读数据段生命周期贯穿程序。通过参数传入的地址可直接返回该地址如strcpy返回目标地址。堆区动态分配的内存通过malloc等前提是未释放。8.2 禁止返回局部变量的地址局部变量包括局部数组在函数返回后其栈帧被销毁返回其地址将导致悬垂指针访问未定义行为。int*bad_func(){intx10;returnx;// 错误}九、函数指针指向函数的指针9.1 定义与赋值函数名代表函数的入口地址。函数指针的定义需指定返回类型和参数类型列表返回值类型(*指针名)(参数类型列表);例如int (*pfun)(int, int);定义了一个可指向返回int、接受两个int参数的函数的指针。赋值intadd(inta,intb){returnab;}pfunadd;// 或 pfun add;9.2 调用通过函数指针调用函数可直接使用指针名或解引用加实参intresultpfun(3,4);// 等价于 add(3,4)9.3 回调函数回调函数是将函数指针作为参数传递给另一函数使得被调函数能够在适当时候调用该函数。回调机制广泛应用于事件驱动、排序算法如qsort的比较函数和框架设计中其核心优势在于解耦调用者与具体实现提高代码复用性和灵活性。示例简化版排序比较intcompare_int(constvoid*a,constvoid*b){return(*(int*)a-*(int*)b);}voidsort(void*base,intn,intsize,int(*cmp)(constvoid*,constvoid*));调用时传递compare_int作为回调。十、总结指针是C语言的精髓其核心思想可归纳为指针即地址指针变量存储地址通过基类型决定访问宽度。数组名在表达式中退化为指针函数参数传递数组时实际传递指针。数组指针、指针数组、二级指针各具用途分别用于指向数组整体、存储指针集合、修改指针变量。指针函数与函数指针需严格区分前者返回指针后者指向函数。指针与数组、字符串、函数、动态内存管理紧密关联掌握指针是深入理解C语言内存模型和系统编程的基础。正确使用指针能够显著提升程序效率但不当使用如野指针、越界访问将导致严重错误。开发者应始终遵循“初始化、检查边界、避免悬垂”的原则并善用const修饰符增强安全性与可读性。

相关新闻

2026学术写作AI论文写作工具全榜单:7款实测,谁是论文党的真效率工具?

2026学术写作AI论文写作工具全榜单:7款实测,谁是论文党的真效率工具?

在 AI 持续渗透学术创作流程的 2026 年,学术写作工具的能力边界已经不再局限于内容生成,而是逐步延伸到结构梳理、格式规范、可视化表达、语言润色与答辩整理等多个关键环节。对于本科生、研究生以及需要持续输出论文与课题材料的研究者而言,…

2026/9/23 19:07:39 阅读更多 →
ai免费写论文好用吗?实测3款AI论文软件,结果有高有低!

ai免费写论文好用吗?实测3款AI论文软件,结果有高有低!

宝子们,有没有人跟我一样,一提到写论文就头皮发麻? 熬夜熬到凌晨三点,结果导师一句"逻辑不通"打回重写,谁懂啊! 说真的,我之前也以为 AI 写论文是智商税,直到自己踩了无数…

2026/9/22 10:59:40 阅读更多 →
从MSSQL到域控:HTB Escape靶机渗透实战与AD域横向移动详解

从MSSQL到域控:HTB Escape靶机渗透实战与AD域横向移动详解

1. 项目概述与核心挑战最近在HackTheBox平台上挑战了一个名为“Escape”的Windows靶机,评级为Medium。这个靶机给我留下了深刻的印象,它不像那些简单的“拿shell、提权”两步走机器,而是构建了一个相当贴近真实企业环境的场景。整个渗透路径涉…

2026/9/24 13:17:12 阅读更多 →

最新新闻

把相亲当成系统优化:程序员的理性婚恋决策框架

把相亲当成系统优化:程序员的理性婚恋决策框架

我做了十年程序员,被家里安排相亲的次数也不少。最初我特别反感这种场合,总觉得像把人放到货架上比参数。直到有次我把“你到底想找什么样的人”这个问题认真写下来,按项目需求文档的方式拆了一遍,才发现自己其实从来没想清楚过。…

2026/9/26 7:50:00 阅读更多 →
开源AI编程工具链:构建可审计、可调试的工业级人机协同工作流

开源AI编程工具链:构建可审计、可调试的工业级人机协同工作流

1. 这不是“用AI写代码”的速成课,而是十年老码农在开源工具堆里摸爬后的清醒笔记“AI编程”这个词最近被刷屏刷得有点变形——有人当它是自动补全的升级版,有人把它当成能替代工程师的黑箱,还有人直接拿它当简历镀金的新素材。但如果你真在G…

2026/9/26 7:50:00 阅读更多 →
muduo EventLoop核心实现:从Reactor模式到跨线程调度的深入剖析

muduo EventLoop核心实现:从Reactor模式到跨线程调度的深入剖析

很多人学muduo,是从仿写开始的;很多人仿写muduo,最后卡死在EventLoop上。我不算天才型选手,EventLoop这个模块前前后后写了三版,第一版连基本的事件分发都跑不起来,第二版能跑但跨线程调用延迟严重&#xf…

2026/9/26 7:50:00 阅读更多 →
Java热部署合规方案:JRebel替代与DevTools优化

Java热部署合规方案:JRebel替代与DevTools优化

我不能提供任何软件激活码、破解工具或绕过正版授权机制的内容。 JRebel 是由 Perforce 公司开发的商业 Java 热部署工具,其合法使用必须通过官方渠道购买许可证。根据中国《计算机软件保护条例》及《中华人民共和国著作权法》,未经许可复制、分发、使用…

2026/9/26 7:49:59 阅读更多 →
SDR++无线电接收完整入门指南:5步从零调通FM、航空与卫星信号

SDR++无线电接收完整入门指南:5步从零调通FM、航空与卫星信号

SDR无线电接收完整入门指南:5步从零调通FM、航空与卫星信号 【免费下载链接】SDRPlusPlus Cross-Platform SDR Software 项目地址: https://gitcode.com/GitHub_Trending/sd/SDRPlusPlus 第一次打开 SDR,屏幕是一片花花绿绿的条纹,顶上…

2026/9/26 7:49:59 阅读更多 →
AI Agent技能安全实战:OpenClaw Skills风险拆解与五层防护

AI Agent技能安全实战:OpenClaw Skills风险拆解与五层防护

1. 从一次技能调用失控说起:AI Agent 的安全边界到底在哪AI Agent 这两年被讨论得很多,从“帮我订机票”到“自动写代码并提交 PR”,能力边界不断外扩。但真正让一线开发者夜里睡不踏实的,往往不是模型答得对不对,而是…

2026/9/26 7:48:59 阅读更多 →

日新闻

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、…

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →