1. 两个符号本质区分
1.1 & 取地址运算符(单目)
作用:获取变量在内存中的地址,结果是一个指针值。
语法:&变量名
1.2 * 解引用运算符(单目)
作用:根据指针保存的地址,访问该地址里存储的真实数据。
语法:*指针变量
注意:* 有两种身份,不要混淆:
•定义指针变量时:int *p; 这里 * 只是标识 p 是指针,不是解引用运算
•运算表达式中:*p 这里 * 是解引用操作
2. 基础示例分步理解
#include <stdio.h> int main() { int a = 10; // 普通整型变量,存数值10 int *p; // p是int型指针,专门存int变量的地址 // 1. &a:取出变量a的内存地址,赋值给指针p p = &a; printf("a的值:%d\n", a); printf("a的地址&a:%p\n", &a); printf("指针p存储的值(就是a的地址):%p\n", p); printf("*p 解引用:取p地址里的数据 = %d\n", *p); // 2. 通过*p修改原变量a的值 *p = 20; printf("修改后a = %d", a); // a变成20 return 0; }运行逻辑拆解
① &a→ 拿到 a 的地址(如0xffff0004)
② p = &a→ 指针 p 存下这个地址
③ *p→ 顺着 p 存的地址,找到内存里 a 的值
3. & 和 * 互为逆运算
对同一个变量,*(&a)等价于a
int a = 5; // &a 取地址 → *再解引用,还原原值 printf("%d", *(&a)); // 输出5同理:&(*p)等价于p
int a=5; int *p=&a; // *p是a的值,&取地址又变回a的地址,等于p printf("%p", &(*p)); printf("%p", p);4. 常见场景用法
4.1 函数传参(修改外部变量,不用返回值)
普通传参是值拷贝,函数内改不了外面变量;
传地址 + 函数内解引用*可修改实参:
void change(int *x) { *x = 100; // 解引用,修改主函数a的值 } int main() { int a = 10; change(&a); // &a取地址传给指针形参 printf("%d", a); // 输出100 return 0; }4.2 二级指针int **pp(* 和 & 叠加)
int a = 10; int *p = &a; // p存a的地址 int **pp = &p; // pp存指针p的地址(二级指针) // 层层解引用 printf("%d", **pp); // 等价:*(*pp) → *p → a关系:
&a→ p 的值&p→ pp 的值*pp→ p**pp→ a
5. 易混淆易错点
5.1 定义指针时的 * 不是解引用
int* p; // *仅修饰p是指针,无运算作用 p = &a; // 运算时&取地址赋值5.2 不能对常量 / 表达式取地址&
int a; &5; // 错误,字面量无内存地址 &(a+1);// 错误,表达式临时值无地址5.3 野指针解引用*会崩溃
指针没有存有效地址时,不能用*:
int *p; *p = 10; // 崩溃!p是随机垃圾地址5.4&只能作用于内存实体:变量、数组元素
数组名本身是地址,不用再加 &:
int arr[5]; int *p = arr; // 正确,arr等价&arr[0] int *p = &arr; // 类型不匹配(数组地址 vs int指针)6. 总结
① &变量:向外拿地址,从数据拿到它的门牌号;
② *指针:向内找数据,拿着门牌号进门取里面的值;
③ 二者叠加*(&x)还原原始变量,互为反向操作。