Home > Software design >  free of malloc inside the function, how to do that?
free of malloc inside the function, how to do that?

Time:05-05

I create the malloc inside str function and i want to free this malloc variable

#include <stdio.h>

char *str(void)
{
    // create the malloc
    char *string = malloc(2); // how to free it
    *(string   0) = 'J';
    *(string   1) = 'O';
    // return the malloc
    return string;
}

int main(void)
{
    // print the function
    printf("%s, str());
    return 0;
}

CodePudding user response:

free(string)

would free it. But to print it as a string you must have the \0 in the end.

Note: You should not free it inside the function if your plan is to return it at the end of the function call. Since that would potentially give rise to undefined behavior.

Correct way of doing things:

char *str(void)
{
    // create the malloc
    char *string = malloc(3); // how to free it
    if(string){
       *(string   0) = 'J';
       *(string   1) = 'O';
       *(string   2) = '\0';
    // return the malloc
    }
    return string;
}

int main(void)
{
    // print the function
    char *s = str();
    if(s)
       printf("%s", s);
    free(s);
    return 0;
}

Incorrect

If you do this, then it would be a memory leak:

int main(void)
{
    // print the function
    printf("%s", str());
    return 0;
}

And if you do this, then you have undefined behavior when you try to print it out.

char *str(void)
{
    // create the malloc
    char *string = malloc(2); // how to free it
    *(string   0) = 'J';
    *(string   1) = 'O';
    // return the malloc
    free(string);
    return string;
}

int main(void)
{
    // print the function
    printf("%s", str()); // undefined behavior. A dragon might appear.
    return 0;
}

CodePudding user response:

Usually it is better alternative to let the caller provide the buffer to print to; if printing actually was successful could be hinted to via a return value; a new function signature might then look like this:

#include <stdbool.h>

bool str(size_t length, char buffer[length])
{
    if(length < 3)
    {
        // buffer is too short...
        return false;
    }

    buffer[0] = 'J';
    buffer[1] = 'O';
    buffer[2] = 0; // terminating null character, which you ommitted!
}

Note that the length specifier in the array parameter is ignored (function parameters only!), the definition is equivalent to char buffer[] or char* buffer; still specifying the length can serve to tell a user what kind of parameter actually is expected (-> self documenting code); note, too, that this only applies for the outer-most dimenstion (in char[12][10] the 12 is ignored but not the 10, the parameter type is equivalent to char(*)[10] which is a pointer to an array of length 10).

A user then is free where to allocate the string, dynamically on heap or on stack:

int main(void)
{
    char stack[3];
    if(str(sizeof(stack), stack))
    {
        printf("%s", stack);
    }

    size_t len = 3;
    char* heap = malloc(len);
    if(!heap) // should always be checked!
    {
        // allocation failed!
        return -1; 
    }
    if(str(len, heap))
    {
        printf("%s", heap);
    }

    free(heap);

    return 0;
}

If you still want to retain the original signature then you need the returned string twice, once to print it, once to free it – i.e. you need to store it in an intermediate variable to be able to do so:

int main(void)
{
    char* s = str(); // store it in a variable!
    printf("%s", s); // still need to append the null terminator for!!!
    free(s); // now you can free it

    return 0;
}

If you don't append the null terminator then you need to explicitly limit the number of characters to print to console:

printf("%.2s", s);
//       ^^  (!)
  •  Tags:  
  • c
  • Related