C语言指针:指针类型、void*指针、const修饰及传址调用
文章目录一、指针类型的意义1. 指针的解引用2.指针的运算(1) 指针-整数(2) 指针-指针(3) 指针的关系运算二、void*类型的指针三、const修饰的指针1.const修饰变量2.const修饰指针变量四、指针在函数中的使用1.函数的传值调用2.函数的传址调用一、指针类型的意义●既然指针变量的大小和类型无关只要是指针变量在同一平台下大小都是一样的那为什么还要有各种各样的指针类型呢?我们通过下面的例子来理解指针类型的意义。1. 指针的解引用对比下面两段代码在调试时观察内存及变量值的变化。#includestdio.h//代码1intmain(){intn0x11223344;int*pn;*p0;return0;}在代码1中通过逐过程(F10)调试由上图可知系统为整型变量n申请了4个字节的空间存放值0x11223344整型变量n的地址0x010FFAAC存放在了指针变量p中通过对指针p解引用将变量n的值赋为0由上图可知内存中原先4个字节存储的0x11223344也全部变为0了。#includestdio.h//代码2intmain(){intn0x11223344;char*p(char*)n;*p0;return0;}在代码2中还是同样的整型变量nn中存储的还是0x11223344这个值通过逐语句(F10)调试起来我们发现变量n的地址和代码1中的地址不一样虽然是同样的变量同样的值但是当vs编译器再次调试起来的时候系统会重新随机为变量n分配内存空间内存空间的地址也就不一样。随着程序运行结束这块空间会释放还给操作系统。待下一次程序运行时会重新为变量分配空间。但是这里将变量n的地址存储在了char*类型的指针变量中而变量n的地址又是一个int*类型的指针所以这里就将n的地址强制类型转换为了char*的指针再对指针p解引用将n的值赋为0发现只有n的第一个字节被改为了0其他三个字节的值没变。这跟代码1中的不一样代码1中是将n的4个字节的值全部改为了0。●所以这里得到一个结论指针的类型决定了对指针解引时有多大的权限(一次能访问几个字节)。像 char* 的指针解引用就只能访问一个字节而 int* 的指针解引用会访问四个字节。2.指针的运算(1) 指针±整数先看一段代码#includestdio.hintmain(){intn10;char*pc(char*)n;int*pin;printf(n %p\n,n);printf(pc %p\n,pc);printf(pc1 %p\n,pc1);printf(pi %p\n,pi);printf(pi1 %p\n,pi1);return0;}程序运行结果由上图可以看出char* 类型的指针变量1跳过1个字节int*类型的指针变量1跳过了4个字节。这就是指针变量的类型差异带来的变化。指针加1是加了一个指针所指向对象类型的大小(单位字节)而不是地址直接加一个1。所以指针加上一个整数表示指针加上这个整数乘以指针所指向对象类型的大小即指针整数*sizeof(类型)。而指针减去一个整数也是一样的道理即指针-整数*sizeof(类型)。结论: 指针的类型决定了指针向前或者向后走一步有多大(距离)。需要注意的是在数组中指针±整数可能会出现越界访问的问题。(2) 指针-指针指针与指针之间不适合做加法运算因为地址加地址没有意义但是指针减指针就不一样了指针减指针得到的是两个指针之间的元素个数但前提是这两个指针一定要指向同一个数组#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,0};int*p1arr[0];int*p2arr[9];printf(%d\n,p2-p1);return0;}程序运行结果(3) 指针的关系运算这里只举一个指针之间比较大小的例子后面会遇到很多指针的关系运算。#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};int*parr[0];intszsizeof(arr)/sizeof(arr[0]);while(parrsz)//指针大小的比较{printf(%d ,*p);p;}return0;}程序运行的结果二、void*类型的指针在指针类型中有一种特殊类型的指针叫void *类型可以理解为无具体类型的指针(或者叫泛型指针)这种类型的指针可以用来接受任意类型的指针(地址)。但是也有局限性void*类型的指针不能直接进行指针±整数和解引用的运算。例如#includestdio.hintmain(){intn10;int*pin;char*pcn;return0;}在上面的代码中创建了一个整型变量n那它的地址就要用 int* 类型的指针变量来存储上面指针变量pi是int*类型的用来存储变量n的地址没有问题但是pc是char*类型的指针变量用来存储整型变量n的地址编译器就会报警告因为类型不兼容。如果使用 void* 类型的指针变量来接收n的地址就不会出现上面的警告#includestdio.hintmain(){intn10;int*pin;void*pn;return0;}但是对 void* 类型的指针解引用编译器就会直接报错#includestdio.hintmain(){intn10;int*pin;void*pn;*p0;return0;}可以看到上面是在vs2022编译器中运行的结果void*类型的指针可以接收不同类型的地址但是无法直接对其进行解引用。那么void*类型的指针到底有什么用呢?一般void*类型的指针是使用在函数参数的部分用来接收不同类型数据的地址这样的设计可以实现泛型编程的效果。使得一个函数用来处理多种类型的数据后面还会深入讲解这部分的知识。三、const修饰的指针1.const修饰变量变量是可以修改的如果把变量的地址交给一个指针变量通过指针变量的解引用可以修改这个变量。但是如果我们希望给一个变量加上一些限制不能被修改那要怎么做呢?这就要使用const来修饰变量#includestdio.hintmain(){intm0;m10;//m可以被修改constintn0;n20;//n不可以被修改return0;}上面的代码运行后会报错由上图可知变量n被const修饰n就不能被修改了n本质上是变量只不过被const修饰后在语法上就加了限制只要我们在代码中直接对n进行修改就不符合语法规则就会报错致使没法修改n。那有没有其他办法可以修改被const修饰的变量的值呢如果不直接通过n去赋值而通过n的地址去修改n的值就可以做到。这样做是在打破语法规则。#includestdio.hintmain(){constintn0;printf(n %d\n,n);int*pn;*p10;printf(n %d\n,n);return0;}程序运行的结果可以看到通过这样的方法确实能把n的值改掉我们知道const修饰n就是为了让n的值不被修改那如果p拿到n的地址就能修改n这样就打破了const的限制这是不合理的所以应该让p即使拿到n的地址也不能修改n。看下面2.const修饰指针变量const修饰指针变量可以放在*的左边也可以放在*的右边但是意义不一样int*p;//没有const修饰constint*p;//const放在*的左边做修饰int*constp;//const放在*的右边做修饰那const放在*号左边或是右边具体的作用是什么通过下面四段代码来具体学习#includestdio.h//代码1无const修饰的情况intmain(){intn10;intm20;int*pn;*p0;pm;return0;}由上图的运行结果可知运行成功这可以知道在没有对变量进行const修饰时无论是对指针p解引用还是改变指针变量p中存储的地址都没有问题。#includestdio.h//代码2const放在*的左边intmain(){intn10;intm20;constint*pn;*p0;pm;return0;}由上图代码2运行的结果报错出错的是*p 0这条语句而p m这条语句没有问题。#includestdio.h//代码3const放在*的右边intmain(){intn10;intm20;int*constpn;*p0;pm;return0;}由上图代码3运行的结果报错出错的是p m这条语句而*p 0这条语句没有问题。#includestdio.h//代码4*的左右两边都有constintmain(){intn10;intm20;intconst*constpn;*p0;pm;return0;}由上图可知代码4中在*的左右两边都加上const修饰的后程序运行的结果报错出错的是 p m 和 *p 0 这两条语句。综合上面的情况const修饰指针变量p的时候●const如果放在*的左边修饰的是指针变量p所指向的内容表示指针变量p所指向的内存单元里面的内容不能修改但是指针变量p是可修改的。●const如果放在*的右边修饰的是指针变量p所以指针变量p不可修改但指针变量p所指向的内容是可修改的。●const如果既放在*的左边又放在*的右边那就既修饰指针变量p指向的内容也修饰指针变量p指针变量p所指向的内容和指针变量p都不能被修改。再补充一点const放在*的左边时无论是放在类型的前面还是放在类型的后面都是等价的。四、指针在函数中的使用1.函数的传值调用现在写一个swap函数用来交换两个整型变量的值一般我们会想到的方法是#includestdio.hvoidswap1(intx,inty){inttmpx;xy;ytmp;}intmain(){inta10;intb20;printf(交换前a%d b%d\n,a,b);swap1(a,b);printf(交换后a%d b%d\n,a,b);return0;}运行结果通过上面的代码及运行结果发现a和b的值并没有交换这是为什么呢我们通过逐语句(F11)调试来看我们发现在main函数内部创建了变量a和ba的地址是0x005cfe6cb的地址是0x005cfe60在调用swap1函数时将a和b传递给了swap1函数在swap1函数内部创建了形参x和y接收a和b的值但是x的地址是0x005cfd88y的地址是0x005cfd8cx和y确实接收到了a和b的值不过x的地址和a的地址不一样y的地址和b的地址也不一样相当于x和y是独立的空间那么在swap1函数内部交换x和y的值自然不会影响a和b当swap1函数调用结束后回到main函数a和b的值就没有交换。swap1函数在使用的时候是把实参a、b的值赋给了形参x、y这种调用函数的方式叫做传值调用。结论:函数的传值调用是直接将实参的值传递给形参实参传递给形参的时候形参会单独创建一份临时空间来接收实参即形参此时是实参的一份临时拷贝对形参的修改不会影响实参。2.函数的传址调用对于上面通过swap1函数交换两个变量的值如果函数是传值调用的话形参和实参之间就没有建立真正的联系。不能够交换两个变量的值那怎么办呢我们现在要解决的就是当调用swap函数的时候swap函数内部操作的就是main函数中的a和b直接将a和b的值交换。那么这里就可以使用指针在main函数中将a和b的地址传递给swap函数swap函数里边通过地址间接的操作main函数中的a和b就可以达到交换的效果了。#includestdio.hvoidswap2(int*px,int*py){inttmp*px;*px*py;*pytmp;}intmain(){inta10;intb20;printf(交换前a%d b%d\n,a,b);swap2(a,b);printf(交换后a%d b%d\n,a,b);return0;}运行结果由上图可看出通过调用swap2函数成功的将a和b的值交换了。通过将变量的地址(指针)传递给函数让函数和函数外边的变量建立起了联系也就是函数内部可以直接操作函数外部的变量。像这种将变量的地址传递给函数的方式叫做传址调用。结论函数的传址调用是把函数外部创建变量的地址传递给函数参数的一种调用函数的方式。所以在创建和调用函数时如果只是需要主调函数中的变量值来实现计算就可以采用传值调用。如果想要在函数内部修改主调函数中的变量值就需要传址调用。

