2

It's a follow-up of Redeclaring of an array in loop in C with some of my additional observation.

Consider following two examples:

#include <stdio.h>
int main(void)
{
    int i = 1;
    while (i <= 10) {
        int t[10];
        if (i == 1)
            t[0] = 100;
        else {
            t[0]++;
            printf("i = %d, t[0] = %d\n", i, t[0]);
        }
        i++;
    }
    return 0;
}

with result as expected:

i = 2, t[0] = 101
i = 3, t[0] = 102
i = 4, t[0] = 103
i = 5, t[0] = 104
i = 6, t[0] = 105
i = 7, t[0] = 106
i = 8, t[0] = 107
i = 9, t[0] = 108
i = 10, t[0] = 109

and second one (slightly different) with VLA (introduced in C99):

#include <stdio.h>
int main(void)
{
    int i = 1;
    while (i <= 10) {
        int t[i];
        if (i == 1)
            t[0] = 100;
        else {
            t[0]++;
            printf("i = %d, t[0] = %d\n", i, t[0]);
        }
        i++;
    }
    return 0;
}

What I am getting for second example (in gcc 4.4.7) is something strange to me:

i = 2, t[0] = 101
i = 3, t[0] = 102
i = 4, t[0] = 103
i = 5, t[0] = 1
i = 6, t[0] = 2
i = 7, t[0] = 3
i = 8, t[0] = 4
i = 9, t[0] = 1637935601
i = 10, t[0] = 1637935602

Is there any rule/reference in C standard for VLAs declared inside loop or is it just a compiler's bug ?

Community
  • 1
  • 1
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • I suspect it's undefined behaviour since `t[0]` is not initialized. – R Sahu Jul 29 '14 at 17:46
  • 1
    Calling out for a compiler bug is usually the indication of lack of experience, knowledge and humility. Don't do that. – The Paramagnetic Croissant Jul 29 '14 at 17:47
  • You should add printing the address of `t[0]` with your print too. Looking at the output, I suspect with VLA you have one address with sizes 1..4, other address with sizes 5..8 and yet another with sizes 9..10 (or not, in case values change because previous data just gets overwritten). – hyde Jul 29 '14 at 18:02

2 Answers2

5

In both cases you are supposed to see garbage values. Your array object (VLA or not) begins its lifetime again on each iteration of the cycle. And every time it begins its lifetime with indeterminate values in it. In your first example you simply got lucky and those "indeterminate" values just happened to be the same as the values left in memory by the previous iteration. Meanwhile, the underlying mechanics of VLA is different, so you just didn't get that lucky with VLA.

Note that in C language the lifetimes of VLA and non-VLA objects are defined differently. Non-VLA objects begin their lifetime at the opening { of the corresponding scope, while VLA objects begin their lifetimes at the point of declaration. And even for non-VLA objects defined without an initializer, when control passes over their definitions they immediately acquire indeterminate values.

But these details would matter in situations as the one described here: GOTO before local variable. However, this does not matter in your specific examples, since in your examples both arrays are destroyed and recreated on each iteration.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

The lifetime of a variable length array extends from the delcaration till the end of the scope. this is covered in the draft C99 standard section 6.2.4 Storage durations of objects which says:

For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration.27) If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.

So you are invoking undefined behavior here since you are using indeterminate values.

This is different for not variable length arrays, the draft standard says:

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.[...]

The Rationale for International Standard—Programming Languages—C explains why:

These rules have to be modified slightly for variable length arrays. The implementation will not know how much space is required for the array until its declaration is reached, and so cannot create it until then.

A more complicated case where this matters is covered in GOTO before local variable, which I have an answer for as well.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • OK. So this depends on the `while () { ... }` leaving and re-entering the _loop body_, which in this case is a _compound-statement_, which (6.8.2 of C99 standard) is a _block_. I find that (6.8.5.1 "The while statement") tells me "The evaluation of the controlling expression takes place before each execution of the loop body". I suppose that tells me that after each execution of the loop body it leaves its block scope (if any)... but is there a more direct statement of that which I have failed to find ? –  Jul 29 '14 at 18:22