接上集,我们来学习指针和函数的关系
指针与函数
前面我们学习了指针可以通过地址访问和修改数据。
例如:
int a = 10;
int *p = &a;
*p = 20;此时:
a → 20
*p → 20
那么问题来了:
如果把变量传给函数,函数能不能直接修改这个变量?
普通函数参数
先看一个简单的例子:
#include <stdio.h>
void change(int x) {
x = 20;
}
int main() {
int a = 10;
change(a);
printf("%d\n", a);
return 0;
}输出:
10
虽然调用了:
change(a);但是 a 并没有变成 20。
为什么?
因为:
void change(int x)这里的 x 是函数自己的一个变量。
调用:
change(a);实际上是把 a 中的数据复制给了 x。
可以理解成:
main:
a
↓
10
调用 change(a)
↓
函数:
x
↓
10
此时实际上存在两个变量:
a → 10
x → 10
所以:
x = 20;修改的是 x,而不是 a。
函数结束后,x 被销毁:
a → 10
所以最后还是:
10
通过指针让函数修改变量
如果希望函数修改 a,就可以把 a
的地址传给函数。
例如:
#include <stdio.h>
void change(int *p) {
*p = 20;
}
int main() {
int a = 10;
change(&a);
printf("%d\n", a);
return 0;
}输出:
20
这里发生了什么?
首先:
int a = 10;然后:
change(&a);把 a 的地址传给了函数。
函数:
void change(int *p)使用一个 int * 类型的指针接收这个地址。
可以理解为:
main:
a
↓
┌──────┐
│ 10 │
└──────┘
↑
│
&a
│
↓
函数:
p
↓
保存 a 的地址
因此:
*p就可以通过这个地址访问 a。
执行:
*p = 20;实际上修改的是 a。
所以:
a → 20
*p → 20
函数中的指针参数
来看完整的关系:
void change(int *p)这里的:
int *p表示:
p是一个int类型的指针变量。
调用:
change(&a);就是把:
&a传给函数。
所以:
&a
↓
a的地址
↓
p保存这个地址
↓
*p
↓
访问a
因此:
*p = 20;就可以修改 a。
一个更直观的例子
#include <stdio.h>
void add(int *p) {
*p = *p + 10;
}
int main() {
int a = 10;
add(&a);
printf("%d\n", a);
return 0;
}输出:
20
执行:
add(&a);之后:
a → 10
&a
↓
p
函数执行:
*p = *p + 10;实际上就是:
*p → 10
10 + 10
*p → 20
a → 20
为什么要传地址?
如果只是:
change(a);传进去的是:
a中的数据
函数得到的是数据的副本:
a → 10
x → 10
修改 x 不会影响 a。
而:
change(&a);传进去的是:
a的地址
函数得到的是这个地址:
a
↓
10
↑
│
p
所以函数可以通过:
*p找到并修改原来的数据。
可以简单记成:
传值:
a → 10
↓
x → 10
修改x
↓
a不变
传地址:
a → 10
↑
│
p
*p → 10
修改*p
↓
a也改变
函数修改数组
前面我们学习了指针可以遍历数组。
因此也可以把数组的地址传给函数。
例如:
#include <stdio.h>
void print_array(int *p, int size) {
for (int i = 0; i < size; i++) {
printf("%d\n", *(p + i));
}
}
int main() {
int a[5] = {10, 20, 30, 40, 50};
print_array(a, 5);
return 0;
}输出:
10
20
30
40
50
这里:
print_array(a, 5);数组名 a 在这里会转换成指向第一个元素的指针。
因此函数接收到的:
int *p指向:
a[0]然后:
*(p + i)就可以访问数组中的每一个元素。
关系是:
a
↓
a[0] 的地址
↓
p
p + 0 → a[0]
p + 1 → a[1]
p + 2 → a[2]
p + 3 → a[3]
p + 4 → a[4]
函数通过指针修改数组
不仅可以读取数组,还可以修改数组。
例如:
#include <stdio.h>
void change_array(int *p, int size) {
for (int i = 0; i < size; i++) {
*(p + i) = *(p + i) * 2;
}
}
int main() {
int a[5] = {1, 2, 3, 4, 5};
change_array(a, 5);
for (int i = 0; i < 5; i++) {
printf("%d\n", a[i]);
}
return 0;
}输出:
2
4
6
8
10
因为函数中的:
*(p + i)访问的就是 a[i]。
所以:
*(p + i) = *(p + i) * 2;实际上就是修改数组中的元素。
指针与函数的核心
到这里,我们可以把前面学习的内容全部连接起来:
变量
↓
变量有地址
↓
&a 获取地址
↓
指针保存地址
↓
*p 通过地址访问数据
↓
把地址传给函数
↓
函数通过指针访问和修改原来的数据
例如:
void change(int *p) {
*p = 20;
}
int main() {
int a = 10;
change(&a);
printf("%d\n", a);
}核心关系:
a
↓
&a
↓
传给函数
↓
p
↓
*p
↓
修改a
记住:
普通参数:
change(a)
传递a中的数据
指针参数:
change(&a)
传递a的地址
因此,当函数需要修改调用者中的变量时,就可以使用指针参数。
Comments NOTHING