2
char **loadValues()
{
    char **toReturn;
    int i;
    toReturn = malloc(5 * sizeof(char *));
    for (i = 0; i < 5; i++)
    {
        toReturn[i] = malloc(25);              //Change the size as per your need
        strncpy(toReturn[i], "string", i + 1); //Something to copy
    }
    return toReturn;
}

I copied above part of the code. In it, the "toReturn" variable is initialized by using malloc. Don't we have to "free" this "toReturn" variable?

Don't we have to free these variables when we return them in C. I still couldn't find a clear answer and I can't find a way to free it when I return it. Can someone explain it to me?

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • You don't have to use `free()` if you are on modern OS and don't use `loadValues()` too many times. [c - What REALLY happens when you don't free after malloc? - Stack Overflow](https://stackoverflow.com/questions/654754/what-really-happens-when-you-dont-free-after-malloc) Another condition is that you don't have to satisfy checkers like Valgrind. – MikeCAT Mar 27 '21 at 20:01
  • 2
    Freeing what to return is a bad idea because returning means it will be used later and using freed buffer is illegal. – MikeCAT Mar 27 '21 at 20:02
  • 1
    That's like giving your previous phone number to someone asking for your number – klutt Mar 27 '21 at 20:06
  • 3
    Aside: a hidden danger. Function `strncpy()` does not supply a null terminator if it reaches the `count` limit, and `malloc()` does not initialise the memory it gives. So no terminator. – Weather Vane Mar 27 '21 at 20:10
  • Thank you all. I learned more things. – Kavishka Madhushan Mar 28 '21 at 13:50

3 Answers3

3

You cannot free the allocated memory inside the function and return that data so that it can be used outside the function. But you still can free() the memory outside the function.

AimenZer
  • 86
  • 1
  • 10
3

I assume that your question is: how does the function that calls loadValues and receives the pointer it returns, can free the loaded values.

If we leave loadValues as it is now, the best solution is to create another function, called freeValues and call it when we are done with the values:

void freeValues(char **values)
{
    for (i = 0; i < 5; i++)
    {
        free(values[i]);
    }
    free(values);
}

Then you can do something like this in your main program:

char **values = loadValues();
// ... use values for something
freeValues(values);

Another option, is to allocate toReturn using a single call to malloc, in which case it can be freed simply by calling to free.

Orielno
  • 409
  • 2
  • 8
2

Don't we have to "free" this "toReturn" variable?

Yes, eventually you'd want to free the memory after you're done with it.

I still couldn't find clear answer and I can't find a way to free it when I return it. Can someone explain it to me?

When you use the function you assign it to a new pointer, you can use this pointer, not only to access the memory block you returned, but also to free it, example:

int main()
{
    char** values = loadValues();
    
    // do something with values

    // don't need them anymore
    for (int i = 0; i < 5; i++){
        free(values[i]);
    }
    free(values);
}

Note that strncpy(toReturn[i], "string", i + 1); is likely not what you want, in each iteration you are copying only from 1 to 5 characters respectively, not the entire string, and more importantly, not the null terminator.

The third argument of strncpy should be the length of "string" plus 1 more byte for the null terminator, so 7 in this case. Alternatively, if want to copy only part of ther string, you have to null-terminate it yourself.

If the goal is to copy the entire string, you can let the compiler do that for you:

//...
toReturn = malloc(5 * sizeof(char *));
for (i = 0; i < 5; i++)
{
    toReturn[i] = strdup("string");  // duplicate string and store it in toReturn[i]
}
//...

Of course you still need to free it yourself like in the first situation.

anastaciu
  • 23,467
  • 7
  • 28
  • 53