在循环中跟踪当前和以前的变量

Keeping track of current and previous variables in a loop

本文关键字:变量 循环 跟踪      更新时间:2023-10-16

我的程序中有一个bug,我发现非常令人困惑。

下面是问题代码的最小版本,以重现我的错误。

#include <iostream>
struct derp
{
  int idx;
};
int main (int argc, char **argv)
{
  derp initial;
  initial.idx = 0;
  derp *prev = &initial;
  while (true)
  {
    int c;
    while ((c = getchar()) != 'n' && c != EOF)
    {
    }
    if (c == EOF)
    {
      break;
    }
    derp cur;
    cur.idx = prev->idx + 1;
    std::cerr << "Prev: " << prev->idx << ", cur: " << cur.idx << std::endl;
    prev = &cur;
  }
}

另存为wtf.cpp .

编译。

$ CC wtf.cpp

$ (echo;echo;echo) | ./a.out
预期输出:

Prev: 0, cur: 1
Prev: 1, cur: 2
Prev: 2, cur: 3

运行时实际输出:

Prev: 0, cur: 1
Prev: 2, cur: 2
Prev: 3, cur: 3

我在Sun Solaris 10 10/09 s10x_u8wos_08a X86上使用Oracle Solaris Studio 12.4的CC。

问题是您的代码使用了一个超出作用域的指针。在循环的前一次迭代中有效的任何对cur的引用在进行下一次迭代时都是无效的。这就是为什么当prev指向initial时,第一次迭代是代码按预期工作的唯一迭代。在随后的迭代中,prev恰好指向与cur相同的位置,因为编译器在循环的所有迭代中将其保持在相同的位置。但是,该行为是未定义的,因此使用其他编译器编译时可能会得到不同的结果。

需要在循环外声明prevcur,并复制整个结构,如下所示:

derp prev;
prev.idx = 0;
derp cur;
while (true) {
    int c;
    while ((c = getchar()) != 'n' && c != EOF)
    {
    }
    if (c == EOF)
    {
        break;
    }
    cur.idx = prev.idx + 1;
    std::cerr << "Prev: " << prev.idx << ", cur: " << cur.idx << std::endl;
    prev = cur;
}

演示。

prev是一个指针,它最初指向一个变量,该变量在整个while循环中保持其作用域。然后在while循环中,创建一个新变量'cur',它的作用域仅限于该迭代,并保存指向该临时变量的指针。尝试在while循环之外定义cur。

干杯!