在C

时间:2018-01-04 21:16:00

标签: c pointers memory memory-leaks structure

我的C代码存在一些问题。

该代码旨在读取特定类型的txt文件(它通过相似性在基本搜索引擎的C项目中使用,可以搜索图像,音频或文本文件)。

以下是代码:

typedef struct HISTOGRAMME_E{
    int ** valeurs;
    int nbcolonne;
    int nbligne;
    char type;
}HISTOGRAMME;

HISTOGRAMME * lireDescripteur(FILE * read){

    HISTOGRAMME * retour = malloc(sizeof(HISTOGRAMME));


    int etat = 0;
    int id, type, nbligne, nbcolonne;
    unsigned int max;
    unsigned int cpt = 0;
    int i;
    char canswitch = 1;
    char* val = malloc(sizeof(char));

    int ** histoTempo;


    while (fscanf(read,"%s",val) == 1) {
        // Fonctionnement en MAE

        // Actions
        if(etat == 1){
            id = atoi(val);
            etat = 0;
        }

        if(etat == 2){
            if(strcmp(val, "RGB"))
                type = 3;
            else
                type = 1;
            etat = 0;
        }

        if(etat == 3){
            nbcolonne = atoi(val);
            etat = 0;
        }

        if(etat == 4){
            nbligne = atoi(val);
            etat = 0;
        }



        // Valeurs

        if(etat == 5){
            max = nbligne * nbcolonne;
            histoTempo = malloc(sizeof(int*)*2);
            histoTempo[0] = malloc(sizeof(int)*max);
            histoTempo[1] = malloc(sizeof(int)*max);
            cpt = 0;
            canswitch = 0;
            histoTempo[0][0] = (int)strtol(val, NULL, 0);
            etat = 52;
        }

        if(etat == 51 && canswitch){
            histoTempo[0][cpt] = (int)strtol(val, NULL, 0);
            etat = 52;
            canswitch = 0;
        }


        if(etat == 52  && canswitch){

            histoTempo[1][cpt] = atoi(val);
            etat = 51;
            canswitch = 0;
            cpt += 1;
        }





        // Changement d'états
        if(strcmp(val, "<id>") == 0 && (etat == 0))
            etat = 1;

        if(strcmp(val, "<type>") == 0 && (etat == 0))
            etat = 2;

        if(strcmp(val, "<nbcolonne>") == 0 && (etat == 0))
            etat = 3;

        if(strcmp(val, "<nbligne>") == 0 && (etat == 0))
            etat = 4;

        if(strcmp(val, "<valeurs>") == 0 && (etat == 0))
            etat = 5;


        //if(strcmp(val, "</valeurs>") == 0 && ((etat==51) || (etat == 52))) 
        if(strcmp(val, "</valeurs>") == 0)
            {
                //affichage debug
                printf("id:%u, type:%u, nbcolonne:%u, nbligne:%u\n", id, type, nbcolonne,nbligne);
                /*for(i=0;i<cpt;i++){
                    printf("%x : %u \n", histoTempo[0][i], histoTempo[1][i]);
                }*/

                int ** histogramme = malloc(sizeof(int*)*2);
                histogramme[0] = malloc(sizeof(int)*cpt);
                histogramme[1] = malloc(sizeof(int)*cpt);

                for(i=0;i<cpt;i++){
                    histogramme[0][cpt] = histoTempo[0][cpt];
                    histogramme[1][cpt] = histoTempo[1][cpt];
                }
                cpt = 0;
                etat = 0;
                retour->valeurs = histogramme;
                retour->nbcolonne = nbcolonne;
                retour->nbligne = nbligne;
                retour->type = type;


                nbligne = 0;
                nbcolonne = 0;
                type = 0;
                free(histoTempo[0]);
                free(histoTempo[1]);
                free(histoTempo);
                free(val);
                return retour;
            }
        canswitch =1;
    }
    return retour;
}

void test()
    {
    FILE * read =  fopen(FICHIER_DESCRIPTEUR,"r");


    HISTOGRAMME * test;
    int i = 0;

    test = lireDescripteur(read);

    //printf("%i\n\n\n", test->valeurs[1][1]);
    fclose(read);
    free(test);
}

这是Valgrind的日志:

> 220 bytes in 1 blocks are indirectly lost in loss record 1 of 3
>> ==21968==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>> ==21968==    by 0x402AF2: lireDescripteur (index_img.c:905)             
>> ==21968==    by 0x402C62: test (index_img.c:942)                             
>> ==21968==    by 0x402C8F: main (index_img.c:958)               


> ==21968== 220 bytes in 1 blocks are indirectly lost in loss record 2 of 3
>> ==21968==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>> ==21968==    by 0x402B13: lireDescripteur (index_img.c:906)            
>> ==21968==    by 0x402C62: test (index_img.c:942)                  
>> ==21968==    by 0x402C8F: main (index_img.c:958)



> ==21968== 456 (16 direct, 440 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
>> ==21968==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>> ==21968==    by 0x402ADF: lireDescripteur (index_img.c:904)         
>> ==21968==    by 0x402C62: test (index_img.c:942)                 
>> ==21968==    by 0x402C8F: main (index_img.c:958)

它似乎是来自&#34; histogramme&#34;的malloc。 in&#34; lireDescripteur&#34;但我无法理解为什么。 (valgrind指出的三行代码:)

int ** histogramme = malloc(sizeof(int*)*2);
histogramme[0] = malloc(sizeof(int)*cpt);
histogramme[1] = malloc(sizeof(int)*cpt);

该功能&#34; lireDescripteur&#34;应该在类型&#34; HISTOGRAMME&#34;的结构上返回一个指针,用它的&#34; valeurs&#34;指向&#34; histogramme&#34;。

Complete code

Complete valgrind log

1 个答案:

答案 0 :(得分:4)

valgrind指出的问题似乎超出了你所展示的代码,但是在你展示的代码中,你也有内存泄漏,因为你没有在所有返回路径中释放val:这里:

    canswitch =1;
}
return retour;  // you're not freeing `val` here

更重要的是,您有未定义的行为,因为val是一个1字节的数组,并且您正在为其添加更多数据(请参阅:How dangerous is it to access an array out of bounds?)。

我建议使用一个正确大小的本地数组(如果你有更大的单词则增加):

char val[100];

int ** histoTempo;


while (fscanf(read,"%99s",val) == 1) {  // safe fscanf: cannot read more than 99 chars

最后不要free(val)。这样你就可以解决内存泄漏可能导致程序崩溃的内存泄漏。

(您的程序有几次这个问题,来自您提供的链接。作为一般规则,当您不需要将缓冲区返回给调用者时,请使用正确大小的本地数组)