本章概述思维导图:

C语言指针

指针是C语言中最强大但也最容易混淆的特性之一。它提供了直接操作内存地址的能力,使得C语言具有高效性和灵活性。下面我将详细介绍C语言指针的各个方面。

指针定义

指针的本质:指针是一个变量,其值为另一个变量的内存地址;可以理解为:(普通变量:存储数据值的变量)、(指针变量:存储内存地址的变量);

指针变量定义格式:

指针查询数据和修改数据格式:

指针注意事项:

1.数据类型 :要跟指向变量的类型保持一致;

2.定义中的' * ':这是标记,不是解引用的含义;

3.变量名和指针名都是自己起的名字;

4.指针指向变量名时,指向的是内存地址,并不是数据,所以要用取地址符&;

5.定义中的‘ * ’是标记,查询数据和存储数据中的‘ * ’是解引用,二者并不一样;

代码示例:

#include <stdio.h>
int main()
{int num1=100;int *p=&num1;printf("num1=%d\n",num1);printf("指针指向的内存地址上的值为:%d\n",*p);return 0;
}//代码运行结果:
num1=100
指针指向的内存地址上的值为:100

代码讲解:首先定义一个整型变量num1并赋值为100,然后声明一个整型指针p并用&运算符将num1的地址赋给它(此时p存储的是num1的内存地址),接着通过printf直接输出num1的值,再通过解引用指针*p(即访问p指向的内存地址中的值)输出相同结果,最终证明指针p确实指向了num1的内存空间。

指针使用细节:

1.指针变量的名字不能重复定义;

2.指针变量的数据类型要跟指向变量的类型保持一致;

3.指针变量占用的大小,跟数据类型无关,跟操作系统有关;(32位操作系统:占4个字节,64位操作系统占8个字节);

4.给指针变量赋值时,不能把一个数值赋值给指针变量;

指针的作用

指针的作用1:操作其它函数中的变量

指针的一个重要作用是在不同函数之间直接操作变量,避免全局变量的使用,同时提高代码的灵活性和效率。

代码示例(利用指针在不同函数交换变量):

#include <stdio.h>
void huan(int *p1,int *p2);//函数封装:交换变量
int main()
{int num1=100;int num2=1000;printf("初始值为:num1=%d\tnum2=%d\n",num1,num2);huan(&num1,&num2);printf("交换后值为:num1=%d\tnum2=%d\n",num1,num2);return 0;
}
void huan(int *p1,int *p2)//函数封装:交换变量
{int temp=0;temp=*p1;*p1=*p2;*p2=temp;
}//代码运行结果:
初始值为:num1=100	num2=1000
交换后值为:num1=1000	num2=100

代码讲解:在 main 函数中定义两个变量 num1 和 num2,调用 huan 函数时传递它们的地址(&num1 和 &num2),huan 函数通过指针参数(int *p1 和 int *p2)接收地址,并通过解引用(*p1 和 *p2)直接修改原始变量的值,最终完成交换。

关键点在于传递地址而非值,使得函数能操作外部变量,避免了值传递的副本限制,体现了指针在间接访问和修改数据时的核心作用。


指针的作用2:函数返回多个值

在C语言中,函数通常只能通过返回值传递一个结果,但通过指针参数,可以绕过这一限制,实现返回多个值的效果。

代码示例(在数组中找出最大值和最小值):

