0

I've been experimenting with double indirection (I've recently wandered into object oriented c and need to understand pointers a lot better), and Instruments is picking up a memory leak when I am freeing memory. The more I look at it the more it's starting to look like it's an error with Instruments (mac) but I want to be completely sure. I have four malloc statements and four free statements, so each time I allocate memory, I am also deallocating it.

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

int main(int argc, const char * argv[]) {
    printf("test initializing\n");
    printf("-----------------\n");

    char **strings = (char**)malloc(sizeof(char*)*2); // MALLOC #1
    char *string1 = "string1";
    char *string2 = "string2";

    *(strings + 0) = string1;
    *(strings + 1) = string2;

    printf("string1: %s\n", string1);
    printf("string2: %s\n", string2);
    printf("*(strings + 0): %s\n", *(strings + 0));
    printf("*(strings + 1): %s\n", *(strings + 1));
    // I know *(strings + 0) == *strings, I just liked that they lined up :)

    free(strings), strings = NULL;                   // FREE #1

    int address = (int)strings;
    printf("address: %d\n", address);

    printf("-----------------\n");

    strings = (char**)malloc(sizeof(char*) * 2);     // MALLOC #2
    // Instruments is saying that this ^ malloc is not being freed.

    printf("strings    : %d\n", (int)strings);
    printf("*strings   : %d\n", (int)*strings);
    printf("**strings  : %d\n", (int)**strings);
    printf("*(strings + 1) : %d\n", (int)*(strings + 1));

    printf("-----------------\n");

    *strings =  (char*)malloc(sizeof(char) * 10);    // MALLOC #3
    *(strings + 1) = (char*)malloc(sizeof(char) * 10);  // MALLOC #4

    strncpy(*strings, "string1", 10);
    strncpy(*(strings + 1), "string2", 10);

    printf("strings        : %p\n", strings);
    printf("*strings       : %p\n", *strings);
    printf("*(strings + 1) : %p\n", *(strings + 1));

    printf("*(strings + 0) : %s\n", *(strings + 0));
    printf("*(strings + 1) : %s\n", *(strings + 1));

    free(*strings), *strings = NULL;                 // FREE #2
    free(*(strings + 1)), *(strings + 1) = NULL;     // FREE #3
    free(strings), strings = NULL;                   // FREE #4

    printf("-----------------\n");
    printf("test  terminating\n");
    return 0;
}

and then here is the output (obviously pointer addresses will not be the same if you run it):

test initializing
-----------------
string1: string1
string2: string2
*(strings + 0): string1
*(strings + 1): string2
address: 0
-----------------
strings    : 1070176
*strings   : 3677
**strings  : 115
*(strings + 1) : 3685
-----------------
strings        : 0x100105460
*strings       : 0x100105470
*(strings + 1) : 0x100105480
*(strings + 0) : string1
*(strings + 1) : string2
-----------------
test  terminating

If I loop this, the memory leak does not grow--it remains at one object leaked.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
zhill
  • 9
  • 1
  • It is more readable to use `strings[1]` instead of `*(strings + 1)`. The result is the same. – i486 Dec 09 '14 at 10:37
  • you forgot to `#include ` to use `strncpy`, also some of your `printf`s are UB. – mch Dec 09 '14 at 10:42
  • The first few chapters should cover this. http://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list – 2501 Dec 09 '14 at 11:41
  • 1
    You can always use valgrind to double check. – nchen24 Dec 09 '14 at 11:47
  • @zhill what happens if you isolate just the allocation that is supposedly being leaked? i.e. just comment out everything apart from the malloc and the free of the second allocation. If is still being leaked then its probably your detector that's wrong. If it goes away then add the code back until it happens again. – David Woo Dec 09 '14 at 20:07
  • @mch sorry the string.h include is else where but it's there in my actual code and I'm not sure what you mean by UB. – zhill Dec 09 '14 at 20:13
  • @2501 these are great resources, thank you! – zhill Dec 09 '14 at 20:13
  • @David completing your suggestion removes the "leak"; my worry is that there is an accidental pointer manipulation in there that is preventing me from freeing that malloc'd area. I'm going to start going through the man pages of all of those c funcs. – zhill Dec 09 '14 at 20:15
  • @nchen24 I'll have to check into that. I've never used it. – zhill Dec 09 '14 at 20:17
  • 1
    @zhill it's undefined behaviour to dereference an uninitialized pointer like in the 11th printf, that's the point where the program crashs on my pc. It's also undefined behaviour to print the address of an `char*` or `char**` with `%p`. – mch Dec 09 '14 at 20:22

1 Answers1

1

Some minor comments you have not included the prototype for strncpy (string.h)

You also cast the return value of malloc which is not a good thing to do - it is but not considered good practice. If you are on a C++ compiler that requires a cast then you should have used delete/new instead not malloc/free.

Other than that you are doing something odd here

21  free(strings), strings = NULL;                   // FREE #1
22  
23  int address = (int)strings;
24  printf("address: %d\n", address);

you free, set it to NULL then cast to int.

AndersK
  • 35,813
  • 6
  • 60
  • 86