C语言指针打印疑惑:为何a与p、p2与pp2地址相同?
C语言数组名与指针变量地址相同的原因解析
问题代码
int main() { int a[] = { 1, 2, 3, 4, 5 }; // a指向a[0]的地址 int *p = a; // p与a指向同一地址 int **pp = &p; // 指向p int *p2[] = { a, a+1, a+2, a+3, a+4 }; // 指向a int **pp2 = p2; // 与p2指向同一地址 printf(" a: %p, *a: %p\n", a, *a); printf(" p: %p, *p: %p\n", p, *p); printf(" pp: %p, *pp: %p, **pp: %p\n", pp, *pp, **pp); printf(" p2: %p, *p2: %p, **p2: %p\n", p2, *p2, **p2); printf("pp2: %p, *pp2: %p, **pp2: %p\n", pp2, *pp2, **pp2); return 0; }
编译运行方式
gcc main.c -o main ./main
运行输出
a: 0061FF04, *a: 00000001 p: 0061FF04, *p: 00000001 pp: 0061FEEC, *pp: 0061FF04, **pp: 00000001 p2: 0061FEF0, *p2: 0061FF04, **p2: 00000001 pp2: 0061FEF0, *pp2: 0061FF04, **pp2: 00000001
疑惑点
a和p的打印地址相同(0061FF04),p2和pp2的打印地址相同(0061FEF0),这一现象无法理解。
解答
1. 为什么a和p的打印地址相同?
- 数组名
a在绝大多数表达式场景中会自动隐式转换为指向数组首元素的指针,也就是&a[0]。当你用%p打印a时,实际输出的是数组第一个元素的内存地址。 - 指针变量
p被赋值为a,本质是接收了a转换后的指针值(即&a[0]),所以p存储的内容就是数组首元素的地址。打印p时,输出的就是这个存储的地址值,自然和a的打印结果一致。 - 注意:
a是数组类型,不是指针变量,它没有自己独立的内存地址(或者说&a是整个数组的地址,和&a[0]数值相同但类型不同);而p是实实在在的变量,有自己的内存地址,你可以添加printf("&a: %p, &p: %p\n", &a, &p);验证,两者地址完全不同。
2. 为什么p2和pp2的打印地址相同?
p2是一个指针数组,数组名p2同样会在表达式中隐式转换为指向数组首元素的指针,也就是&p2[0]。- 二级指针
pp2被赋值为p2,也就是接收了p2转换后的指针值(&p2[0]),所以打印pp2时,输出的就是这个地址,和p2的打印结果一致。 - 同理,
p2是数组类型,pp2是指针变量,&p2和&pp2的地址完全不同,可通过打印验证。
额外提示:代码中的未定义行为
你代码中用%p打印*a、*p、**pp等int类型的值是错误的,%p格式符要求对应参数是void*类型。这些值是整数,应该用%d打印,当前输出的00000001是把整数1强制当成地址解析的结果,属于未定义行为,建议修正。
内容的提问来源于stack exchange,提问作者user1132252
相关产品推荐
相关产品推荐

