Plony al Mony
Plony al Mony

Reputation: 53

Keeping track of current and previous variables in a loop

I have a bug in a program of mine which I find very confusing.

Below is a minimal version of the problematic code to reproduce my 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;
  }
}

Save it as wtf.cpp.

Compile.

$ CC wtf.cpp

Run.

$ (echo;echo;echo) | ./a.out

Expected output:

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

Actual output when running:

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

I am using CC from Oracle Solaris Studio 12.4 on Sun Solaris 10 10/09 s10x_u8wos_08a X86.

Upvotes: 2

Views: 1502

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726809

The problem is that your code uses an out-of-scope pointer. Any reference to cur that was valid in a prior iteration of the loop is invalid as soon as you get to the next iteration. That's why the first iteration, when prev points to initial, is the only iteration when your code works as expected. On subsequent iterations prev happens to point to the same place as cur, because the compiler keeps it in the same place in all iterations of the loop. However, the behavior is undefined, so you may get different results when compiling with other compilers.

You need to declare both prev and cur outside the loop, and make a copy of the entire structure, like this:

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;
}

Demo.

Upvotes: 3

Bas in het Veld
Bas in het Veld

Reputation: 1322

prev is a pointer, and it initially points to a variable that retains its scope throughout the while loop. Then in the while loop, you create a new variable 'cur', which has a scope limited to that iteration, and save a pointer to that temporary variable. Try defining cur outside the while loop.

Cheers!

Upvotes: 2

Related Questions