LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Correct use of free() in complex structures (https://www.linuxquestions.org/questions/programming-9/correct-use-of-free-in-complex-structures-321767/)

sleepisforwimps 05-09-2005 05:05 PM

Correct use of free() in complex structures
 
Consider the following program:

Code:

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

int main()
{
  struct TestStruct
  {
    int X;
    int Y;

    char *CharString;
  } *TestStructPtr;

  TestStructPtr = malloc (sizeof (struct TestStruct));
  TestStructPtr->CharStr = malloc ((sizeof (char)) * 16);

  TestStruct->X = 3;
  TestStruct->Y = 4;
  TestStruct->CharString = "Hello World!\n\n\n");

  printf ("TestStructPtr = (%i, %i).\n\n", TestStructPtr->X, TestStructPtr->Y);
  printf ("CharString = %s.", TestStructPtr->CharString);

  free (TestStructPtr);

  return 0;
}

This program contains a pointer to a struct (TestStructPtr) that itself contains a pointer (CharString), nested pointers if you will.

When I compile this program with the option "-Wall" included I get no error or warning messages and when when run the program runs as expected so all seems OK. However when I run the same program under Valgrind I get warned of a memory leak. This makes sense as the CharString pointer has not been freed up. To handle this leak I added an extra free() command specifically for that pointer so the program now looks like this:

Code:

.
.
.
  printf ("TestStructPtr = (%i, %i).\n\n", TestStructPtr->X, TestStructPtr->Y);
  printf ("CharString = %s.", TestStructPtr->CharString);

  free (TestStruct->CharString);
  free (TestStructPtr);
.
.
.

Now the program still compiles OK but when the new line is reached at run-time I get the following error message:

Code:

*** glibc detected *** free(): invalid pointer: 0x080485b4 ***
Obviously that doesn't work but I've no idea why. OK, let's try something else, let's create a new char pointer that points to the same memory address as CharString, that way we can free() CharString by proxy, as it were. This is the next version of the code:

Code:

.
.
.
  printf ("TestStructPtr = (%i, %i).\n\n", TestStructPtr->X, TestStructPtr->Y);
  printf ("CharString = %s.", TestStructPtr->CharString);

  char *TempPtr = TestStructPtr->CharString;

  free (TempPtr);
  free (TestStructPtr);
.
.
.

The program still compiles OK but when I run it I get an error message similar to the one above when it comes to the "free (TempPtr);" line. Why does free() not work in this situation and how do I properly free nested pointers?

Dark_Helmet 05-09-2005 06:10 PM

The problem is not with free() but because you lose the malloc you originally gave to CharString.

malloc() returns a pointer to the address of the memory reserved. So you set CharString equal to that. That's perfectly legit.

Then you do this:
Code:

  TestStruct->CharString = "Hello World!\n\n\n");
That's where your wheels come off. A literal character string is not copied with an equal ( = ) assignment. To copy a string, you need to use strcpy(), strncpy(), or one of a number of alternatives.

By using the assignment operator, you lose the address of the memory you malloc'ed, and replace it with the address where "Hello World\n\n\n" is stored (which is likely kept inside the executable itself).

sleepisforwimps 05-09-2005 06:38 PM

OK, I've changed the program so that it now reads:

Code:

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


int main()
{
  struct TestStruct
  {
    int X;
    int Y;

    char *CharString;
  } *TestStructPtr;

  TestStructPtr = malloc (sizeof (struct TestStruct));
  TestStructPtr->CharStr = malloc ((sizeof (char)) * 16);

  TestStruct->X = 3;
  TestStruct->Y = 4;
  strcpy (TestStructPtr->CharString, "Hello World!\n\n\n");

  printf ("TestStructPtr = (%i, %i).\n\n", TestStructPtr->X, TestStructPtr->Y);
  printf ("CharString = %s.", TestStructPtr->CharString);

  free (TestStructPtr->CharString);
  free (TestStructPtr);

  return 0;
}

With that, gcc is happy, glibc is happy, Valgrind is happy and that makes me happy. Now I just need to figure out where that fits in with my project. Thanks for your help.


All times are GMT -5. The time now is 12:13 AM.