I was writing a code, and accidentally put int
before a variable twice, and noticed something different in the end product.
int main ()
{
int number = 123456789;
int step = 0;
while (number>0)
{
cout << number << endl;
number = number/10;
step = step 1;
cout << "step ; " << step << endl;
}
return 0;
}
The output was:
9
step ; 1
8
step ; 2
7
step ; 3
6 ...
However, when I called it this way:
int main ()
{
int number = 123456789;
int step = 0;
while (number>0)
{
cout << number << endl;
number = number/10;
int step = step 1;
cout << "step ; " << step << endl;
}
return 0;
}
The output suddenly changed to:
9
step ; 11006125
8
step ; 11006126
7
step ; 11006127
6
Can someone please explain the difference, so that I will be mindful next time?
CodePudding user response:
C is block scoped. When you redeclare step
inside the while
loop (by using int step
instead of just step
), you "shadow" the step
from outside that scope; while the outer step
(with value 0
) still exists, it cannot be read directly from the inner scope (a pointer/reference to the outer step
with a different name could read/write the data, you just can't read the outer step
directly through that name).
The outer step
is invisible, so int step = step 1;
translates as "please assign to the local step
the value of whatever is already stored in the local step
(which, not existing until that moment, has no defined value yet) after adding 1
". Since the step
it reads from is garbage, this is undefined behavior, and in practice, it gets garbage (whatever junk happened to be left on the stack in that position from before you entered the while
).
The second and subsequent creations of the inner step
are still undefined behavior, but in this case (and in most cases where loop unrolling isn't involved) the compiler chose to reuse the same storage for them as the prior use of inner step
(that expired when that iteration of the loop ended). Thus, as a coincidence of the new inner step
reading from the same memory location as the expired inner step
, it increments normally from then on, based on the original garbage value as a base.
But again, to be clear, all of this is undefined behavior. Be thankful you didn't get nasal demons, and only use the first form in the future. I'll note, if you enable all warnings, any compiler worth its salt should detect this error (the entire error exists in the scope of a single line); sadly, it appears at least GCC is not worth its salt, because the only thing it detects, even with -Wall -Wextra -Werror -pedantic
is that you didn't use the outer step
variable. If you used it, or deleted the declaration of the outer step
, it compiles with no warnings, so I guess you're stuck just remembering not to initialize a variable in terms of its own value.
CodePudding user response:
In the second case, you declare a second variable, which is also called step
, but is visible only inside the loop.