C语言:指针(结合案例)
2026/9/15 9:11:11 网站建设 项目流程

前文我们已经初步学习了指针,本篇文章将结合几个重要的例子来加深对指针的理解。

一、理论知识整理

1. 指针变量的字节数

所有指针变量在内存中占的字节数都是相同的,永远是2个字节(16位地址)。

无论定义的是int *p1float *p2还是double *p3。

p1、p2、p3 这三个指针变量本身都只占2个字节。

类比理解:就像一栋楼的门牌号,不管房间多大,门牌号都是固定位数的(比如都是3位数)。但门牌号背后的房间大小是不一样的。

2. 指针前面类型的真正含义

定义指针时前面写的类型(int、float、double),不是指针变量本身的类型,而是:

这个指针将来要指向的那个内容变量的类型,也就是它打开的"房间"的大小。

指针定义指针本身占字节指向的变量占字节指向的变量类型
int *p12字节2字节int型
float *p22字节4字节float型
double *p32字节8字节double型

核心规则:同类型互指。

什么类型的指针,就要得什么类型变量的地址。eg:

int型指针→只能得int型变量的地址

float型指针→只能得float型变量的地址

double型指针→只能得double型变量的地址

3. 指针口诀四(完整三句话)

这是做指针的核心口诀,必须背熟:

第一句:地址变量得地址,得谁地址指向谁。

指针变量拿到哪个变量的地址,就指向哪个变量。

第二句:有星为内容值,不是读就是写。放在赋值号左边为写,其他都为读。

*p出现在赋值号左边→写操作(往p指向的内存里写值)

*p出现在其他任何地方→读操作(读出p指向的内存里的值)

第三句:无星为地址,地址的赋值意味着改指向。

p1 = p2没有星,操作的是地址本身,执行后p1的指向改变了,和p2指向同一个地方。

4. 指针作为函数参数(形参如何影响实参)

C语言永远是单向传值:实参→形参,形参的值不能直接传回给实参。

但是,通过传地址(传指针),形参可以间接地修改实参的值。需要同时满足两个条件:

条件一:把地址传给对方(实参是指针/地址)

主函数把变量的地址(钥匙)交给子函数

条件二:对方要用指针运算符*进行读写

子函数拿到钥匙后,要*p进门去修改房间里的东西

只传地址但不用*运算→只是交换了形参自己的指向,不会影响实参。 传地址且用了*运算→真正修改了主函数中变量的值。

指针的优势:return语句最多只能返回一个值,而通过指针可以同时"返回"多个修改后的值。

5. 指针变量必须初始化后才能使用

指针变量不仅仅要定义,还要初始化,定义且初始化后才能用。

未初始化的指针是野指针,里面的地址是随机的,可能指向:

用户区(碰巧没事)

系统区(写操作→篡改系统数据→死机/崩溃)

对野指针进行写操作是极度危险的,在实际运行中会触发内存访问错误。

6. 指针题的画图方法

内容变量(普通变量)→画房子,里面写值

指针变量→画指向箭头,得谁地址就指向谁

函数调用时,主函数和子函数的同名变量是彼此独立、互不影响的,画图时要分开画

二、VS2019示例

此处列举四道经典例题。

例题1:指针传参修改实参(基础题)

题目:主函数x=1, y=2,调用子函数时传&y&x(注意顺序反了),子函数先输出*x*y,再执行*x=3; *y=4;,主函数最后再输出x和y。

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> // 子函数:形参x、y都是指针变量 void fun(int *x, int *y) { // 有星为内容值,不在赋值号左边 → 读 // x得到的是主函数y的地址,所以*x读的是主函数y的值=2 // y得到的是主函数x的地址,所以*y读的是主函数x的值=1 printf("%d%d", *x, *y); // 输出 21 // 有星为内容值,在赋值号左边 → 写 *x = 3; // 把3写入x指向的房子(主函数的y),y变成3 *y = 4; // 把4写入y指向的房子(主函数的x),x变成4 } int main() { int x = 1, y = 2; // 注意:传参顺序是 &y, &x(反的) // 实参&y传给形参x,实参&x传给形参y fun(&y, &x); // 子函数中*x=3改了主函数的y → y=3 // 子函数中*y=4改了主函数的x → x=4 printf("%d%d", x, y); // 输出 43 return 0; } // 最终输出:2143

例题2:swap交换(正确版—用*交换内容)

