2

Let suppose to have a function f such that it includes, in its body, the declaration of a new variable, b. I have noticed that every time f is invoked, the variable b - that should be every time created and destroyed (EDIT: not in the dynamic case, as pointed out by another (now solved) related question) - has always the same memory address.

The following very simple code shows you an example:

#include <stdio.h>
#include <stdlib.h>

void f ( void ){
   int b;
   printf ("%p\n", &b);
}

int main (){
    int i = 0;
    while (++i <= 10)
        f();
return 0;
}

Output: (always the same memory address).

Is it possible to modify f in such a way that at each call it creates b always with new memory address, differently from every previous calling?

EDIT: some users suggested using a dynamic allocation of the memory, but unfortunately I still did not manage to solve the problem.

You may ignore the premise and look directly at my new formulation of the problem.

Let's consider the following code.

#include <stdio.h>
#include <stdlib.h>

void f ( void ){
   int * b = malloc ( sizeof(int) );
   printf ("%p\n", &b);
}

int main (){
   int i = 0;

   while (++i <= 10)
      f();
return 0;
}

Why does it produce always the same output?

As you may easily imagine, my experience with C is limited. Every suggestion and/or reference for learning more is very welcome.

Thanks

Pss: I need to solve this problem as a step before creating some dynamics structure data, as lists or trees. The idea is that every time we add a node, the new node must refer to a new memory address in order to avoid loops. On my book there is written that a solution is to use the malloc instruction, and I am trying to fully understand why.

Biagio
  • 131
  • 1
  • 6
  • 5
    May I ask why do you need that? – Sourav Ghosh Dec 20 '15 at 13:03
  • 1
    Passing `&b`, which is type `int*` to the `%p` format, which calls for `void*`, is undefined behavior. – MikeCAT Dec 20 '15 at 13:07
  • I don't see anything like the programs's output in your question, and what is `f` to modify? – MikeCAT Dec 20 '15 at 13:08
  • If you want to manage the addresses of variables yourself, then you should call `malloc` to allocate them (and `free` to free them when you're done). As long as you haven't freed a given variable, then any new variable allocated by `malloc` will have a different address. – Tom Karzes Dec 20 '15 at 13:09
  • Prehaps the quotation "Is it possible to modify f in such a way that at each call it creates b always with new memory address, differently from every previous calling?" is the output of this undefined behavior? How lucky you are! – MikeCAT Dec 20 '15 at 13:09
  • 1
    @MikeCAT Technically it is but this is one of the few situations where I disagree with the standard. That works and is going to work in the future on all platforms where all pointers have equal representation (i.e. almost all platforms you are ever going to see). – fuz Dec 20 '15 at 13:20
  • Are you looking for https://en.wikipedia.org/wiki/Address_space_layout_randomization – technosaurus Dec 20 '15 at 14:13
  • @technosaurus: ASLR primarily refers to where shared libraries are loaded, and maybe to where the stack is placed. It isn't really applicable to this example. – Jonathan Leffler Dec 20 '15 at 16:58
  • 1
    Your edit is almost there, just leave out the `&b` in the printf! – Dylan Kirkby Dec 20 '15 at 17:22

3 Answers3

4

The behavior you are observing is the result of stack frames being created and recycled. When f() is called repeatedly in your while loop, four things happen:

  1. The memory management unit fetches a chunk of memory for it on the stack to hold its arguments, local variables, and return value.

  2. The local variable b is declared in this stack frame, and as it is uninitialized it contains "garbage data" (say 0xDEADBEEF for this example).

  3. f() returns and its stack frame is recycled by moving the "Top of Stack" pointer is moved up to the main() stack frame. Note that the contents of the stack frame for f() are never cleared or zeroed out

  4. The function f() is immediately called again, so a chunk of memory is fetched. This is the exact same chunk as was fetched by the first call of f() (go ahead and check by printing the address of b). Since b is uninitialized, it contains "garbage data", but it is the same "garbage data" (0xDEADBEEF) that was in the first call of f() since the location has not been written to since.

Stack Frame Illustration

Allocating storage on the heap using malloc may not fix this problem though! A call to malloc() followed by a free() followed by another call to malloc() will give you the same address on the heap yet again as demonstrated by this test program:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    char *ptr1 = malloc(sizeof(char));
    printf("Allocated memory at %p\n", ptr1);

    free(ptr1);
    printf("Freed memory at %p\n", ptr1);

    char *ptr2 = malloc(sizeof(char));
    printf("Allocated memory at %p\n", ptr2);

    free(ptr2);
    printf("Freed memory at %p\n", ptr2);

    if (ptr1 == ptr2) {
        printf("Pointers were the same!\n");
    }

    return 0;
}

Which prints out:

Allocated memory at 0x7f9c49404bf0 Freed memory at 0x7f9c49404bf0 Allocated memory at 0x7f9c49404bf0 Freed memory at 0x7f9c49404bf0 Pointers were the same!

So I think the answer to your question is really no, you cannot modify f() such that b is assigned a different address at every call unless you malloc it in each call of f() without following it with a free() call (which is a memory leak). This makes sense though, because if you require a different address for each local variable, you are requiring memory to be blocked off (leaked) after each use. Allocated memory is freed at the end of main() automatically, but you could imagine if you looped much much more than 10 times, you could burn through your process memory.

This code looks like this:

#include <stdio.h>
#include <stdlib.h>

void f (void){
   int *b = malloc (sizeof(int));
   printf ("%p\n", b);
}

int main (){
   int i = 0;

   while (++i <= 10)
      f();
   return 0;
}

Very close to what you had but since b is an address, you can just print b, not &b

Edit: image credit to https://andrewharvey4.wordpress.com/tag/avr/

Dylan Kirkby
  • 1,427
  • 11
  • 19
  • I am really grateful for the complete detailed explanation - it helped me a lot. And for the finally "&"...thanks, I bet I would have spent hours otherwise. Have a nice day! – Biagio Dec 20 '15 at 17:36
1

The address of an automatic variable depends on the value of the stack pointer on function entry and is going to be a fixed offset from that. If you call a function in a loop like this:

while (...) {
    ...
    f(...);
    ...
}

It's very likely that the compiler generates code in a way that f's automatic variables always have the same addresses. This is something you cannot easily alter.

If we do not use automatic variables, we can get the desired result easily. Just allocate a new variable in f each time. Of course, this leaks a lot of memory, but there isn't any better way as f has to remember the addresses already used for b either way if you want b to reside at a different address each time and the addresses previously used are unusable (and thus wasted) for this purpose.

fuz
  • 88,405
  • 25
  • 200
  • 352
1

Maybe what you are looking for is dynamic memory allocation? You might want to read the docs for malloc, calloc, realloc and free (prototyped in <stdlib.h>.)

Technically, there's a storage class associated with each object. For automatic variables like f this is automatic and is commonly allocated on the stack (but there are also stack-less machines). For dynamically allocated objects the storage class is dynamic and it is commonly allocated from the heap (but there are also heap-less machines).

In essence you should not rely on addresses having a specific pattern or value.

Jens
  • 69,818
  • 15
  • 125
  • 179