Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Block Structure memory allocation for variables

Tags:

c++

c

for(int i=0;i<10;i++)
{
  int x=0;
  printf("%d",x);
   {
     int x=10;
     printf("%d",x);
   }
  printf("%d",x);
}

Here I want to know if memory for variable x will be allocated twice or is the value just reset after exiting the 2nd block and memory is allocated only once (for x) ?

like image 655
Zephyr Avatar asked Dec 19 '22 04:12

Zephyr


2 Answers

From the point of view of the C programming model, the two definitions of x are two completely different objects. The assignment in the inner block will not affect the value of x in the outer block.

Moreover, the definitions for each iteration of the loop count as different objects too. Assigning a value to either x in one iteration will not affect the x in subsequent iterations.

As far as real implementations are concerned, there are two common scenarios, assuming no optimisation is done. If you have optimisation turned on, your code is likely to be discarded because it's quite easy for the compiler to figure out that the loop has no effect on anything outside it except i.

The two common scenarios are

  1. The variables are stored on the stack. In this scenario, the compiler will reserve a slot on the stack for the outer x and a slot on the stack for the inner x. In theory it ought to allocate the slots at the beginning of the scope and deallocate at the end of the scope, but that just wastes time, so it'll reuse the slots on each iteration.

  2. The variables are stored in registers. This is the more likely option on modern 64 bit architectures. Again, the compiler ought to "allocate" (allocate is not really the right word) a register at the beginning of the scope and "deallocate" at the end but, it'll just reuse the same registers in real life.

In both cases, you will note that the value from each iteration will be preserved to the next iteration because the compiler uses the same storage space. However, never do this

for (int i = 0 ; i < 10 ; ++i)
{
    int x;
    if (i > 0)
    {
        printf("Before %d\n", x); // UNDEFINED BEHAVIOUR
    }
    x = i;
    printf("After %d\n", x);
}

If you compile and run the above (with no optimisation), you'll probably find it prints sensible values but, each time you go round the loop, x is theoretically a completely new object, so the first printf accesses an uninitialised variable. This is undefined behaviour so the program may give you the value from the previous iteration because it is using the same storage or it may firebomb your house and sell your daughter into slavery.

like image 198
JeremyP Avatar answered Dec 24 '22 01:12

JeremyP


Setting aside compiler optimization that might remove these unused variables, the answer is twice.

The second definition of x masks (technical term) the other definition in its scope following its declaration. But the first definition is visible again after that scope. So logically (forgetting about optimization) the first value of x (x=0) has to be held somewhere while x=10 is 'in play'. So two pieces of storage are (logically) required.

Execute the C program below. Typical partial output:

A0 x==0 0x7ffc1c47a868
B0 x==0 0x7ffc1c47a868
C0 x==10 0x7ffc1c47a86c
D0 x==0 0x7ffc1c47a868
A1 x==0 0x7ffc1c47a868
B1 x==0 0x7ffc1c47a868
C1 x==10 0x7ffc1c47a86c
//Etc...

Notice how only point C sees the variable x with value 10 and the variable with value 0 is visible again at point D. Also see how the two versions of x are stored at different addresses. Theoretically the addresses could be different for each iteration but I'm not aware of an implementation that actually does that because it is unnecessary. However if you made these non-trival C++ objects their constuctors and destructors would get called on each loop though still reside at the same addresses (in practice).

It is obviously confusing to human readers to hide variables like this and it's not recommended.

#include <stdio.h>

int main(void) {
    for(int i=0;i<10;i++)
    {
        int x=0;
        printf("A%d x==%d %p\n",i,x,&x);
        {
            printf("B%d x==%d %p\n",i,x,&x);
            int x=10;
            printf("C%d x==%d %p\n",i,x,&x);
        }
        printf("D%d x==%d %p\n",i,x,&x);
    }
}
like image 37
Persixty Avatar answered Dec 24 '22 01:12

Persixty