Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - Freeing memory after strdup()

Tags:

c

memory

I'm doing a lesson from the Learn C the Hard way online course. In the code sample below, I don't understand why the two free() calls are necessary. I thought one would only need to call free() once, because only one malloc() occurs. Could somebody clarify why we need two?

If I comment out free(who->name); then valgrind tells me that I've lost a chunk 'o memory, like so;

LEAK SUMMARY:
definitely lost: 21 bytes in 2 blocks

Here's the code:

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

struct Person {
    char *name;
    int age;
    int height;
    int weight;
};

struct Person *Person_create(char *name, int age, int height, int weight)
{
    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->name = strdup(name);
    who->age = age;
    who->height = height;
    who->weight = weight;

    return who;
}

void Person_destroy(struct Person *who)
{
    assert(who != NULL);

    free(who->name); /* Why this one??! */
    free(who);
}

int main(int argc, char *argv[])
{
    // make two people structures
    struct Person *joe = Person_create(
            "Joe Alex", 32, 64, 140);

    struct Person *frank = Person_create(
            "Frank Blank", 20, 72, 180);

    // destroy them both so we clean up
    Person_destroy(joe);
    Person_destroy(frank);

    return 0;
}
like image 340
Andy J Avatar asked Jul 29 '14 08:07

Andy J


People also ask

Do you need to free after strdup?

Now, strdup() uses malloc() under the hood to automatically allocate the memory for you. However, this means that you must free the memory yourself, after you finish using it! So, simply put, strdup() allocates memory using malloc() , and then copies your source string to the allocated memory.

Does strdup allocate memory?

The strdup() function allocates sufficient memory for a copy of the string str , does the copy, and returns a pointer to it.

What can I use instead of strdup in C?

syntax: char *strndup(const char *s, size_t n); This function is similar to strdup(), but copies at most n bytes. Note: If s is longer than n, then only n bytes are copied, and a NULL ('\0') is added at the end.

What does strdup return?

The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3). The strndup() function is similar, but copies at most n bytes.


1 Answers

strdup(3) is documented as

  The strdup() function returns a pointer to a new string which is a
  duplicate of the string s.  Memory for the new string is obtained
  with malloc(3), and can be freed with free(3).

BTW, as Matt McNabb commented, strdup is standard in Posix, not in the C99 language specification.

Of course free only releases the memory zone that you pass it (it does not magically and indirectly free any zone pointed inside the memory zone you pass it). Again, free(3) says:

  The free() function frees the memory space pointed to by ptr, which
  must have been returned by a previous call to malloc(), calloc() or
  realloc().  Otherwise, or if free(ptr) has already been called
  before, undefined behavior occurs.  If ptr is NULL, no operation is
  performed.

Read much more about C dynamic memory allocation. If you don't like that, learn about garbage collection. With C on Linux and some other systems, you could consider using Boehm's conservative garbage collector. You'll then use GC_MALLOC and/or GC_MALLOC_ATOMIC instead of malloc, and GC_STRDUP instead of strdup and you won't bother about free (you might sometimes use GC_FREE if wanted). I find it very useful, but it does have some drawbacks (a bit slower than malloc, and no explicit guarantee about releasing memory...).

Read about memory corruption, and memory leaks

BTW, you should first compile your program with all warnings and debug info (e.g. gcc -Wall -g). Then you could use your debugger (gdb), set a breakpoint in malloc after main has been reached, and see when malloc is called. You'll see that  strdup is calling malloc ....


FYI, on Linux, malloc is implemented using mmap(2) -and sometimes the old sbrk(2)- syscalls -to get "large" memory regions (of several kilobytes or even megabytes), and free may sometimes call munmap(2) -for these large regions- but most often it justs mark a freed block as reusable, so that block could be reused in some future calls to malloc. Hence a program doing malloc and free might not release all it previously used memory to the kernel. See also this question about memory fragmentation.

use also Valgrind and the address sanitizer

On some operating systems (e.g. Linux) you could compile your C code (using GCC) using gcc -Wall -Wextra -g then use the valgrind tool at runtime. It slows down the execution, but it is helpful in finding bugs like some memory leaks and some buffer overflow. With a recent GCC or Clang compiler, you could also use -at compile time- its address sanitizer (instrumenting the generated code).

You might also read the GC handbook, related to memory allocation and garbage collection algorithms.

like image 148
Basile Starynkevitch Avatar answered Sep 17 '22 16:09

Basile Starynkevitch