1

I've implemented a function that returns a string. It takes an integer as a parameter (age), and returns a formatted string.

All is working well, except from the fact that I have some crazy memory leaks. I know strdup() is the cause of this, but I've tried to research some fixes to no avail.

My code is:

const char * returnName(int age) {

    char string[30];

    sprintf( string, "You are %d years old", age);

    return strdup(string);
}

Valgrind's output is:

==15414== LEAK SUMMARY:
==15414==    definitely lost: 6,192 bytes in 516 blocks
==15414==    indirectly lost: 0 bytes in 0 blocks
==15414==      possibly lost: 0 bytes in 0 blocks
==15414==    still reachable: 0 bytes in 0 blocks
==15414==         suppressed: 0 bytes in 0 blocks

Any help in resolving this memory leak issue is greatly appreciated.

5 Answers5

5

strdup() is essentially equivalent to

char* dup = malloc(strlen(original) + 1);
strcpy(dup, original);

So you need to remember to call free() after you're finished using the string.

const char* name = returnName(20);
/* do stuff with name */
free((void*)name);

If you don't call free(), then of course valgrind reports a leak.

PC Luddite
  • 5,883
  • 6
  • 23
  • 39
  • Asked this below to another user aswell: What if I am printing in a main method as such: `printf("%s", returnName(3));` so there is no variable name such as `name` assosciated when invoking the method - how would I free it? Thanks. –  Oct 19 '15 at 22:19
  • @user2832891 Then, you've caused a memory leak. You need to associate a variable with it so that you can `free` it later. – PC Luddite Oct 19 '15 at 22:23
  • @PCLuddite Did you just made a copy of my Answer ? – Michi Oct 19 '15 at 22:50
  • @Michi I didn't try to, but I can see how you might think that. I changed my example to an earlier edit so that there's some variety. – PC Luddite Oct 19 '15 at 23:44
  • @Michi And in the spirit of fair play, I upvoted your answer. I apologize for any infringement. – PC Luddite Oct 19 '15 at 23:51
  • how can you keep a `const char*` value to a `char*` variable? return type of `returnName(3)` is `const char*` – Forhad Hossain Jul 22 '17 at 05:42
3

From man strdup:

Memory for the new string is obtained with malloc(3), and can be freed with free(3).

So you need to free the space allocated and returned by strdup.

Say you invoke returnName like that:

 const char* str = returnName(3);

After you're done with str you can free it like this:

free((char*) str);

The cast is needed because free expects a non-const void*. This explicit conversion is alright here because returnName actually should return constant data1. Calling free is only a nasty implementation detail here.


1 As discussed with @M.M in the comments to this answer.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
cadaniluk
  • 15,027
  • 2
  • 39
  • 67
  • 1
    What if I am printing in a main method as such: `printf("%s", returnName(3));` so there is no variable name such as `str` assosciated when invoking the method - how would I free it? –  Oct 19 '15 at 22:18
  • `const char* str = returnName(3); printf("%s\n", str);` – cadaniluk Oct 19 '15 at 22:19
  • Was hoping I could avoid explicitly declaring a new variable but I guess that'll have to do. Thanks. –  Oct 19 '15 at 22:21
  • Getting the following error when trying exactly what you typed: `note: expected ‘void *’ but argument is of type ‘const char *’ extern void free (void *__ptr) __THROW;` –  Oct 19 '15 at 22:24
  • @user2832891 `const` pointers can't be `free`d apparently. So you need to return `char*` from your function instead. – cadaniluk Oct 19 '15 at 22:25
  • 1
    The function can still return `const char *`. Const pointers can be freed. You probably meant that pointers to const can't be freed, however you can cast the pointer to `void *` (or `char *`) before calling `free`. – M.M Oct 19 '15 at 22:38
  • @M.M I agree but how can the function return `const char*` then? Conversion from `const T*` to `T*` isn't implicit AFAIK and I (and probably most other C programmers) don't like explicit conversions. – cadaniluk Oct 19 '15 at 22:44
  • Many also don't like using non-const pointers to data that is not supposed to be modified :) – M.M Oct 19 '15 at 22:45
  • @M.M But memory returned by `strdup` can be modified, right? Otherwise you got a point. – cadaniluk Oct 19 '15 at 22:46
  • It can, but OP has intentionally designed his function so that the caller should not modify the returned string. – M.M Oct 19 '15 at 22:52
  • @M.M Yes, seems logical. Then this case, casting `const char*` to `char*` is alright. Will add that! – cadaniluk Oct 19 '15 at 22:53
3

strdup looks something like this:

char *strdup(const char *str){
    size_t n = strlen(str) + 1;
    char *dup = malloc(n);

    if(dup){
        strcpy(dup, str);
    }

    return dup;
}

As you can see there is malloc involved too, which means that at some point after you dynamically allocate that memory using strdup you have to free it after you don't need it any more.

Michi
  • 5,175
  • 7
  • 33
  • 58
1

the cause of the memory leaks is NOT from the call to strdup() but rather because the caller of the posted function is failing to pass the returned pointer to free() when done with the string.

user3629249
  • 16,402
  • 1
  • 16
  • 17
1
const char * returnName(int age) {
    char string[30];
    sprintf( string, "You are %d years old", age);
    return strdup(string);
}

return type of returnName() is const char*. So, you can not hold the returned value to a char* type variable. Hold returned value to a const char* variable and cast it to char* while make memory free

const char* retName = returnName(3);
// Use retName
free((char*)retName);
Forhad Hossain
  • 401
  • 4
  • 18