Reputation: 27210
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int * ptr;
printf("before malloc pointer is :%p \n",ptr);
printf("before malloc valu is :%d \n",*ptr);
ptr = malloc(sizeof(int));
printf("after malloc pointer is %p \n",ptr);
printf("after malloc valu is :%d \n",*ptr);
int jig=32;
*ptr = jig;
printf("after assignment valu is : %d\n",*ptr);
free(ptr);
printf("after free %p \n",ptr); // after free pointer holds sane address then
printf("after fee is %d\n",*ptr); // why it coudnt print that???
return 0;
}
output is :
before malloc pointer is :0x6edff4
before malloc valu is :7265660
after malloc pointer is 0x9a52008
after malloc valu is :0
after assignment valu is : 32
after free 0x9a52008
after fee is 0
after free still pointer holds the address of that memory then why we can not print that memory's value.??
what does free() do.?
does it just make all memory as 0 ..??
Upvotes: 1
Views: 2636
Reputation: 612864
free
returns the memory to the system. It is the partner operation to malloc
. Everything block of memory that you allocate with malloc
should be returned to the system by calling free
. After you call free
you are no longer allowed to access that memory.
It's generally considered wise to set the pointer to NULL
after you have called free
, at least in debug builds, so that you can be sure that an error will be raised if you later attempt to dereference the pointer by mistake.
So, why can you still access memory that has been freed? Well, you can't reliably do so. It just so happens that the implementation of most memory management systems mean that you can sometimes get away with such abuses. Many memory managers allocate large blocks of memory from the operating systems and then, in turn, allocate small sub-blocks to the application. When you call free
, the allocator returns that block back to its pool of readily available memory, but does not necessarily give the memory back to the OS, since OS memory allocation routines are typically expensive. Hence accessing it may still appear to work, because the memory is still allocated in your process. It's just that its now owned by the memory manager rather than by your app. Something like that is happening to you here.
Of course, sometimes you won't get away with abuses like this, most likely once you have deployed your software onto your most important client's machine!
Upvotes: 3
Reputation: 490108
Typically the memory manager will have something like a linked list of free blocks that are used to satisfy subsequent allocations.
Here's a minimal implementation I wrote several years ago. It's not really intended (or suitable) for serious use, but gives at least some general notion of one way to manage a heap:
#include <stddef.h>
typedef struct node {
size_t size;
struct node *next;
} node;
node *free_list;
static void *split_end(node *block, size_t new_size) {
size_t difference = block->size - new_size;
node *temp = (node *)((char *)block + difference);
temp->size = new_size;
block->size = difference;
return (void *)((size_t *)temp+1);
}
static void *split_begin(node *block, size_t new_size) {
size_t difference = block->size-new_size;
node *temp = (node *)((char *)block + new_size);
temp->size = difference;
temp->next = free_list;
free_list = temp;
return block;
}
void b_init(void *block, size_t block_size) {
((node *)block)->size = block_size - sizeof(node);
((node *)block)->next = NULL;
free_list = block;
}
void b_free(void *block) {
node *b = (node *)((size_t *)block -1);
b->next = free_list;
free_list = b;
}
void *b_malloc(size_t size) {
node *temp, **ptr;
size_t larger = size+sizeof(node);
size += sizeof(size_t);
for ( ptr = &free_list;
NULL != ptr;
ptr = &((*ptr)->next))
{
if ((*ptr)->size >= size) {
if ( (*ptr)->size <= larger) {
temp = (*ptr);
(*ptr) = (*ptr)->next;
return (void *)((size_t *)temp + 1);
}
else
return split_end(*ptr, size);
}
}
return NULL;
}
void *b_realloc(void *block, size_t new_size) {
node *b = (node *)((char *)block - sizeof(size_t));
char *temp;
size_t i, size;
if ( new_size == 0) {
b_free(block);
return NULL;
}
new_size += sizeof(size_t);
size = b->size;
if ( new_size <size)
size = new_size;
size -= sizeof(size_t);
if ( b->size >= new_size+sizeof(node *) )
return split_begin(b, new_size);
if ( b->size >= new_size)
return b;
temp = b_malloc(new_size);
if ( NULL == temp)
return NULL;
for ( i=0; i<size;i++)
temp[i] = ((char *)block)[i];
b_free(block);
return temp;
}
#ifdef TEST
#define num 10
int main(void) {
int i;
char block[4096];
char *temp[num];
char *big;
b_init(block, sizeof(block));
big = b_malloc(100);
for (i=0; i<num; i++)
temp[i] = b_malloc(10);
for (i=0; i<num; i++)
b_free(temp[i]);
b_realloc(big, 200);
b_realloc(big, 10);
b_realloc(big, 0);
return 0;
}
#endif
Upvotes: 1
Reputation: 75389
after free still pointer holds the address of that memory then why we can not print that memory's value.??
Because the memory no longer belongs to you. You free
d it, which means the OS is allowed to reuse it however it sees fit, wherever it needs to allocate more memory. You no longer own it, therefore you no longer have any business looking at the value of the data held by that memory.
Note also that:
int *ptr;
...
printf("Before malloc valu is :%d\n", *ptr);
is equally invalid. ptr
holds a garbage value, and can point anywhere. Dereferencing it is not guaranteed to be a memory location you can access.
Both of these cases invoke undefined behavior, which means the standard says, "DON'T DO THIS," and if you ignore the standard your code will break in horrible ways whenever your boss is looking.
what does free() do.?
does it just make all memory as 0 ..??
No, not necessarily. The OS often zeroes out unused memory in the background to make calls to calloc
faster, but free
only tells the operating system "I'm done with this memory, do whatever you need to with it." The OS typically updates some housekeeping data to indicate that the block of memory is no longer owned by a process, so that a later call to malloc
can use it if it's needed.
Upvotes: 4
Reputation: 39356
The interesting thing about malloc()
and free()
is that they don't actually change the memory they give you -- they just change how it's "thought of".
When you call malloc(), a segment of memory is chosen and dedicated to be yours. While it's yours you can use it how you like.
When you're done with it you free()
it -- but it's still there. It's still the same memory[1], it's just not considered "yours" anymore. So someone else might be using it.
[1] I supposed with virtual addressing this might not be always true. But it's usually true.
Upvotes: 3