简体   繁体   中英

malloc and free issue

So I have this piece of code, I run it a couple of times:

void svnViewStatus()
{
    FILE *file;
    int i, j, k, q=0, ok;
    char mystring[100000], *vect[100000], *var, last[12], first[12];
    file = fopen("db_svnViewStatus.txt", "r");
    if(file == NULL)
    {
        printf("error");
    }
    else
    {
        i=1;
        while(fgets(mystring, 100000, file))
        {
            if( i > 1) 
            {
                j=1;
                var = strtok(mystring, ";");
                while(var != NULL)
                {
                    if(j==3)
                    {
                        if(i == 2)
                        {
                            strcpy(first, var);
                        }
                        strcpy(last, var);
                    }
                    if(j == 2)
                    {
                        if(q != 0)
                        {
                            ok=1;
                            for(k=0; k<q; k=k+2)
                            {
                                if(strcmp(vect[k], var) == 0)
                                {
                                    *vect[k+1]++;
                                    ok=0;
                                }
                            }
                            if(ok == 1)
                            {
                                vect[q] = malloc(strlen(var)+1);
                                strcpy(vect[q], var);
                                vect[q+1] = malloc(sizeof(int));
                                *vect[q+1] = 1;
                                q = q+2;
                            }
                        }
                        else
                        {
                            vect[q] = malloc(strlen(var)+1);
                            strcpy(vect[q], var);
                            vect[q+1] = malloc(sizeof(int));
                            *vect[q+1] = 1;
                            q = q+2;
                        }
                    }
                    j++;
                    var = strtok(NULL, ";");
                }
            }
            i++;
        }
    }
    fclose(file);
    printf("nr: %d \n", i-2);
    printf("first: %s \n", first);
    printf("last: %s \n", last);
    for(i=0; i<q; i = i+2)
    {
        printf("User %s: %d \n", *vect[i], *vect[i+1]);
    }
    for(i=0; i<q; i=i+1)
    {
         free(vect[i]);
    }

}

and in the db_svnViewStatus.db I have:

NumeRepo:CitateWoodyAllen;DataCreat:12 Nov 2011;Detinator:Ioana;Descriere:Citate ale faimosului regizor Woody Allen
1;Ioana;12 Nov 2011;Woody Allen;What if everything is an illusion and nothing exists? In that case, I definitely overpaid for my carpet.
2;Mihai;12 Nov 2011;Woody Allen;The lion and the calf shall lie down together but the calf won't get much sleep
3;Mihai;13 Nov 2011;Woody Allen;Eighty percent of success is showing up
4;Cristi;23 Nov 2011;Woody Allen;It is impossible to travel faster than the speed of light, and certainly not desirable, as one's hat keeps blowing off
5;Ioana;25 Nov 2011;Woody Allen;I had a terrible education. I attended a school for emotionally disturbed teachers.
6;Cristi;25 Nov 2011;Woody Allen;I will not eat oysters. I want my food dead. Not sick. Not wounded. Dead.

But I get this:

"HEAP CORRUPTION DETECTED: after Normal block (#54) at 0x000032E90. CRT detected that the application wrote to memory after end of heap buffer."

Any help?

Also, should I use free after I allocate memory? Why?

You should allocate memory for terminating zero, like this:

vect[q] = malloc(strlen(var)+1);

If you fail to allocate an extra byte, strcpy will write past the end of the allocated block, causing heap corruption.

There are 2 problems. The first is that you're not allocating enough memory for the string. You need an extra byte for the null terminator.

The other is that you're setting vect [ q + 1 ] to a pointer, then you're overwriting that pointer with the value 1. When you attempt to free it, you're attempting to free the memory at memory location 1. You need to change:

vect[q+1] = 1;

to

*(vect [ q + 1 ]) = 1;

You're not allocating enough memory here:

vect[q] = malloc(strlen(var));

strlen(3) reports just the length of contents of the string and leaves out the trailing ASCII NUL chraacter that C uses to terminate strings. Any time you see: malloc(strlen(foo)); it is almost certainly a bug . Always write malloc(strlen(foo) + 1); . Make that + 1 obvious, because any time you don't see that + 1 , you've probably found a bug.

strcpy(vect[q], var);

Because vect[q] doesn't have enough memory allocated for it, this line overwrote an unrelated byte with the ASCII NUL character.

As for free(3) ing your memory, most programmers find it very helpful to write the malloc(3) and free(3) calls at the same time , with the same source code check-in, so that features can be added or removed cleanly and easily. Is there an easy and corresponding "tear down" function that corresponds to the function you've just written? ..._init() functions often have ..._final() functions, ..._open() functions often have ..._close() functions, and so on. These pairs are ideal for memory management.

This code compiles cleanly and runs cleanly under valgrind .

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