相关新闻

如何用Containerlab快速搭建企业级网络实验室:容器化网络测试的终极指南

如何用Containerlab快速搭建企业级网络实验室:容器化网络测试的终极指南

如何用Containerlab快速搭建企业级网络实验室:容器化网络测试的终极指南 【免费下载链接】containerlab container-based networking labs 项目地址: https://gitcode.com/gh_mirrors/co/containerlab 还在为搭建网络测试环境而头疼吗?传统方式需…

2026/7/5 21:18:33 阅读更多 →
Primer设计系统架构现代化升级策略:从技术债务清理到性能收益的完整迁移路线图

Primer设计系统架构现代化升级策略:从技术债务清理到性能收益的完整迁移路线图

Primer设计系统架构现代化升级策略:从技术债务清理到性能收益的完整迁移路线图 【免费下载链接】design Primer Design Guidelines 项目地址: https://gitcode.com/gh_mirrors/des/design 面对日益复杂的UI组件生态系统,Primer设计系统的版本升级…

2026/7/5 21:18:33 阅读更多 →
Vite 依赖预构建:开发启动快,也要看缓存失效

Vite 依赖预构建:开发启动快,也要看缓存失效

Vite 依赖预构建:开发启动快,也要看缓存失效 一、预构建解决的是依赖成本 Vite 开发环境启动快,很大一部分来自依赖预构建。它会把 CommonJS 或复杂依赖转换成更适合浏览器加载的 ESM,并缓存起来。平时它很安静,但一旦…

