对于使用gcc -Wall -pedantic -std=c99 -g bug.c
编译的以下代码,我看到以下奇怪的结果
#include<stdio.h>
#include<stdlib.h>
typedef struct node_ {
int key;
} node;
void
add (node** cur, node* n)
{
if(*cur)
{
printf("%p %p\n", (void *)*cur, (void *)n);
printf("%d %d\n", (*cur)->key, n->key);
}
*cur = n;
}
int
main()
{
node* previous = 0;
char k[] = {1, 2, 3};
/* add(&previous, &(node){k[0]}); */
/* add(&previous, &(node){k[1]}); */
/* add(&previous, &(node){k[2]}); */
/* puts(""); */
for(int i=0; i<3; ++i)
add(&previous, &(node){k[i]});
}
结果
% gcc --version
gcc (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
% ./a.out
0x7fff756d60f0 0x7fff756d60f0
2 2
0x7fff756d60f0 0x7fff756d60f0
3 3
使用展开的循环,我会看到正确的行为
0x7ffdae8c72d0 0x7ffdae8c72e0
1 2
0x7ffdae8c72e0 0x7ffdae8c72f0
2 3
答案 0 :(得分:4)
for(int i=0; i<3; ++i)
add(&previous, &(node){k[i]});
这相当于:
for(int i=0; i<3; ++i) {
node tmp = { k[i] };
add(&previous, &tmp);
}
每次循环时,都会再次创建,使用和销毁临时node
结构。在第一次迭代之后,查看*previous
是一个错误,因为它指向一个不再存在的变量。
这种情况相当于从函数返回局部变量的地址。 (除了没有单独的函数;我们只留下一个局部块。但原理是相同的:在离开其范围并结束其生命周期后,我们保留一个指向局部变量的指针。)