views:

130

answers:

7

When I run this code:

#include <stdio.h>

typedef struct _Food
{
    char          name [128];
} Food;

int
main (int argc, char **argv)
{
    Food  *food;

food = (Food*) malloc (sizeof (Food));
snprintf (food->name, 128, "%s", "Corn");

free (food);

printf ("%d\n", sizeof *food);
printf ("%s\n", food->name);
}

I still get

128
Corn

although I have freed food. Why is this? Is memory really freed?

+2  A: 

Freeing memory doesn't necessarily overwrite the contents of it.

Fred Larson
+7  A: 

When you free 'food', you are saying you are done with it. However, the pointer food still points to the same address, and that data is still there (it would be too much overhead to have to zero out every bit of memory that's freed when not necessary)

Basically it's because it's such a small example that this works. If any other malloc calls were in between the free and the print statements, there's a chance that you wouldn't be seeing this, and would most likely crash in some awful way. You shouldn't rely on this behavior.

bobDevil
It is more expensive to catch this kind of error. But if during the debugging phase you are willing to pay that expense (at least on occasional runs) consider using something like Valgrind's memcheck. You'll catch other things too: http://valgrind.org/docs/manual/mc-manual.html
Hostile Fork
+2  A: 

There is nothing like free food :) When you "free" something, it means that the same space is again ready to be used by something else. It does NOT mean filling it up by garbage. Secondly, the pointer value has not changed -- if you are seriously coding you should set a pointer to NULL once you have freed it so that potential junk accesses like this do not happen.

Fanatic23
A: 

In some systems freeing memory will unmap it from the address space and you will get a core dump or equivalent if you try to access it after unallocating it.

In win32 systems (at least up through XP) this is specifically not the case. Microsoft made their memory subsystem on 32 bit Windows purposely linger memory blocks to maintain compatibility with well known MS-DOS applications that used memory after freeing it.

In the MS-DOS programming model there is no concept of mapping or process space so these types of bugs didn't show up as program failures until they were executed as DOS-mode programs under Windows95.

That behavior persisted for 32-bit Windows for over a decade. It may change now that legacy compatibility is being withdrawn in systems such as Vista and 7.

Amardeep
-1: There isn't a system in existence today that implements free by unmapping the memory (except possibly for very large allocations).
Keith Randall
+1 since the point is correct even though Randall is sure no a single existing operating systems unmap the memory — I don't know every OSs, I am not sure __all__ does not unmap... I can believe rather in lazy-unmapping... thus, the memory _could_ be unmapped, or not yet, depending on system activity.
ShinTakezou
+2  A: 

sizeof is a compile-time operation, so memory allocation won't change how it works.

free does not erase memory, it just marks the block as unused. Even if you allocate a few hundred megabytes of memory, your pointer may still not be overwritten (modern computers have lots of RAM). However, after you free memory, you can no longer depend on its value.

See if your development environment has a memory allocation debugging setting -- some have settings to overwrite blocks with something like 0xDEADBEEF when you free them.

Also, you may wish to adopt the habit of setting your pointer to NULL immediately after calling free (to help encourage your program to crash early and loudly).

Seth
+1  A: 

free tells the memory allocator that it can reuse that memory block, nothing else. It doesn't overwrite the block with zeros or anything - luckily, because that could be quite an expensive operation! What it does do is make any further dereferencing of the pointer undefined, but 'undefined' behaviour can very well mean 'do the same thing as before' - you just can't rely on it. In another compiler, another runime, or under other conditions it might throw an exception, or terminate the program, or corrupt other data, so... just DON'T.

Kilian Foth
+1  A: 

There's no such thing as "struct has data" or "struct doesn't have data" in C. In your program you have a pointer that points somewhere in memory. As long as this memory belongs to your application (i.e. not returned to the system) it will always contain something. That "something" might be total garbage, or it might look more or less meaningful. Moreover, memory might contain garbage that appears as something meaningful (remains of the data previously stored there).

This is exactly what you observe in your experiment. Once you deallocated the struct, the memory formerly occupied by it officially contains garbage. However, that garbage might still resemble bits and pieces of the original data stored in that struct object at the moment it was deallocated. In your case you got lucky, so the data looks intact. Don't count on it though - next time it might get totally destroyed.

As far as C language is concerned, what you are doing constitutes undefined behavior. You are not allowed to check whether a deallocated struct "has data" or not. The "why" question you are asking does not really exist in the realm of C language.

AndreyT