这两个符号是 C 语言中指针 的基石,也是 C 语言强大和灵活(同时也容易出错)的主要原因,它们总是成对出现,理解了它们,你就理解了 C 语言的精髓之一。

(图片来源网络,侵删)
& (Ampersand) - 取地址运算符
这个符号的作用非常直观:获取一个变量在内存中的地址。
可以把它想象成一个变量的“家庭住址”,你不需要知道这个地址具体是什么,但你需要这个地址才能找到这个变量。
语法和示例
int age = 25; int *ptr_to_age = &age; // 将 age 的地址赋值给指针变量 ptr_to_age
&age:表达式&age会计算出变量age在内存中的地址。int *ptr_to_age:这是一个指针变量的声明,它声明了一个名为ptr_to_age的变量,这个变量专门用来存储一个int类型变量的地址。- 在这里表示
ptr_to_age是一个“指针”。 int表示这个指针指向的数据类型是int。
- 在这里表示
内存中的样子:
+---------------------+
| 内存地址 | 内容 |
+---------------------+
| 0x1001 | 25 | <-- 变量 age 存放在这里
+---------------------+
| 0x1002 | 0x1001 | <-- 指针 ptr_to_age 存放着 age 的地址 (0x1001)
+---------------------+
(Asterisk) - 解引用运算符
这个符号的作用与 & 相反:通过一个地址,访问该地址上存储的值,这个过程也被称为“解引用”。

(图片来源网络,侵删)
可以把它想象成“按地址找门牌号,然后开门拿东西”,你有了地址(指针),用 就能拿到里面的东西(值)。
语法和示例
int age = 25; int *ptr_to_age = &age; // 使用 * 解引用指针 int value = *ptr_to_age; // value 的值现在是 25 *ptr_to_age = 30; // 修改指针指向地址上的值,age 的值变成了 30
*ptr_to_age:表达式*ptr_to_age会取出指针ptr_to_age所指向地址上的值。- 在上面的例子中,
ptr_to_age存储的是age的地址,*ptr_to_age就等同于age。 *ptr_to_age = 30;这行代码的效果和age = 30;是完全一样的。
- 在上面的例子中,
& 和 作为函数参数
当 & 和 作为函数参数出现时,它们的意义变得至关重要,主要体现在值传递和指针传递的区别上。
a) 普通参数(值传递)
默认情况下,C 语言函数传递参数是“值传递”,这意味着函数内部接收到的是原始值的一个副本。
问题: 函数内部无法修改外部变量的值。

(图片来源网络,侵删)
#include <stdio.h>
// 函数尝试修改 x 的值
void try_to_modify(int x) {
x = 100; // 这里修改的只是副本,不影响外部的 a
printf("函数内部 x 的值: %d\n", x);
}
int main() {
int a = 10;
printf("调用函数前 a 的值: %d\n", a);
try_to_modify(a); // 传递 a 的值 (10)
printf("调用函数后 a 的值: %d\n", a); // a 的值仍然是 10
return 0;
}
输出:
调用函数前 a 的值: 10
函数内部 x 的值: 100
调用函数后 a 的值: 10
a 的值没有被改变,因为 try_to_modify 函数操作的是 a 的一个副本。
b) 使用 & 作为参数(指针传递 - 解决修改问题)
为了能让函数修改外部变量,我们需要传递变量的地址,这样,函数内部就可以通过这个地址找到并修改原始变量。
#include <stdio.h>
// 函数接收一个 int 类型的指针 (int *)
void modify_by_address(int *ptr) {
*ptr = 100; // 通过解引用,修改指针指向地址上的值
printf("函数内部 *ptr 的值: %d\n", *ptr);
}
int main() {
int a = 10;
printf("调用函数前 a 的值: %d\n", a);
// 传递 a 的地址 (&a)
modify_by_address(&a);
printf("调用函数后 a 的值: %d\n", a); // a 的值已经被成功修改!
return 0;
}
输出:
调用函数前 a 的值: 10
函数内部 *ptr 的值: 100
调用函数后 a 的值: 100
modify_by_address(&a):我们传递了a的地址&a。void modify_by_address(int *ptr):函数参数ptr是一个指针,它接收了a的地址。*ptr = 100:函数内部通过*ptr解引用,直接操作了内存地址0x1001上的内容,从而改变了外部变量a的值。
常见用途:
- 修改函数外部的变量:如上例所示。
- 避免大对象的拷贝:如果参数是一个很大的结构体,直接传递值会消耗大量内存和时间,传递结构体的地址则高效得多。
c) 使用 作为参数(指针本身作为数据)
函数需要返回多个值,或者其中一个“返回值”是一个指针,这时,函数参数本身就可以是一个指针。
示例:交换两个变量的值
C 语言没有真正的“引用”,所以交换两个变量的值必须通过指针。
#include <stdio.h>
// 函数接收两个 int 类型的指针
void swap(int *a, int *b) {
int temp = *a; // 保存 a 指向的值
*a = *b; // 将 b 指向的值赋给 a 指向的地址
*b = temp; // 将 temp 的值赋给 b 指向的地址
}
int main() {
int x = 5, y = 10;
printf("交换前: x = %d, y = %d\n", x, y);
swap(&x, &y); // 传递 x 和 y 的地址
printf("交换后: x = %d, y = %d\n", x, y);
return 0;
}
输出:
交换前: x = 5, y = 10
交换后: x = 10, y = 5
在这个例子里,*a 和 *b 是函数内部用来操作外部变量 x 和 y 的手段。
总结与核心区别
| 符号 | 名称 | 作用 | 使用场景 | 示例 |
|---|---|---|---|---|
& |
取地址运算符 | 获取变量的内存地址 | 赋值给指针变量 作为函数参数,以修改外部变量 |
int *p = &x;func(&x); |
| *``** | 解引用/指针运算符 | 通过地址访问该地址上的值 | 声明指针变量 解引用指针以获取或修改其指向的值 |
int *p;int y = *p;*p = 10; |
关键记忆点:
&是“问地址”:&变量得到这个变量的地址。- *`
是“拿东西”**:*指针` 得到这个指针指向地址上的东西(值)。 - 在函数参数中:
&让函数能够修改调用者的变量。- 让函数能够接收一个地址,或者让函数的返回值是一个地址。
理解了 & 和 的区别和联系,你就掌握了 C 语言中处理内存和实现高效、灵活函数的核心技能。
