在上一篇介绍中,我们了解了指针的基本概念和它在 C 语言中的重要作用。今天,我们将深入探讨指针的操作符和类型,这是熟练使用指针的关键一步。
一、指针操作符
C 语言中有两个与指针密切相关的重要操作符:
-
&(取地址符) -
*(解引用符)
它们在指针的声明和使用中起着核心作用。
🎯 理解指针和操作符:房间和纸条的比喻
我们可以用“房间”和“纸条”来类比变量和指针的关系,帮助大家更直观地理解:
-
普通变量就像是一个有名字的房间,比如一个叫
name的房间。你通过房间名name,就能找到这个房间,并查看它里面的内容(比如“张三”)。 -
指针变量也是一个有名字的房间,比如叫
p的房间。但它里面装的不是具体的数据,而是一张写着其他房间编号的纸条,比如纸条上写着age房间的编号。
换句话说,p 并不直接存数据,它存的是另一个变量(房间)的地址,是“通往另一个房间的线索”。
🧭 &(取地址符):告诉我房间在哪里
& 操作符就像一个“地址查询员”。
你问它:“age 房间的编号是多少?”
它就会把 age 房间的位置编号(即地址)写在一张纸条上交给你:&age。
这就是取地址操作,它告诉我们某个变量在内存中的地址。
🛠️ *(解引用符):按照纸条找到房间取数据
* 操作符就像一个“执行者”。
你递给他一张纸条(一个指针变量 p),他就会:
-
打开
p这个房间(指针变量本身), -
取出里面那张纸条(地址),
-
沿着地址找到目标房间(比如
age), -
然后把里面的内容(值)带出来。
这就是 *p 的含义:去指针 p 指向的地址,取出那个地址所对应的数据。
下面这段代码能更直观地展示我们刚才讲到的指针、地址和值之间的关系:
#include <stdio.h>
int main() {
int age = 30;
int *p = &age;
printf("age 的地址是:%p\n", &age); // 地址:十六进制显示
printf("指针 p 的值是:%p\n", p); // p 存的也是地址
printf("指针 p 指向的值是:%d\n", *p); // 解引用,输出 30
return 0;
}
age 的地址是:0x7ffeefbff5a4
指针 p 的值是:0x7ffeefbff5a4
指针 p 指向的值是:30
🧭 特别说明:声明 vs 使用中 * 的含义不一样!
在 C 语言中,* 有两个不同的作用场景:
| 位置 | 含义 | 示例 | 解读 |
|---|---|---|---|
| 声明中 | 表示“这是一个指针变量” | int *p; | p 是一个指向 int 类型的指针 |
| 使用中 | 表示“解引用,访问指针所指向的值” | *p = 10; | 将 p 指向的地址中的值改为 10 |
🧱 示例代码:声明 vs 使用
#include <stdio.h>
int main() {
int a = 5;
int *p = &a; // 声明:* 表示 p 是一个 int 类型的指针
printf("a = %d\n", a); // 输出:a = 5
printf("*p = %d\n", *p); // 使用:* 表示解引用,访问 a 的值
*p = 10; // 修改 p 指向的值(即 a)
printf("a = %d\n", a); // 输出:a = 10
return 0;
}
🔍 解读:
-
int *p;:声明中*表示“我声明了一个指针”,它不是操作符,而是类型说明的一部分。 -
*p = 10;:这里的*是 解引用操作符,告诉编译器“去 p 指向的那个地址,把值改成 10”。
💬 容易误解的写法
很多初学者写:
int* p, q;
以为是“p 和 q 都是指针”,其实只有 p 是指针,q 是普通 int 变量!
建议写的时候这样写,避免误会
int *p; //指针
int *q; //指针
int *p, *q //都是指针
📌 小结:
声明时的
*:我是谁(身份标签)
使用时的*:我要干什么(操作动作)
虽然写法一样,含义天差地别,千万不要混淆!
二、指针类型:纸条也分种类
在 C 语言中,指针不仅仅是“地址纸条”,纸条上还会标明“这条纸是指向什么类型房间的”。
📌 什么是指针类型?
我们在定义指针时,不是只写 *p,而是要明确它指向的变量类型,例如:
int *p; // p 是一个指向 int 类型的指针
char *c; // c 是一个指向 char 类型的指针
double *d; // d 是一个指向 double 类型的指针
这些声明的意思是:
-
p这个指针房间里,存着一张纸条,这张纸条指向一个 int 类型的房间 -
c的纸条指向的是 char 类型的房间 -
d的纸条指向的是 double 类型的房间
🧠 为什么指针要有类型?
因为当我们使用 *p 进行解引用操作时,编译器需要知道从这个地址开始,读取多少字节的数据。
-
int *告诉编译器要读 4 个字节(在大多数系统上) -
char *则只读 1 个字节 -
double *可能读 8 个字节
👉 换句话说,类型是“读取指南”,没有类型,解引用就像在黑暗中摸东西,容易出错。
⚠️ 错误示范:类型不匹配引发的错误解引用
我们来看下面这段代码,它故意将一个 int * 强制转换为 char * 并解引用,看看会发生什么:
#include <stdio.h>
int main() {
int age = 0x41424344; // 十六进制,内存中是 'A', 'B', 'C', 'D' 的 ASCII 值
int *pInt = &age;
char *pChar = (char *)&age; // 强制将 int 地址当作 char 指针
printf("age: %d\n", age);
printf("*pInt: %d\n", *pInt); // 正确,读取整型 0x41424344
printf("*pChar: %c\n", *pChar); // 警惕:读取的是最低位的 1 字节,对应 'D'
printf("*((int*)pChar): %d\n", *((int*)pChar)); // 转回来,输出正确整型
return 0;
}
🖨️ 示例输出(可能因平台不同略有差异):
age: 1094861636
*pInt: 1094861636
*pChar: D
*((int*)pChar): 1094861636
🔍 分析说明:
-
0x41424344是 16 进制整数,按 ASCII 表示,4 字节依次对应'A''B''C''D'。 -
由于 x86 架构是小端字节序,最低位
0x44(即'D')排在最前面,所以*pChar读取的是'D'。 -
当你用
char *去解引用一个int地址,只能读取一个字节,结果会出乎意料。 -
强制转换回
(int*)后才能正确还原整型数值。
🚨 教训:
指针是地址没错,但类型告诉你:这个地址里的内容该怎么解释、读多少个字节、以什么方式解码。
把一个指向 int 的指针当作 char * 使用,就像你拿放着身份证的抽屉去读身份证号码,但只撕下一角去解读——当然会出错。
✅ 建议:
不要随意强制类型转换指针,除非你非常明确内存布局,并清楚你在干什么(例如操作系统开发或硬件驱动中)。
🧾 总结:纸条的作用、种类与使用方式
通过今天的学习,我们进一步理解了指针的本质:它就像是一张纸条,指向另一个房间的位置,也就是变量的地址。围绕这个“纸条”概念,我们掌握了两大关键内容:
✅ 指针操作符:
-
&是“地址查询员”,帮我们获取变量房间的位置编号; -
*在使用时是“执行者”,根据纸条的地址去房间取数据; -
注意:
*在声明时是身份标签,表示“这是一个指针”,在使用时才是解引用动作!
✅ 指针类型:
-
每张纸条(指针)都必须标明指向什么类型的房间(如
int*,char*,double*); -
类型决定了解引用时该取多少字节、怎么解释内存中的内容;
-
指针虽然都是“地址”,但它们不是万能钥匙,只有类型匹配,才能安全准确地访问数据。
学会了这两部分内容,就等于掌握了“如何正确拿着纸条,找到正确的房间,并安全地读取或修改里面的东西”。接下来,我们可以继续探索指针的更高级用法,比如指向指针的指针(装着纸条的纸条)、指针数组、甚至函数指针,让你在指针的世界里更加游刃有余。

被折叠的 条评论
为什么被折叠?



