C指针循环中的奇怪行为

时间:2015-08-29 14:48:56

标签: c pointers

对于使用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

1 个答案:

答案 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是一个错误,因为它指向一个不再存在的变量。

这种情况相当于从函数返回局部变量的地址。 (除了没有单独的函数;我们只留下一个局部块。但原理是相同的:在离开其范围并结束其生命周期后,我们保留一个指向局部变量的指针。)