题目:输入两个数,通过swap函数交换它们的值。

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> // 正确的swap:用临时普通变量temp,通过*交换指向的内容 void swap(int *p1, int *p2) { int temp; // 普通变量,存内容值 temp = *p1; // 读:读出p1指向的值,给temp *p1 = *p2; // 读+写:读出p2指向的值,写入p1指向的单元 *p2 = temp; // 读+写:读出temp的值,写入p2指向的单元 } int main() { int a, b; int *p1 = &a, *p2 = &b; printf("请输入两个整数(空格分隔):"); scanf("%d%d", p1, p2); // p1、p2本身就是地址,不用再加& // 输入 2 5 → a=2, b=5 printf("交换前:a=%d, b=%d\n", a, b); // a=2, b=5 swap(p1, p2); // 传地址(p1、p2里存的是a和b的地址) printf("交换后:a=%d, b=%d\n", a, b); // a=5, b=2 return 0; } // 输入:2 5 // 输出:交换前 a=2,b=5 交换后 a=5,b=2

为什么能交换成功?

  1. 主函数把a和b的地址(钥匙)传给了swap的形参p1、p2
  2. swap里用了*运算,拿着钥匙进门,真正修改了a和b房子里的内容
  3. 形参p1、p2虽然在函数结束后被释放,但它们对a、b的修改已经留在了内存里

例题3:swap交换(错误版 — 只交换地址,不用*)

题目:本例跟例题2看起来很像,但swap里用的是int *temp,交换的是p1、p2本身(地址),没有用*

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> // 错误的swap:用临时指针变量temp,交换的是地址本身(指向) void swap(int *p1, int *p2) { int *temp; // 临时指针变量 temp = p1; // 无星为地址 → 改指向:temp指向p1原来指向的地方(a) p1 = p2; // 无星为地址 → 改指向:p1现在指向p2原来指向的地方(b) p2 = temp; // 无星为地址 → 改指向:p2现在指向temp指向的地方(a) // 结果:形参p1和p2的指向交换了,但a和b房子里的内容根本没动! } int main() { int a, b; int *p1 = &a, *p2 = &b; printf("请输入两个整数(空格分隔):"); scanf("%d%d", p1, p2); // 输入 2 5 → a=2, b=5 printf("交换前:a=%d, b=%d\n", a, b); // a=2, b=5 swap(p1, p2); printf("交换后:a=%d, b=%d\n", a, b); // 还是 a=2, b=5!没有交换成功 return 0; } // 输入:2 5 // 输出:交换前 a=2,b=5 交换后 a=2,b=5(没变!)

为什么交换失败?

  1. 虽然传了地址(满足条件一)
  2. 但swap里全程没有用*运算(不满足条件二)
  3. 只是把形参p1、p2这两把"钥匙"交换了,根本没有进门去改房间里的东西
  4. 形参被释放后,主函数的a、b完全不受影响

记住:想让形参影响实参,传地址只是必要条件,还必须在子函数里用*去读写。

例题4:swap交换(错误版—野指针,运行崩溃)

题目:本例跟例题2类似,但swap里用int *temp且未初始化,直接*temp = *p1

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> // 极度危险的swap:temp是未初始化的野指针 void swap(int *p1, int *p2) { int *temp; // 只定义了指针temp,没有初始化!temp里是随机地址 *temp = *p1; //危险!把p1指向的值写入temp指向的随机地址 // 如果temp碰巧指向系统区,就会篡改系统内存 → 死机/崩溃 *p1 = *p2; *p2 = *temp; } int main() { int a, b; int *p1 = &a, *p2 = &b; printf("请输入两个整数(空格分隔):"); scanf("%d%d", p1, p2); printf("交换前:a=%d, b=%d\n", a, b); swap(p1, p2); // 运行到这里会触发内存访问错误,程序崩溃 printf("交换后:a=%d, b=%d\n", a, b); return 0; } // 运行结果:程序崩溃(VS2019会报"写入访问权限冲突"或类似错误)

为什么崩溃?

  1. int *temp;只定义不初始化,temp是野指针,指向随机内存
  2. *temp = *p1;对野指针进行写操作,把值写到了随机地址
  3. 如果那个随机地址是系统保护区,操作系统会直接终止程序(内存访问违规)
  4. 即使碰巧没崩溃,也可能篡改了其他重要数据,后果不可预测

正确做法:temp用普通变量(如例题2),或者如果一定要用指针,必须先让temp指向一个合法变量:

int t; int *temp = &t; // 先初始化,让temp指向t *temp = *p1; // 安全,写入的是t的内存

三、四道例题对比总结

例题swap里temp类型有没有用*结果原因
例1有*成功修改实参传地址+用*读写
例2int temp(普通变量)有*交换成功传地址+用*改内容
例3int *temp(指针)无*(只操作地址)交换失败传了地址但没用*,只改了形参指向
例4int *temp(未初始化指针)有*程序崩溃野指针写操作,访问非法内存

学习过程有诸多不足之处,欢迎来私信与我一同交流学习,共同进步!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询