views:

274

answers:

7

I have the following C-code:

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

typedef struct node
{
    int a;
}node;

int main()
{
    node * n;

    printf("\n%d\n",n->a);

    n  = (node *) malloc ( sizeof( node ));

    printf("\n%d\n",n->a);
    n->a = 6;
    printf("\n%d\n",n->a);
    free(n);
    printf("\n%d\n",n->a);
    n->a = 4;
    printf("\n%d\n",n->a);
    return 0;
}

Output obtained is :

1314172

0

6

0

4

My question is even after free(n) , why does n->a = 0 and how can we also reassign it to any value like n->a = 4 ?

Doesn't free make the memory block pointed to by n invalid ??

+16  A: 
free(n);
n->a = 4; // is not guaranteed to work, might crash on some implementations

Invokes Undefined Behaviour.

why does n->a = 0 and how can we also reassign it to any value like n->a = 4 ?

Thats because Undefined Behaviour means anything can happen. You can't rely on that.

P.S : Don't write such code.

EDIT :

As Jonathan noticed your code invokes Undefined Behavior long before you free() and then dereference n.

node * n; //n is not initialized
printf("\n%d\n",n->a);  //dereferencing a wild pointer invokes UB.
Prasoon Saurav
+1 Indeed. free() will release the allocated space so it can be reallocated again by some other operation, but it doesn't necessary cleans that memory space. So on your example, I believe that what you print after free() is actually just trash left by previous operations on that memory space.
karlphillip
The code runs into undefined behaviour long before the `free()`; the first `printf()` dereferences an uninitialized pointer.
Jonathan Leffler
@Jonathan Leffer : Thanks, edited my post. :-)
Prasoon Saurav
+4  A: 

No, free may or may not do anything to the associated memory. Referencing it is invalid though. Other processes/your process may have overwritten the memory, or if you're unlucky, the data might be just as you'd left it.

It's up to you to make sure you don't reference free'd memory.

Salgar
+4  A: 

When you dereference a pointer to unallocated memory, the behaviour is undefined. This means that it could do anything. It might trigger an error, or it might do something else.

In most cases, if you free some memory, that memory is not immediately re-used, and is not immediately reclaimed by the Operating System. This means that the memory is still accessible to your application and will still contain its previous values. You can often read or write to it without errors, but you must not rely on this behaviour.

If you ran this code in a number of different environments, you would find that in some environments it always works, in some it always triggers an error, but that in many others it works ‘most of the time’. This makes C quite difficult to debug! :)

Daniel Cassidy
+1  A: 

the memory block is released. That doesnt mean that you cannot write to it; it means that you must not write to it. The machine will not stop you doing it (usually, there are some tools like electric fence that will prevent it)

As you will find in the future ; you will end up doing this accidentally a lot; and usually Bad Things (tm) will happen

pm100
+13  A: 

Reusing a freed pointer is similar to making a copy of a key for a car you rented, returning the car, and then trying to use that key to get in the car after you have returned the car to the rental place. You might be able to get away with it, but you shouldn't be doing it and very often it will get you in trouble.

nategoose
+1 cool analogy
TokenMacGuy
A: 

On most operating systems targeted at hardware with an MMU (such as x86), the only way to actually get an error for a memory read is if the application address is unmapped. Since the MMU doesn't have an entry that tells it where to find in physical memory the data associated with the logical address the application asked for, it causes an interrupt and the operating system takes over, to do something about it.

But most operating systems don't do much to manage memory on behalf of the application, except to give it a contiguous chunk of memory of the desired size. The operating system doesn't allow the applications to muck about in the MMU, either, since most MMU's aren't quite smart enough to let applications do things safely without affecting other programs negatively (either by accident or malice).

So when you malloc() something, if your app doesn't already have a place to put that in its existing address space, it asks the operating system for more, but when you later free() it, unless that happens to be at the very end of the address space for your app, you can't give it back to the operating system to make that memory area cause an error when you try to read it.

There are some ways to get that, for instance, with mmap(), but that's not really the right reason to use that function.

TokenMacGuy
Partially untrue. It doesn’t have to be at the ‘end’ of the application’s address space. On x86, for example, the OS can reclaim any aligned 4kB block (‘page’). Part of the purpose of virtual memory is to hide this kind of memory fragmentation from the application. (Actually on x86 the OS can choose from various page sizes, but 4kB is the most common).
Daniel Cassidy
While the hardware and operating system support it, in practice, most allocators (for instance, the one in glibc), don't actually avail themselves of it. There's nothing stopping an application from using an allocator that does this, though. All three layers need to cooperate to make that sort of thing work.
TokenMacGuy
A: 

Most of the OS will allocate a certain minimum space that will be equal to or greater than the space you requested. Once you call free, this space will not go back to the OS, instead kept with you for future reuse. Hence, you can get away with something like what you have written above.

But on a strict note, this is categorized as "Undefined" behavior. But you can get away with it most of the times. Just don't make a habit off it ;)

allajunaki
"don't make a habit" of writing to freed memory? I think it would be more appropriate to say "don't ever, EVER, do that". It's insanity to think you can rely on undefined behaviour.
filipe
well, I said that on a lighter note. If someone writes data they need to freed memory in a production code (other than perhaps for some random data or something similar), then they really do not fit in a development team ;) You are right, its pure insanity to use a freed memory for anything practical. But then again, here we are with that exact situation, with a working code (though in an in-deterministic way).
allajunaki