cvariablesfor-loopstackautomatic-storage

Variable created inside loop changes value during iterations in C


I have code similar to the following in our product. According to me, the output is '0 1 2 3'. But the output of the similar code is '1 1 1 1'.

for(i = 0 ;i < 5;i++){
    int j;
    if(i)
        printf("%d ",j);
    j = i;
}

My understanding is that the j is allocated on the stack only once during the entire period of 'for' loop and the same value is used during iterations. Also, if I move the declaration of j outside for loop, I'm getting the expected result. What am I missing here?

PS - When I run the same code on my personal machine, I am getting the expected output. But on production it is different.


Solution

  • First, to clear things about the storage duration of an automatic local variable, let me quote the C11 standard, chapter §6.2.4, (emphasis mine)

    An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, [...]

    and,

    For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.

    So, in your code, each iteration gets a new instance of j. Nothing is retained.

    In your code,

        int j;   //not initialized
        if(i)
            printf("%d ",j);  //this one here
    

    you're trying to use an unitialized automatic local variable j, which has indeterminate value. It invokes undefined behavior.

    As per C11, chapter §6.7.9

    If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate

    and related, for UB, annex §J.2

    The value of an object with automatic storage duration is used while it is indeterminate.

    Once your code hits UB, the output cannot be justified, anyway.

    OTOH, when you declare j outside the loop, it has function scope. Then, unlike above case, there will be only one instance of j for all iterations of the loop.

    As per the execution flow, first time, i being 0, if will evaluate to false, printf() will be skipped and j will get initialized. Then, in next iteration, when you hit the printf(), j is initialized and it's all well thereafter.