static void svnViewStatus(void)
{
    FILE *file;
    int i, j, k, q=0, ok;
    char mystring[100000], *vect[100000], *var, last[12], first[12];
    file = fopen("db_svnViewStatus.txt", "r");
    if (file == NULL)
    {
        printf("error");
        return;
    }

    for (i = 1; fgets(mystring, sizeof(mystring), file) != 0; i++)
    {
        if (i == 1) /* Skip heading */
            continue;
        char *space = mystring;
        for (j = 1; (var = strtok(space, ";")) != NULL; space = NULL, j++)
        {
            if (j == 3)
            {
                if (i == 2)
                {
                    strcpy(first, var);
                }
                strcpy(last, var);
            }
            if (j == 2)
            {
                if (q != 0)
                {
                    ok = 1;
                    for (k = 0; k<q; k += 2)
                    {
                        if (strcmp(vect[k], var) == 0)
                        {
                            (*vect[k+1])++;
                            ok=0;
                        }
                    }
                    if (ok == 1)
                    {
                        vect[q] = malloc(strlen(var)+1);
                        strcpy(vect[q], var);
                        vect[q+1] = malloc(sizeof(int));
                        *vect[q+1] = 1;
                        q += 2;
                    }
                }
                else
                {
                    vect[q] = malloc(strlen(var)+1);
                    strcpy(vect[q], var);
                    vect[q+1] = malloc(sizeof(int));
                    *vect[q+1] = 1;
                    q += 2;
                }
            }
        }
    }

    fclose(file);
    printf("nr: %d \n", i-2);
    printf("first: %s \n", first);
    printf("last: %s \n", last);
    for (i=0; i<q; i = i+2)
    {
        printf("User %s: %d \n", vect[i], *vect[i+1]);
    }
    for (i=0; i<q; i=i+1)
    {
        free(vect[i]);
    }
}

int main(void)
{
    svnViewStatus();
    return 0;
}

It has several levels less indentation than the original. Code marching off the right side of the screen is indicative of problems, most often. As noted in comments, the primary problem was in the expression that was intended to increment an integer via a pointer, but actually incremented the pointer and not the integer. There are a couple of for loops replacing while loops so that the loop control is all at the top of the loop. It is often easier to control a loop that way.

I'm still unhappy with the code. You're allocating int and treating char * as int * , which on a 64-bit machine means you have an 8-byte pointer pointing to 4 bytes of data (and two malloc() calls). If you used a structure such as:

struct data
{
    char *string;
    int   count;
};

struct data vect[5000];

With this, you'd only allocate (duplicate) the string into the next element of the structure. It would be more compact, and there's less danger of getting things wrong. (You'd write vect[i].count++; and it would do what you want with no fuss, no muss.) And you'd not need to be messing around with q += 2; (or q = q + 2; ).

This code is better, using the structure. It also checks memory allocations and ensures that the names copied into first and last do not overflow (and are null terminated). It still doesn't do a bounds check on the vect array to ensure that it doesn't overwrite the end. If there's an error while reading the file, memory is leaked; clean up would require some care (and a function to do it).

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

struct data
{
    char *string;
    int   count;
};

static void svnViewStatus(void)
{
    FILE *file;
    int i, q = 0;
    char mystring[100000], last[12], first[12];
    struct data vect[50000];
    file = fopen("db_svnViewStatus.txt", "r");
    if (file == NULL)
    {
        printf("file open error\n");
        return;
    }

    for (i = 1; fgets(mystring, sizeof(mystring), file) != 0; i++)
    {
        if (i == 1) /* Skip heading */
            continue;
        char *space = mystring;
        char *var;
        for (int j = 1; (var = strtok(space, ";")) != NULL; space = NULL, j++)
        {
            if (j == 3)
            {
                if (i == 2)
                {
                    strncpy(first, var, sizeof(first)-1);
                    first[sizeof(first)-1] = '\0';
                }
                strncpy(last, var, sizeof(last)-1);
                last[sizeof(last)-1] = '\0';
            }
            if (j == 2)
            {
                int found = 0;
                for (int k = 0; k < q; k++)
                {
                    if (strcmp(vect[k].string, var) == 0)
                    {
                        vect[k].count++;
                        found = 1;
                    }
                }
                if (found == 0)
                {
                    vect[q].string = strdup(var);
                    if (vect[q].string == 0)
                    {
                        printf("Memory allocation error\n");
                        return;
                    }
                    vect[q].count = 1;
                    q++;
                }
            }
        }
    }

    fclose(file);

    printf("nr: %d\n", i-1);
    printf("first: %s\n", first);
    printf("last: %s\n", last);
    for (i = 0; i < q; i++)
    {
        printf("User %s: %d\n", vect[i].string, vect[i].count);
    }

    for (i = 0; i < q; i++)
    {
        free(vect[i].string);
    }
}

int main(void)
{
    svnViewStatus();
    return 0;
}

First, in this expression statement:

*vect[k+1]++;

you have an operator precedence issue. You probably wanted to do that instead:

(*vect[k+1])++;

Then in this function call:

printf("User %s: %d \n", *vect[i], *vect[i+1]);

the type of vect[i] is a char pointer. To print the string you don't want to dereference it and probably wanted to that instead:

printf("User %s: %d \n", vect[i], *vect[i+1]);

Answering your last question:

Also, should I use free after I allocate memory? Why?

Yes, you should use free(); If you don't use free() you take the risk of have a memory leak problem.

You should call free() right at the end of the function, before the return statement if you have one.

However, the calling function in your case main, can also call free() when your svnViewStatus() function is finished and returns control to main. This is because it is okay to use a different pointer variable with free(); you just have to make sure that the new pointer stores the same address. I mean the address of the first byte of the memory block malloc allocated.

And as dasblinkenlight mentioned it, you need to allocate memory for terminating zero.

I hope this help.

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