2026/7/5 21:16:33 阅读更多 →

最新新闻

YOLO11中的DFL损失函数:提升目标检测定位精度的关键技术

YOLO11中的DFL损失函数:提升目标检测定位精度的关键技术

1. 项目概述在目标检测领域,YOLO系列算法一直以其高效的检测性能著称。作为最新版本,YOLO11在损失函数设计上进行了重大改进,其中Distribution Focal Loss(DFL)的引入尤为关键。这个损失函数专门针对边界框回归任务设计…

2026/7/5 22:50:57 阅读更多 →
d3d8to9终极指南:让经典Direct3D 8游戏在现代Windows系统上完美运行

d3d8to9终极指南:让经典Direct3D 8游戏在现代Windows系统上完美运行

d3d8to9终极指南:让经典Direct3D 8游戏在现代Windows系统上完美运行 【免费下载链接】d3d8to9 A D3D8 pseudo-driver which converts API calls and bytecode shaders to equivalent D3D9 ones. 项目地址: https://gitcode.com/gh_mirrors/d3/d3d8to9 d3d8to…

2026/7/5 22:48:56 阅读更多 →
RGB-D 抓取检测实战:YOLOv8 + FastSAM 3D 分割,点云噪声降低 85%

RGB-D 抓取检测实战:YOLOv8 + FastSAM 3D 分割,点云噪声降低 85%

