Jeegar Patel
Jeegar Patel

Reputation: 27210

how free() works?

#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

Answers (4)

David Heffernan
David Heffernan

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

Jerry Coffin
Jerry Coffin

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

Chris Lutz
Chris Lutz

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 freed 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

Owen
Owen

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

Related Questions