#include <stdio.h>
void out_max_min(int arr[],int len,int *p1,int *p2);//函数封装:找最大值和最小值
int main()
{int arr[]={88,54,69,75,25};int len=sizeof(arr)/sizeof(int);for(int i=0;i<len;i++){printf("%d\t",arr[i]);}putchar('\n');int max=0,min=0;out_max_min(arr,len,&max,&min);printf("数据中最大值为%d\t最小值为:%d\n",max,min);}
void out_max_min(int arr[],int len,int *p1,int *p2)//函数封装:找最大值和最小值
{*p1=arr[0];*p2=arr[0];for(int i=0;i<len;i++){if(*p1<arr[i])//找最大值{*p1=arr[i];}if(*p2>arr[i])//找最小值{*p2=arr[i];}}
}//代码运行结果:
88	54	69	75	25	
数据中最大值为88	最小值为:25

代码讲解:在 main() 函数中定义数组并计算长度,打印数组后调用 out_max_min() 函数,传入数组、长度以及 max 和 min 的地址;该函数先将指针指向的值初始化为数组首元素(避免初始化为 0 导致全负数数组出错),然后遍历数组,通过指针更新最大值和最小值,最终返回结果到 main() 函数并打印。


指针的作用3:函数的结果和计算状态分开

在C语言中,指针的核心价值之一是实现“计算逻辑”与“结果存储”的分离,使函数能够专注于核心任务(如数据处理),而将结果的去向交由调用者控制。

代码示例(定义函数,将两数相除,获取他们的余数。返回值为这段算数是否有意义):

#include <stdio.h>
int yu(int *p1,int *p2,int *p3);
int main()
{int num1,num2;int num3=0;printf("输入两个数智能获取余数\n");scanf("%d%d",&num1,&num2);int flag=yu(&num1,&num2,&num3);if(flag){printf("式子无意义");}else{printf("余数为:%d",num3);}return 0;
}
int yu(int *p1,int *p2,int *p3)//函数封装:将两数相处,获取余数。返回值为0这个式子有意义,返回值为1,这个式子无意义
{if(*p2 == 0){return 1;}*p3=*p1%*p2;return 0;
}//代码运行结果:
输入两个数智能获取余数
85
7
余数为:1

代码讲解:主函数中用户输入两个整数后,将它们的地址连同存储余数的变量地址一起传给yu()函数,函数内通过指针参数直接读取输入值并检查除数是否为零,若为零则返回错误标志1,否则计算余数并通过指针将结果写入主函数的变量中,最后主函数根据返回值判断输出余数或错误提示,这种设计既利用指针高效传递了计算结果,又通过返回值清晰区分了正常和异常情况。


指针作用4:方便操作数组和函数传参

指针操作数组的核心优势在于它能直接通过内存地址高效访问和修改元素,避免了数组下标计算的间接开销,同时支持动态内存分配(如用malloc创建可变大小的数组),且在函数间传递数组时只需传递首地址指针而非整个数组,极大节省了内存和时间开销,尤其适合处理大规模数据或多维数组等复杂结构,但需注意指针的边界控制以防止越界访问。

代码示例(在函数中使用指针对数组进行遍历):

#include <stdio.h>
void arr_bianli(int *p,int *p1);//函数封装:利用指针对数组遍历
int main()
{int arr1[]={1,2,3,4,5,6,7,8,9};int len=sizeof(arr1)/sizeof(int);arr_bianli(arr1,&len);return 0;
}
void arr_bianli(int *p,int *p1)//函数封装:利用指针对数组遍历
{for(int i=0;i<*p1;i++){printf("arr[%d]=%d\t",i,*(p+i));}putchar('\n');
}//代码运行结果:
arr[0]=1	arr[1]=2	arr[2]=3	arr[3]=4	arr[4]=5	arr[5]=6	arr[6]=7	arr[7]=8	arr[8]=9	

代码讲解:主函数中定义数组 arr1 并计算其长度 len,调用 arr_bianli() 时传递数组首地址(arr1)和长度指针(&len),函数内通过指针解引用获取长度(*p1)控制循环次数,并利用指针算术(*(p+i))访问每个元素并打印其下标和值,这种方式避免了数组拷贝,直接操作内存地址,既高效又清晰地展示了指针与数组的紧密关联。


指针的计算

指针的计算是C语言中操作内存地址的核心机制,它通过基于数据类型大小的地址偏移实现高效的数据访问和内存操作。

指针的定义:

指针中数据类型的作用:获取字节数据的个数;

步长:指针移动一次的字节个数

char:1个字节;        short:2个字节        int:4个字节        longlong:8个字节;

指针加法:指针往后移动了n步,总字节=n*sizeof(数据类型)=N个字节;

指针减法:指针往前移动了n步,总字节=n*sizeof(数据类型)=N个字节;

代码示例:

#include <stdio.h>
int main()
{//int类型指针步长int arr1[]={1,22,33,44};int *p1=arr1;printf("int类型指针移动2次多少字节:%d字节\narr1[2]=%d\n",2*sizeof(int),*(p1+2));//char类型指针步长char arr2[]="abcd";char *p2=arr2;printf("char类型指针移动2次多少字节:%d字节\narr2[2]=%c\n",2*sizeof(char),*(p2+2));return 0;
}//代码运行结果:
int类型指针移动2次多少字节:8字节
arr1[2]=33
char类型指针移动2次多少字节:2字节
arr2[2]=c

代码讲解:指针的加减运算会根据其指向的数据类型自动计算地址偏移量:当对指针进行 +n 或 -n 操作时,实际移动的字节数等于 n × sizeof(数据类型)(例如 int* 每次移动4字节,char* 每次移动1字节),因此 *(p + i) 能直接访问数组第i个元素(如 int* p 指向数组时,p+2 会跳过8字节访问 arr[2]),这种机制使得指针运算与数组索引天然对应,但需注意避免越界访问。

指针步长和指针变量占用大小的区别

指针步长和指针变量占用大小是两个完全不同的概念,前者决定指针移动时的地址偏移量,后者反映指针变量本身在内存中占用的空间。

指针步长:由指针指向的数据类型决定,计算公式为:步长 = sizeof(数据类型);

指针变量占用大小:指针变量本身在内存中占用的字节数。由操作系统和编译器决定(与指针类型无关),通常为:32位系统:4字节、64位系统:8字节;

C语言野指针

野指针(Wild Pointer)是指未初始化或已释放的指针变量,其指向的内存地址不可预测或无效。访问野指针会导致未定义行为(如程序崩溃、数据损坏)。

野指针的常见成因

1.未初始化的指针

代码示例:

#include <stdio.h>
int main()
{int *p;*p=10;printf("%d\n",*p);return 0;
}//代码运行结果:
段错误 (核心已转储)

代码讲解:未初始化,p的值是随机地址(野指针),危险!可能访问非法内存;


2. 指针越界访问

代码示例:

#include <stdio.h>
int main()
{int arr[3]={1,2,3};int *p=arr;p+=5;printf("%d\n",*p);return 0;
}//代码运行结果:
-912009440

C语言野指针总结

野指针的本质:指向不可控或无效内存的指针。

防范手段:

1. 初始化指针为 NULL

2. 释放内存后立即置空。

3. 确保指针操作在合法范围内。

C语言悬空指针

悬空指针是指指向已被释放或回收的内存地址的指针。此时指针仍保存着旧的内存地址,但该地址已无效,访问它会导致未定义行为(如程序崩溃或数据损坏)。

悬空指针的常见成因

1.内存被释放后未置空

代码示例:

#include <stdio.h>
#include <stdlib.h>
int main()
{int *p=malloc(sizeof(int));*p=10;free(p);*p=20;printf("%d\n",*p);return 0;
}//代码运行结果:
段错误

代码讲解:free已经释放内存了,此时p仍指向原地址,成为悬空指针,危险!访问已释放的内存


2.局部变量指针超出作用域

代码示例:

#include <stdio.h>
int *num(void);//函数封装:返回数据
int main()
{int *p=*num();printf("%d",*p);return 0;
}
int *num(void)//函数封装:返回数据
{int num1=10;return &num1;
}//代码运行结果:
段错误 (核心已转储)

代码讲解:函数num返回局部变量num1的地址,可是num1在函数结束后被销毁释放了。因此成为悬空指针,在主函数中*p是属于未定义行为;

C语言悬空指针总结

悬空指针的本质:指针与内存生命周期不同步。

防范手段:

1.释放内存后立即置空(p = NULL)。

2.不返回局部变量的地址。

3.使用动态内存分配(malloc)替代局部变量。


void类型的指针

void*(无类型指针)是一种通用指针类型,可以指向任意数据类型(如 intfloat、结构体等),但不能直接解引用(即不能通过 * 访问值),必须先转换为具体类型的指针。

代码示例:

#include <stdio.h>
int main()
{int num1=10;void *p=&num1;int *p1=(int*)p;printf("%d\n",*p1);return 0;
}//代码运行结果:
10

代码讲解:先定义一个整型变量 num1 并赋值为 10,再用 void* p 存储其地址(此时 p 仅保存地址信息,不关联具体类型),接着通过显式类型转换 (int*)p 将 void* 还原为 int* 指针 p1,最后通过 p1 解引用并打印 num1 的值(10),体现了 void* 作为通用指针需转换后才能操作数据的特性,同时强调了类型转换必须与实际数据类型匹配,否则会导致未定义行为。


制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!

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

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

相关文章

具身智能VLA困于“数据泥潭”,人类活动视频数据是否是“破局之钥”?

前言尽管当前的视觉-语言-动作&#xff08;VLA&#xff09;模型已展现出显著进展&#xff0c;但其在新场景和与复杂物体交互中的性能会显著下降&#xff0c;在遵循指令方面落后于像LLaVA 这样的大型多模态模型&#xff08;LMM&#xff09;。这种局限性源于现有VLA模型对存在固有…

CIO如何规划企业BI分析指标体系 —— 从经营出发到绩效管理

如果你是一家企业的CIO&#xff0c;要启动一个商业智能BI项目&#xff0c;负责规划整个项目的商业智能BI分析内容&#xff0c;你该如何入手准备&#xff1f;要有什么样的思路。如果是管理层、老板还不能清晰认识到商业智能BI的价值&#xff0c;也提不出很清晰的需求&#xff0c…

go学习笔记:panic是什么含义

anic 是 Go 语言中的一种运行时错误处理机制&#xff0c;用于处理程序中的异常情况。 基本含义 panic 会&#xff1a; 立即停止当前函数的执行 开始执行 defer 函数&#xff08;如果有的话&#xff09; 向上传播到调用栈&#xff0c;逐层执行 defer 如果到达 main 函数&am…

OpenLayers 入门指南【五】:Map 容器

文章目录 一、Map 对象核心参数 1. target 2. view 3. layers 4. controls 5. interactions 6. 其他重要参数 二、Map 对象常用方法 1. 图层管理 2. 控件管理 3. 交互管理 4. 视图与坐标操作 5. 事件监听 6. 覆盖物管理 7. 其他 三、总结 上一章节中我们通过修改OlMap.vue组件已…

关税战火中的技术方舟:新西兰证券交易所的破局之道 ——从15%关税冲击到跨塔斯曼结算联盟,解码下一代交易基础设施

一、今日焦点&#xff1a;全球关税震荡与新西兰的“技术自卫” 1. 特朗普关税大限落地&#xff0c;新西兰启动紧急游说 2025年8月1日&#xff0c;美国总统特朗普正式签署行政令&#xff0c;对贸易顺差国征收最低15%基准关税。新西兰贸易部长紧急声明&#xff1a;“将提出有力证…

windows内核研究(软件调试-软件断点)

软件调试软件断点调试的本质是什么&#xff1f;就是在被调试程序中触发异常&#xff0c;然后被调试程序就会向_DEBUG_OBJECT结构体添加调试事件&#xff0c;这里我们调试器就接管这个异常了&#xff08;调试的过程就是异常处理的过程&#xff09; 软件断点 在x64dbg中通过快捷键…

HarmonyOS】鸿蒙应用开发中常用的三方库介绍和使用示例

&#x1f31f; 鸿蒙应用开发常用三方库指南&#xff08;2025 最新版&#xff09;适用版本&#xff1a;HarmonyOS NEXT / API 12 参考来源&#xff1a;HarmonyOS 三方库中心 截止至 2025 年 8 月 1 日&#xff0c;本文整理了当前社区中下载量高、稳定性强、生态完善的热门三方库…

【通识】C Sharp

1. 使用 \p{名称}构造匹配Unicode常规类别&#xff08;该示例为Pd或“标点、短划线”类别&#xff09;和命名块&#xff08;IsGreek和IsBsicLatin命名块&#xff09; using System; using system.Text.RegularExpressions; public class Example {public static void main() {s…

国内首个开源SCA社区——OpenSCA开源社区

OpenSCA开源社区成果说明项目背景智能时代&#xff0c;软件定义一切。随着开发模式的敏捷化转型&#xff0c;开源代码在软件制品中的占比越来越大&#xff0c;开源软件已然成为软件供应链的重要组成部分。由于其特殊性&#xff0c;开源代码的引入增加了软件应用的风险面&#x…

超聚变:智能体时代,AI原生重构城企数智化基因

2025 世界人工智能大会&#xff08;WAIC&#xff09;世博展览馆内&#xff0c;超聚变展台前人头攒动&#xff0c;其展示的AI落地全栈解决方案及上百个AI应用场景吸引了众多参观者驻足观看。这是今年WAIC大会火爆的一角&#xff0c;更是当下AI应用爆发的一个缩影。当人工智能发展…

Traccar:开源GPS追踪系统的核心价值与技术全景

Traccar&#xff1a;开源GPS追踪系统的核心价值与技术全景 —— 从设备兼容到企业级定位管理的开源实践 一、项目定位&#xff1a;多场景定位管理的开源基石 Traccar是一个高扩展性的开源GPS追踪平台&#xff0c;支持全球超过200种通信协议与2000款GPS设备&#xff08;包括车…

编程与数学 03-002 计算机网络 20_计算机网络课程实验与实践

编程与数学 03-002 计算机网络 20_计算机网络课程实验与实践一、实验环境搭建&#xff08;一&#xff09;使用模拟器&#xff08;如Cisco Packet Tracer&#xff09;搭建网络实验环境&#xff08;二&#xff09;实验设备的配置与连接二、基础网络实验&#xff08;一&#xff09…

15个命令上手Linux!

1、id&#xff0c;显示当前登录系统的用户信息2、pwd&#xff0c;显示当前工作目录的绝对路径3、ls&#xff0c;显示当前目录下的内容&#xff08;ls -r&#xff1a;按反向顺序列出内容&#xff0c;ls -l&#xff1a;以详细列表形式显示&#xff09;4、cd&#xff0c;切换工作目…

MongoDB分片技术实现

MongoDB分片技术实现概述MongoDB分片&#xff08;Sharding&#xff09;是MongoDB的水平扩展解决方案&#xff0c;通过将数据分布到多个分片&#xff08;shard&#xff09;上来处理大数据量和高吞吐量的需求。MongoDB分片架构1. 分片集群组件# MongoDB分片集群架构 version: 3.8…

Python开发环境PyCharm下载与安装

python下载 python下载地址&#xff1a; Download Python | Python.org 上面的下载速度慢的话&#xff0c;用下面的地址下载&#xff08;window&#xff09;&#xff1a; https://download.csdn.net/download/liangmengbk/91580033 PyCharm下载 PyCharm下载地址&#xff1a…

汽车供应链PPAP自动化审核指南:如何用AI实现规则精准匹配与文件智能校验

在汽车行业质量管理的核心环节&#xff0c;PPAP&#xff08;生产件批准程序&#xff09;审核长期困扰着供应商与主机厂。 随着IATF 16949等标准持续升级、新能源零件复杂度激增&#xff0c;传统人工审核模式正面临系统性挑战。 行业数据显示&#xff0c;超过70%的SQE&#xf…

正则表达式在js中的应用

正则表达式在 JavaScript 中的应用非常广泛&#xff0c;尤其是在字符串处理和验证方面。以下是一些常见的正则表达式方法及其应用示例&#xff0c;包括 .test() 方法。 1. .test() 方法 .test() 方法用于测试一个字符串是否匹配正则表达式。如果匹配&#xff0c;返回 true&…

Rust视频处理开源项目精选

Rust视频处理开源项目精选 基于Rust实现的视频处理示例 以下是一些基于Rust实现的视频处理或多媒体相关的开源项目或示例,涵盖编解码、流媒体、分析工具等方向,可作为实际开发参考: 视频编解码与处理 rav1e:Rust编写的AV1视频编码器,高性能且内存安全,适合研究视频压缩…

Python爬虫实战:研究pycrumbs库,构建豆瓣读书数据采集系统

1. 引言 1.1 研究背景 在大数据与人工智能技术快速发展的背景下,互联网作为全球最大的信息载体,蕴含着海量结构化与非结构化数据。高效、合规地获取这些数据成为数据分析、业务决策的前提。网络爬虫作为自动化数据采集工具,通过模拟人类浏览行为遍历网页并提取信息,已成为…

linux的用户操作(详细介绍)

在 Linux 系统中&#xff0c;用户管理是系统管理员的核心工作之一&#xff0c;涉及用户账号的创建、修改、删除、权限分配等操作。Linux 采用多用户多任务机制&#xff0c;通过严格的用户和组管理确保系统安全性和资源分配合理性。以下是 Linux 用户操作的详细介绍&#xff1a;…