简体   繁体   中英

Memory leak double pointer

I can't figure out what I've done wrong here. New to valgrind and C in general but have managed to clean up all my mem leaks except this one

==8749== HEAP SUMMARY:
==8749==     in use at exit: 880 bytes in 11 blocks
==8749==   total heap usage: 80 allocs, 69 frees, 5,620 bytes allocated
==8749== 
==8749== 400 bytes in 5 blocks are definitely lost in loss record 1 of 2
==8749==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8749==    by 0x402B1C: tokenize (tm_utility.c:78)
==8749==    by 0x402E57: load_data (tm_utility.c:188)
==8749==    by 0x400D0A: main (tm.c:57)
==8749== 
==8749== 480 bytes in 6 blocks are definitely lost in loss record 2 of 2
==8749==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8749==    by 0x402B1C: tokenize (tm_utility.c:78)
==8749==    by 0x402C97: load_data (tm_utility.c:147)
==8749==    by 0x400D0A: main (tm.c:57)
==8749== 

It relates to this function:

char** tokenize(const char* input)
{
    char* str = (char*)strdup(input);
    int count = 0;
    int capacity = 10;
    char** result = malloc(capacity*sizeof(*result)); /*LINE 78*/

    char* tok=strtok(str,",");

    while(1)
    {
        if (count >= capacity)
            result = realloc(result, (capacity*=2)*sizeof(*result));

        result[count++] = tok? strdup(tok) : tok;

        if (!tok) break;

        tok=strtok(NULL,",");
    }

    free(str);
    return result;
}

I can see that I haven't free'd something there but I cant figure out where to free it (calling function or locally??) and exactly what it is I'm supposed to free?

Help?

Thanks

EDIT:

Here is the code from the calling function. I couldn't figure out what else I need to free, tried a few different things but just made it worse and ended up posting here.

while (fgets(line, sizeof(line), coinsfile_stream) != NULL)
{

    tokens = tokenize(line);

    for(i=tokens; i && *i; ++i)
    {

        if(y==0)
        {
            tm->coins[x].denomination = atoi(*i);
            y=1;
            x++;
        }
        else
        {
            tm->coins[z].count = atoi(*i);
            y=0;
            z++;
        }
        free(*i);
    }
}

The code that calls tokenize() in load_data() seems to be responsible for doing the freeing. You're returning the allocated space to the calling function.


With the extra code now shown in the question, you need to add a free(tokens); after the for loop that processes the tokens. This code below runs with a clean bill of health from valgrind :

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

char **tokenize(const char *input);

char **tokenize(const char *input)
{
    char *str = (char *)strdup(input);
    int count = 0;
    int capacity = 10;
    char **result = malloc(capacity*sizeof(*result)); /*LINE 78*/

    char *tok = strtok(str, ",\n");

    while (1)
    {
        printf("Found: <<%s>>\n", tok);
        if (count >= capacity)
            result = realloc(result, (capacity *= 2)*sizeof(*result));

        result[count++] = tok ? strdup(tok) : tok;

        if (!tok)
            break;

        tok = strtok(NULL, ",\n");
    }

    free(str);
    return result;
}

int main(void)
{
    char line[1024];
    int x = 0;
    int y = 0;
    int z = 0;

    struct Coin {
        int denomination;
        int count;
    };
    struct Trade {
        struct Coin coins[10];
    };
    struct Trade tm1;
    struct Trade *tm = &tm1;

    while (fgets(line, sizeof(line), stdin) != NULL)
    {
        char **tokens = tokenize(line);

        for (char **i = tokens; i && *i; ++i)
        {
            printf("Token: <<%s>>\n", *i);
            if (y == 0)
            {
                tm->coins[x].denomination = atoi(*i);
                y = 1;
                x++;
            }
            else
            {
                tm->coins[z].count = atoi(*i);
                y = 0;
                z++;
            }
            free(*i);
        }
        free(tokens);
    }
}

Data file:

12,23
34,45
56,67

Example output:

Found: <<12>>
Found: <<23>>
Found: <<(null)>>
Token: <<12>>
Token: <<23>>
Found: <<34>>
Found: <<45>>
Found: <<(null)>>
Token: <<34>>
Token: <<45>>
Found: <<56>>
Found: <<67>>
Found: <<(null)>>
Token: <<56>>
Token: <<67>>

Beware: my code relies on the systems I'm working on (Mac OS X 10.9 Mavericks; GCC 4.8.2 — but valgrind run in an ancient Linux VM hosted on the same platform) not crashing when asked to print the string pointed at by the null pointer. You need to review the while (1) loop; you should probably just change it to while (tok != 0) or equivalent. Once you've done that, you can then simplify the body of the loop too; there are two now redundant tests for nullness.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM