1
What's the output of following code (B)
#include <stdio.h>
#include <stdint.h>
uint32_t a = 10;
void func(uint32_t **out) {
*out = &a;
a = 20;
}
int main(void) {
uint32_t *out = 0;
func(&out);
printf("%u\r\n", *out);
return 0;
}
10
20
无法运行
0
解答:
out 为 uint32_t 类型的指针,func 函数将指针 out 的地址作为形参传入,在函数体内修改指针指向的值为全局变量 a,同时又修改全局变量 a 的值为 20,因此最终输出的是 a 的值 20
相当于先创建一个指针o,在func中:对指针的地址作为形参(指向指针的指针),对这个参数(指针)指向a的地址。然后改动a值。最后引用o,相当于jiet's the output of following code ==(B)==
#include <stdio.h>
#include <stdint.h>
uint32_t a = 10;
void func(uint32_t **out) {
*out = &a;
a = 20;
}
int main(void) {
uint32_t *out = 0;
func(&out);
printf("%u\r\n", *out);
return 0;
}
10
20
无法运行
0
解答:
out 为 uint32_t 类型的指针,func 函数将指针 out 的地址作为形参传入,在函数体内修改指针指向的值为全局变量 a,同时又修改全局变量 a 的值为 20,因此最终输出的是 a 的值 20
相当于先创建一个指针o,在func中:对指针的地址作为形参(指向指针的指针),对这个参数(指针)指向a的地址。然后改动a值。最后引用o,相当于jie
你的疑问涉及指针和二级指针的核心概念。让我通过更直观的方式解释整个过程,特别是参数传递和解引用的细节:
一、关键概念澄清
1. 指针 vs 二级指针
- 指针(
uint32_t*):存储变量的地址(如&a)。 - 二级指针(
uint32_t**):存储指针的地址(如&out)。
2. 参数传递本质
C语言中,函数参数是值传递(拷贝):
- 传递
&out(指针的地址)时,形参out是&out的拷贝(但二者指向同一内存地址)。 - 修改
*out(即修改原指针out的值),但无法修改&out本身(因为是拷贝)。
二、分步图解执行过程
1. 初始状态(main函数)
uint32_t a = 10; // a的值为10,地址假设为0x1000
uint32_t *out = 0; // out的值为NULL(0),自身地址假设为0x2000
内存布局:
地址 变量 值
0x1000 a 10
0x2000 out NULL (0)
2. 调用func(&out)
&out(值为0x2000)被拷贝到func的形参out中。- 形参
out的值为0x2000(即指向main中的out变量)。
3. func内部:*out = &a;
*out等价于main中的out(因为out指向main的out)。&a(值为0x1000)被赋值给*out,即修改了main中out的值。
内存变化:
地址 变量 值
0x1000 a 10
0x2000 out 0x1000 (指向a)
4. func内部:a = 20;
- 直接修改全局变量
a的值为20。
内存变化:
地址 变量 值
0x1000 a 20
0x2000 out 0x1000 (仍指向a)
5. 返回main:printf("%u", *out);
out的值为0x1000(指向a)。*out解引用得到a的值20,输出结果为20。
三、关键误区解答
Q1:*out = &a 到底修改了什么?
*out是对二级指针out的解引用,等价于main中的out变量。*out = &a将main中的out指向a(即out的值变为a的地址0x1000)。
Q2:为什么需要二级指针?
- 若仅传递一级指针(
uint32_t*),函数内部只能修改指针指向的内容(如*out = 20),无法修改指针本身(因为参数是拷贝)。 - 二级指针允许函数通过
*out = &a间接修改外部指针的值。
Q3:最终*out得到了什么?
out指向a(地址为0x1000)。*out通过地址0x1000访问到a的值20。
总结
通过二级指针uint32_t**,函数func修改了main中指针out的值,使其指向全局变量a。最终*out解引用得到的是a被修改后的值20。核心在于理解二级指针如何间接操作外部指针,以及参数传递是值拷贝但可通过地址修改原变量。
这段代码展示了通过二级指针修改外部指针变量的过程。下面详细解析其执行流程和内存变化:
五、关键点总结
-
二级指针的作用:
func通过二级指针uint32_t **out修改了main中一级指针out的值(使其指向a)。- 若直接传递一级指针(
uint32_t *),只能修改指针指向的内容(如*out = 20),无法修改指针本身。
-
全局变量的可见性:
func内部对a的修改直接影响全局变量,因此main中通过out访问到的是修改后的值20。
-
执行顺序的重要性:
- 即使
a = 20;在*out = &a;之后执行,由于out已指向a,修改a仍会影响后续*out的结果。
- 即使
六、常见误区对比
错误示例1:传递一级指针(无法修改外部指针)
void func(uint32_t *out) {
out = &a; // 仅修改局部拷贝,main中的out未改变
}
- 结果:
main中的out仍为NULL,*out会导致空指针解引用错误。
错误示例2:未初始化指针(野指针)
void func(uint32_t **out) {
uint32_t b = 30;
*out = &b; // 返回局部变量地址(函数返回后失效)
}
- 结果:
main中的out指向已销毁的局部变量b,形成野指针。
总结
这段代码通过二级指针实现了函数内部对外部指针的修改,使out成功指向全局变量a,最终输出a被修改后的值20。核心在于理解二级指针如何间接操作一级指针,以及全局变量的作用域。
浙公网安备 33010602011771号