Why does the code below count from 0 to 9?
Does C store the variable i in test always at the same address? And when calling C initializes the variable i with its previous value?
Or is that just by random chance ?
I used Ubuntu with gcc.
#include <stdio.h>
void test(){
int i;
printf("%dn", i);
i++;
}
int main(int argc, char const *argv[])
{
for (int i = 0; i < 10; i++){
test();
}
return 0;
}
/*
output:
0
1
2
3
4
5
6
7
8
9
*/
I also created an array in between function calls to see if the memory might be overritten but that did not change anything.
3
Answers
Actually the code has undefined behavior due to using the uninitialized variable
i
within the function testBut it occurred such a way that the memory where the variable
i
with automatic storage duration is allocated was not rewritten by other functions.It’s not legal to read an uninitialized variable. This is undefined behaviour, which means there’s no predicting what behaviour you’ll get next time.
There’s a couple of explanations why you might get the behaviour you see. The most likely is that your environment uses a stack, the automatic variable
i
is found on the stack, the stack frame of every call to the function happens to be at the same place, and nothing overwrites that part of the stack between calls totest
. In other words, you got very lucky.Again, you cannot count on getting the behaviour you observed, even from the same program.
The correct way to achieve the shown effect is to use a variable in static or extern storage.
or
or
Here is what I get
So answer is, yes it is by random chance. Not pure random. There is a bias that makes this behavior quite probable. But not sure. So by chance in the sense that you are not supposed to count on any such behavior.
The fact that your variable
i
intest
was the same asi
inmain
that is pure chance (totally unrelated to variable name being the same. It is not the same variable. And the names disappear at runtime. In fact, they disappear at the second stage of the classic 3 stages compilation). Well, biased also, because youri
ofmain
starts from 0, and, more often than not, an unitialized variable is 0 (not a rule. It just happens to be frequent). But you see, in my case, it was not so.If your
i
ofmain
was iterating from129391
to129401
, then probability to see the output of your code iterating precisely from129391
to129401
would have been near 0.The fact that the displays, in both cases (yours, starting from 0, and mine, starting from 21967) iterates 1 by 1, is also undefined (you can’t count on it). But yet, that one is almost a sure thing. At least with gcc and without too much optimization.
Simply because the
i
oftest
is a variable in the stack. And the stack has no reason not to be at the same place at each run oftest
. Nothing else uses the stack in between. And there is no reason to reinitialize it (that would be a waste of CPU). So, each subsequent call oftest
finds its variablei
where it let it.But, again,
you can’t count on it. For example, if an heavy optimization realizes that
i
is uninitialized, it could decide to not even allocate memory for it. Or even to unroll loop in main.That is because nothing else touches the stack. Just try this
And now my output is
First time, I get the random value that was at this place in the stack before anyone use it. And that place also happens to be where argument of
other
is pushed. So it is reset to 12 each times.And that, also, you can’t count on it. There is no rule saying that this is how stack is supposed to be used.