7
    #include <stdio.h>

    int a;

    void myproc()
    {
        int a = 2;
        while (a == 2)
        {
            int a = 3;
            printf("a = %d\t", a);
            break;
        }
        printf("a = %d\t", a);
    }

    int main()
    {
        a = 1;
        myproc();
        printf("a = %d\t", a);
        return (0);
    }

I expected the above code to print: a = 3 a = 3 a = 1 However, it prints: a = 3 a = 2 a = 1 Can someone please provide a valid explanation?

hardcoder
  • 415
  • 1
  • 5
  • 13

6 Answers6

6

Yes, they are local automatic variables and are pushed on and popped off the stack when you enter and exit a given scope unless the compiler decides to make certain optimizations (such as storing them in registers, etc.) But for a given variable, the most locally scoped version of that variable is used when accessing it. For instance, in C89 should you decide to declare your loop counters within a for-loop declaration, the following typically produces a compiler error:

for (int i=0; i < N; i++)
    for (int i=0; i < J; i++)
        printf("%d", i);

The value of i printed will always be the value of i declared in the inner for-loop, since that is the most locally scoped version of i.

Jason
  • 31,834
  • 7
  • 59
  • 78
6

Here is an explanation -- see the commentary below.

#include <stdio.h>

int a;

void myproc()
{
    int a = 2; // (1) a = 2
    while (a == 2) // true
    {
        int a = 3;  // (2) new scope, new a = 3
        printf("a = %d\t", a); // (X) prints 3 as it gets the 'nearest a' in the scope
        break;
    } // throws away a=3 from (2)
    printf("a = %d\t", a); // (Y) Uses (1) i.e. 2 and print it 
}

int main()
{
    a = 1;
    myproc();
    printf("a = %d\t", a); // (Z) Just prints 1 as the scope is not effected by myproc
    return (0);
}

So this will print (X) (Y) and (Z)

i.e. 3 2 1

Brendan
  • 1,995
  • 1
  • 20
  • 35
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
3

"Within a loop"?

The question you are asking has absolutely no relation to any loops at all. There's no difference between what you have in your code and the ordinary

int a;

void myproc()
{
    int a = 2;
    {
        int a = 3;
        printf("a = %d\t", a);
    }
    printf("a = %d\t", a);
}

Each nested block has it own variables. That's all there is to it. And it has nothing to do with any loops.

The declaration that is really related to the loop would be the declaration made in the header of the loop, as in

    int a = 3;

    for (int a = 0; a < 10; ++a)
    {
      ...
    }

    printf("a = %d\n", a); // <- prints `3`

That a declared in the for header is still local to the loop.

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

The { } variables declare scope. As when you declare a variable between those braces it is only available in those braces. If you have nested variables (like in myproc you declare a = 2 and then inside the loop a=3) then the variable declared closet to the current scope is the one referenced (in the example, a = 3).

Since your print statements are nested in the {} only the most recently declared variable a is printed, getting your results.

Trisped
  • 5,705
  • 2
  • 45
  • 58
1

Whenever you declaring a variable inside a loop, which is not available outside (out of scope for that variable ). So in your code

 void myproc()
{
    int a = 2;
    while (a == 2)
    {
        int a = 3;// This is not accessable to outside while loop. 
        printf("a = %d\t", a);
        break;
    }
    printf("a = %d\t", a);
}

If you want to print 3, 3, 1 remove int inside while loop :)

duslabo
  • 1,487
  • 4
  • 20
  • 33
1

Actually, the loop is a significantly convenient obfuscator here.

Consider the while loop's test. This test is run twice during the execution of the program, and the first time the test succeeds, as the a it is examining has the value 2. The second time it is run, the test fails, because the a it is testing is a different a, which hold the value 3! This is very surprising.

Given my colleagues explanations, the three declarations of a exist in only their enclosing '{' and '}' delimited scopes (or the world scope for the first one). If this were literally true, then the while (a == 2) test should pass forever, as the interior a declaration assigned to the value 3 is completely hidden from it by the '{' and '}'

int a = 1;         // world scope - a is 1
myproc() 
 {                 // New scope; can define names inside here
  int a = 2;       // Redefine a to be 2
  while ( a == 2 ) // We test whether a is 2
  {                // New scope; can define names inside here 
    int a = 3;     // Redefine a to be 3  
  }                // end of scope, the a = 3 disappears; also branch back to top of loop
 }                 // end of myprog scope, so the a=2 disappears

The way to understand this is to realize that the while (test) { statements; } is actually implemented as:

if ( test ) {      // T1
   L1: {
      statements;
      if ( test )  // T2 
          goto L1;
   }
} 

and so in truth, the test statement is replicated, and the first one 'T1' is executed in the scope outside of the '{' and '}' and gets the a that is 2, and passes; and the second one 'T2' is executed inside the scope of the '{' and '}' and gets the a that is 3 and the test fails.

Given your statements, the second test uses its locally scoped definition of a which is 3, so the loop is exited after one pass.

Mac
  • 299
  • 2
  • 5