RGB-D 抓取检测实战:YOLOv8 FastSAM 3D 分割与点云降噪全流程解析当机械臂需要在杂乱环境中精准抓取物体时,传统基于单一模态的视觉系统常面临光照敏感、纹理依赖等问题。本文将揭示如何通过YOLOv8与FastSAM的协同工作流,实现从2D检测到3D分…

2026/7/5 22:48:56 阅读更多 →
SwiftFormer:移动端视觉任务的Transformer高效解决方案

SwiftFormer:移动端视觉任务的Transformer高效解决方案

1. SwiftFormer:移动端视觉任务的Transformer革新方案在移动端视觉任务领域,我们正面临一个关键转折点。传统CNN架构虽然计算友好但性能逐渐触及天花板,而Transformer架构虽然性能卓越却受限于计算复杂度难以在资源受限设备上落地。SwiftForm…

2026/7/5 22:42:55 阅读更多 →
AI智能体开发实战:从Coze到Dify,掌握未来高薪岗位核心技能

AI智能体开发实战:从Coze到Dify,掌握未来高薪岗位核心技能

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 这次我们来看一个面向2026年AI训练师和智能体工程师岗位的实战公开课,核心是掌握两大主流平台:扣子(Coze)和Di…

2026/7/5 22:40:55 阅读更多 →
PHP与Java跨语言AES加解密兼容性实现与实战指南

PHP与Java跨语言AES加解密兼容性实现与实战指南

1. 项目概述与核心价值最近在对接一个第三方支付平台的回调接口时,遇到了一个典型的老问题:对方使用Java服务,采用AES-128-CBC模式、PKCS5Padding填充方式对数据进行加密,然后进行Base64编码后传输。而我的后端服务是用PHP7写的。…

2026/7/5 22:38:55 阅读更多 →

日新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