F. Zer
F. Zer

Reputation: 1279

Freeing a pointer inside a function, and using it in main

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

char* test() {
    char* s = "Hello World";
    size_t len = strlen(s);
    char* t = malloc(sizeof(char)*(len+1));
    strcpy(t, s);
    free(t);
    return t;
};

int main(void) {
    printf("%s\n", test());
    return 0;
};

I would like to allocate and de-allocate memory inside the function. I tested this code and works, but I am wondering:

Upvotes: 2

Views: 1118

Answers (3)

Luis Colorado
Luis Colorado

Reputation: 12668

It doesn't matter where do you free() a pointer. Once it is free()d, the pointer is not deferrenciable anymore (neither inside nor ouside the function where it was free()d)

The purpose of free() is to return the memory allocated with malloc() so the semantics are that, once you have freed a chunk of memory, it is not anymore usable.

In C, all parameters are passed by value, so free() cannot change the value expression you passed to it, and this is the reason the pointer is not changed into an invalid pointer value (like NULL) but you are advised that no more uses of the pointer can be done without incurring in Undefined Behaviour.

There could be a solution in the design of free() and it is to pass the pointer variable that holds the pointer by address, and so free() would be able to turn the pointer into a NULL. But this not only takes more work to do, but free() doesn't know how many copies you have made of the value malloc() gave to you... so it is impossible to know how many references you have over there to be nullified. That approach makes it impossible to give free() the responsibility of nullifying the reference to the returned memory.

So, if you think that free doesn't turn the pointer into NULL and for some strange reason you can still use the memory returned, don't do it anymore, because you'll be making mistakes.

You are adviced! :)

Upvotes: 1

Eric Postpischil
Eric Postpischil

Reputation: 222372

malloc reserves memory for use.

free releases that reservation. In general, it does not make the memory go away, it does not change the contents of that memory, and it does not alter the value of the pointer that held the address.

After free(t), the bytes of t still contain the same bit settings they did before the free. Then return t; returns those bits to the caller.

When main passes those bits to printf, printf uses them as the address to get the characters for %s. Since nothing has changed them, they are printed.

That is why you got the behavior you did with this program. However, none of it is guaranteed. Once free was called with t, the memory reservation was gone. Something else in your program could have used that memory. For example, printf might have allocated a buffer for its own internal use, and that could have used the same memory.

For the most part, malloc and free are just methods of coordinating use of memory, so that different parts of your program do not try to use the same memory at the same time for different purposes. When you only have one part of your program using allocated memory, there are no other parts of your program to interfere with that. So the lack of coordination did not cause your program to fail. If you had multiple routines in your program using allocated memory, then attempting to use memory after it has been released is more likely to encounter problems.

Additionally, once the memory has been freed, the compiler may treat a pointer to it as if it has no fixed value. The return t; statement is not required to return any particular value.

Upvotes: 2

dbush
dbush

Reputation: 223719

Once you call free on a pointer, the memory it pointed to is no longer valid. Attempting to use a pointer to freed memory triggers undefined behavior. In this particular case it happened to work, but there's no guarantee of that.

If the function returns allocated memory, it is the responsibility of the caller to free it:

char* test() {
    char* s = "Hello World";
    size_t len = strlen(s);
    char* t = malloc(sizeof(char)*(len+1));
    strcpy(t, s);
    return t;
};

int main(void) {
    char *t = test();
    printf("%s\n", t);
    free(t);
    return 0;
};

Upvotes: 4

Related Questions