Pertanyaan malloc dan masalah gratis


Jadi saya memiliki kode ini, saya menjalankannya beberapa kali:

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]);
    }

}

dan di db_svnViewStatus.db saya punya:

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.

Tapi saya mendapatkan ini:

"HEAP CORRUPTION DETECTED: setelah blok Normal (# 54) pada 0x000032E90. CRT mendeteksi bahwa aplikasi menulis ke memori setelah penyangga heap berakhir. "

Ada bantuan?

Juga, haruskah saya menggunakan gratis setelah saya mengalokasikan memori? Mengapa?


4
2018-01-02 01:42


asal


Jawaban:


Kode ini dikompilasi dengan rapi dan berjalan dengan rapi di bawah 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;
}

Ini memiliki beberapa level lebih sedikit indentasi dari aslinya. Kode yang berbaris di sisi kanan layar merupakan indikasi masalah, paling sering. Seperti yang disebutkan dalam komentar, masalah utama adalah ekspresi yang dimaksudkan untuk menaikkan integer melalui pointer, tetapi sebenarnya menambah pointer dan bukan integer. Ada beberapa for loop diganti while loop sehingga kontrol loop semuanya berada di bagian atas loop. Sering kali lebih mudah untuk mengontrol loop dengan cara itu.

Saya masih tidak puas dengan kode itu. Anda mengalokasikan int dan mengobati char * sebagai int *, yang pada mesin 64-bit berarti Anda memiliki pointer 8-byte yang menunjuk ke 4 byte data (dan dua malloc() panggilan). Jika Anda menggunakan struktur seperti:

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

struct data vect[5000];

Dengan ini, Anda hanya akan mengalokasikan (duplikat) string ke dalam elemen berikutnya dari struktur. Akan lebih kompak, dan ada sedikit bahaya untuk melakukan kesalahan. (Anda akan menulis vect[i].count++; dan itu akan melakukan apa yang Anda inginkan tanpa repot, tidak ada muss.) Dan Anda tidak perlu main-main q += 2; (atau q = q + 2;).

Kode ini lebih baik, menggunakan struktur. Ia juga memeriksa alokasi memori dan memastikan bahwa nama-nama itu disalin first dan last jangan overflow (dan null dihentikan). Masih tidak melakukan pemeriksaan batas pada vect larik untuk memastikan bahwa itu tidak menimpa akhir. Jika ada kesalahan saat membaca file, memori bocor; bersihkan akan membutuhkan beberapa perawatan (dan fungsi untuk melakukannya).

#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;
}

1
2018-01-02 02:58



Anda harus mengalokasikan memori untuk mengakhiri nol, seperti ini:

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

Jika Anda gagal mengalokasikan byte tambahan, strcpy akan menulis melewati akhir blok yang dialokasikan, menyebabkan tumpukan korupsi.


6
2018-01-02 01:44



Ada 2 masalah. Yang pertama adalah Anda tidak mengalokasikan cukup memori untuk string. Anda membutuhkan byte tambahan untuk terminator null.

Yang lain adalah bahwa Anda menetapkan vect [q + 1] ke pointer, maka Anda menimpa pointer itu dengan nilai 1. Ketika Anda mencoba untuk membebaskannya, Anda mencoba untuk membebaskan memori di lokasi memori 1. Anda perlu mengubah:

vect[q+1] = 1;

untuk

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

4
2018-01-02 01:48



Anda tidak mengalokasikan cukup memori di sini:

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

strlen(3) hanya melaporkan panjangnya isi dari string dan meninggalkan ASCII trailing NUL chraacter yang C gunakan untuk mengakhiri string. Setiap kali Anda melihat: malloc(strlen(foo));  hampir pasti bug. Selalu menulis malloc(strlen(foo) + 1);. Buat itu + 1 sudah jelas, karena setiap kali Anda tidak Lihat itu + 1, Anda mungkin menemukan bug.

strcpy(vect[q], var);

Karena vect[q] tidak memiliki cukup memori yang dialokasikan untuknya, garis ini menimpa byte yang tidak terkait dengan ASCII NUL karakter.

Seperti untuk free(3)ing memori Anda, sebagian besar programmer merasa sangat membantu untuk menulis malloc(3) dan free(3) panggilan pada waktu bersamaan, dengan kode sumber yang sama, sehingga fitur dapat ditambahkan atau dihapus secara bersih dan mudah. Apakah ada fungsi "meruntuhkan" yang mudah dan sesuai yang sesuai dengan fungsi yang baru saja Anda tulis? ..._init() fungsi sering memiliki ..._final() fungsi, ..._open() fungsi sering memiliki ..._close() fungsi, dan sebagainya. Pasangan ini ideal untuk manajemen memori.


1
2018-01-02 01:48



Pertama, dalam pernyataan ekspresi ini:

*vect[k+1]++;

Anda memiliki masalah presedensi operator. Anda mungkin ingin melakukan itu sebagai gantinya:

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

Kemudian dalam panggilan fungsi ini:

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

tipe dari vect[i] adalah pointer char. Untuk mencetak string yang Anda tidak ingin dereference dan mungkin ingin itu sebagai gantinya:

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

0
2018-01-02 03:04



Menjawab pertanyaan terakhir Anda:

Juga, haruskah saya menggunakan gratis setelah saya mengalokasikan memori? Mengapa?

Ya, Anda harus menggunakan gratis (); Jika Anda tidak menggunakan gratis () Anda mengambil risiko memiliki masalah kebocoran memori.

Anda harus memanggil bebas () tepat di akhir fungsi, sebelum pernyataan kembali jika Anda memilikinya.

Namun, fungsi panggilan dalam kasus utama Anda, juga dapat memanggil bebas () ketika fungsi svnViewStatus () Anda selesai dan mengembalikan kontrol ke utama. Ini karena tidak apa-apa untuk menggunakan variabel penunjuk yang berbeda dengan bebas (); Anda hanya perlu memastikan bahwa penunjuk baru menyimpan alamat yang sama. Maksud saya alamat byte pertama blok memori malloc dialokasikan.

Dan saat dasblinkenlight menyebutkannya, Anda perlu mengalokasikan memori untuk mengakhiri nol.

Saya harap ini membantu.


0
2018-02-27 10:02