Same memory space allocated again & again

In each iteration of the loop, the variable j is declared again and again. Then why does his address remain the same ?

  • Should you give a random address every time?
  • Is this compiler dependent?
#include<stdio.h> #include<malloc.h> int main() { int i=3; while (i--) { int j; printf("%p\n", &j); } return 0; } 

Testrun: -

 shadyabhi@shadyabhi-desktop :~/c$ gcc test.c shadyabhi@shadyabhi-desktop :~/c$ ./a.out 0x7fffc0b8e138 0x7fffc0b8e138 0x7fffc0b8e138 shadyabhi@shadyabhi-desktop :~/c$ 
+6
c gcc linux unix
source share
11 answers

The reason why the address j never changes is because the compiler allocates memory for j on the stack when the function is introduced, and not when j enters the scope.

As always, looking at the assembly code can help explain the concept. Take the following function: -

 int foo(void) { int i=3; i++; { int j=2; i=j; } return i; } 

gcc converts it to the following x86 build code: -

 foo: pushl %ebp ; save stack base pointer movl %esp, %ebp ; set base pointer to old top of stack subl $8, %esp ; allocate memory for local variables movl $3, -4(%ebp) ; initialize i leal -4(%ebp), %eax ; move address of i into eax incl (%eax) ; increment i by 1 movl $2, -8(%ebp) ; initialize j movl -8(%ebp), %eax ; move j into accumulator movl %eax, -4(%ebp) ; set i to j movl -4(%ebp), %eax ; set the value of i as the function return value leave ; restore stack pointers ret ; return to caller 

Skip this build code. The first line saves the current pointer to the base pointer so that it can be restored when the function ends, the second line sets the current top of the stack as the new base stack pointer for this function.

The third line is the one that allocates memory on the stack for all local variables. The subl $8, %esp instruction subtracts 8 from the current top of the stack pointer, esp register. Stacks grow in memory, so this line of code actually increases memory on the stack by 8 bytes. There are two integers in this function: i and j , each of which requires 4 bytes, so it allocates 8 bytes.

Line 4 initializes i to 3 by writing directly to the address on the stack. Lines 5 and 6 are then loaded and incremented i . Line 7 initializes j by writing the value 2 to the memory allocated for j on the stack. Note that when j fell into scope on line 7, the assembly code did not configure the stack to allocate memory for it that had already been taken care of.

I'm sure this is obvious, but the reason the compiler allocates memory for all local variables at the beginning of the function is because it is more efficient for this. Setting the stack every time a local variable is turned on or out of scope would lead to many unnecessary manipulations with the stack pointer without amplification.

I'm sure you can decide what the rest of the assembly code does if you don't leave a comment and I will guide you through it.

+6
source share

This is the memory on the stack. He does not stand out from the heap. The stack will not change in this loop.

+12
source share

Why should it be any different? The compiler needs space on the stack to store int, and each time it passes through the loop, the same space is available.

By the way, you do not use malloc at all. j is stored on the stack.

+6
source share

j and I are allocated on the stack, not on the heap or freestore (which requires malloc or new, respectively). The stack places the next variable in a deterministic location (the top of the stack), and therefore it always has the same address. Although, if you are working in optimized mode, the variable will probably never be "canceled", i.e. The stack size does not change throughout your program, because it will just be wasted.

+4
source share

j is allocated on the stack, so during one call to this function it will always have the same address.

If you called main() from this loop, the "internal" main j would have a different address, since it would be higher on the stack.

For more information, see Hardware Stack on Wikipedia.

+2
source share

You are not actually using malloc , so what's the problem?

This variable is local to this function, and its space is reserved on the stack at compile time .. so why redistribute it at each iteration? Just because it is declared inside a loop?

+2
source share

You are not malloc-ing. Its stack address is also unchanged, because it is always in the same place on the stack once and again.

+1
source share

It is declared in the loop, as you say, but it goes out of scope and is "destroyed" at the end of each iteration (that is, it is not in scope and does not exist when checking the conditions of the loop), Therefore, it is absolutely correct that the same thing the stack location can be reused (in fact, it would be a mistake if it weren’t).

+1
source share

Hint: What do you think this will do?

 #include<stdio.h> #include<malloc.h> int main() { int i=3; while (i--) { int j = 42; printf("%p\n", &j); } return 0; } 
0
source share

As the other answers said, you are not allocating anything here except the stack. But even if you change the code as follows, it does not necessarily change the distribution address.

It depends on the libc used, usually malloc is located there, but some applications (primarily firefox) redefine it for use (memory fragmentation problems, etc.).

 #include<stdio.h> #include<malloc.h> int main() { int i=3; while (i--) { int *j = (int *) malloc(sizeof(int)); printf("%p\n", j); free (j); } return 0; } 

if you comment out the free (j), you will notice that the j-address has changed. But depending on your libc, the j address can always change.

0
source share

Now you will get a series of leaks, since j is not saved for subsequent free ones. j will not necessarily receive a random address, but probably just as a sequence compared to previous j allocations.

If you free j at the end of the loop, you can get the same behavior as before, depending on the malloc implementation and for free.

Edit: you can double-check printed values ​​with this code.

-one
source share

All Articles