2016-05-05 4 views
2

Diese Funktion liest die Werte aus einer Textdatei mit durch Leerzeichen getrennten Werten in ein 2D-Array ein. Wenn ich es ausführe, funktioniert es gut - aber ein Speicherleckcheck durch Valgrind bestätigt Xcode's Verdacht, dass "char * splitString" nie freigegeben wird, die zwei Male, wie es heißt. Ich verstehe das nicht, wenn man bedenkt, dass mein "char * buffer" gut befreit ist. Jede Hilfe wird sehr geschätzt!Warum befreit C nicht den Speicher von malloc'd char *, der von strtok gesetzt wird?

int** readMatrixFile(char* inFileName, int** matrix, int sizeY, int sizeX) 
{ 
    FILE* matrixFP; 
    int ii=0, jj=0, fileValid = 1; 
    char *buffer, *splitString; 
    const char delim[]=" \n\r"; 

    matrixFP = fopen(inFileName, "r"); 
    if(matrixFP != NULL) 
    { 
     /*Check if file is the same size as specified by the command line 
     *assumed valid until the file is checked*/ 
     splitString = malloc(100*sizeof(char)); <------where allocated 
     buffer = malloc(5000*sizeof(char)); 
     do 
     { 
      fgets(buffer, 5000, matrixFP); 
      jj=0; 
      splitString = strtok(buffer, delim); 
      while(splitString != NULL) 
      { 
       jj++; 
       splitString = strtok(NULL, delim); 
      } 
      if(jj!=sizeX) 
      { 
       fileValid = 0; 
      } 
      ii++; 
     } while(!feof(matrixFP)); 
     if(ii != sizeY || buffer==NULL) 
     { 
      fileValid = 0; 
     } 

     free(splitString); <-----Appears to do nothing? 
     free(buffer); 

     if(fileValid) /*Files match to specified command line values*/ 
     { 
      ii=0; 
      rewind(matrixFP); 
      matrix = (int**)malloc(sizeY * sizeof(int *)); 
      do 
      { 
       matrix[ii] = (int*)malloc(sizeX * sizeof(int)); 
       jj=0; 
       do 
       { 
        fscanf(matrixFP, "%d", &matrix[ii][jj]); 
        jj++; 
       } while(jj<sizeX); 
       ii++; 
      } while(ii<sizeY && !feof(matrixFP)); 
     } 
     else 
     { 
      printf("Error: File does not match size specified by the command line\n"); 
     } 
     fclose(matrixFP); 
    } 
    else 
    { 
     perror("Error: File does not exist or is invalid"); 
     matrix = NULL; 
    } 

    return matrix; 
} 

Und Valgrind Ausgang:

  splitString = strtok(NULL, delim); 

und hier:

  splitString = strtok(buffer, delim); 

so

==14087== Memcheck, a memory error detector 
==14087== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. 
==14087== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info 
==14087== Command: ./pmms a b 10 3 10 
==14087== 
/*irrelevent program output*/ 
==14087== 
==14087== HEAP SUMMARY: 
==14087==  in use at exit: 200 bytes in 2 blocks 
==14087== total heap usage: 21 allocs, 19 frees, 11,680 bytes allocated 
==14087== 
==14087== 100 bytes in 1 blocks are definitely lost in loss record 1 of 2 
==14087== at 0x4A06A2E: malloc (vg_replace_malloc.c:270) 
==14087== by 0x400B55: readMatrixFile (matrix_reader.c:35) 
==14087== by 0x40095E: main (pmms.c:23) 
==14087== 
==14087== 100 bytes in 1 blocks are definitely lost in loss record 2 of 2 
==14087== at 0x4A06A2E: malloc (vg_replace_malloc.c:270) 
==14087== by 0x400B55: readMatrixFile (matrix_reader.c:35) 
==14087== by 0x400982: main (pmms.c:24) 
==14087== 
==14087== LEAK SUMMARY: 
==14087== definitely lost: 200 bytes in 2 blocks 
==14087== indirectly lost: 0 bytes in 0 blocks 
==14087==  possibly lost: 0 bytes in 0 blocks 
==14087== still reachable: 0 bytes in 0 blocks 
==14087==   suppressed: 0 bytes in 0 blocks 
==14087== 
==14087== For counts of detected and suppressed errors, rerun with: -v 
==14087== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6) 
+0

Im Code gibt es kein 2D-Array und nichts, das als ein solches verwendet werden kann. – Olaf

+0

Und don 't werfen das Ergebnis von 'malloc' & Freunde in C. – Olaf

+0

@Olaf - Danke! –

Antwort

4

Zuerst iterieren Sie

while(splitString != NULL) 
    { 
      ... 
    } 

so nach der Schleife Abschluss splitStringNULL ist, und free(NULL) tut nichts.

Zweitens, wenn Sie einen hundert-Byte-Speicherblock zugewiesen

splitString = malloc(100*sizeof(char)); // (*) 

der nächste Hinweis auf das splitString Variable ist eine Zuordnung:

splitString = strtok(buffer, delim); 

Also, was auch immer in der Variable gespeichert wurde, es wurde überschrieben! splitString Punkte irgendwo in den buffer Block jetzt und die Adresse des Blocks bei (*) zugewiesen ist für immer verloren. Das bedeutet übrigens, dass Sie diesen Block niemals verwenden und Sie ihn nicht wirklich zuweisen müssen. Diese

+0

_ "Sie verwenden diesen Block nie, und Sie müssen ihn nicht wirklich zuweisen" _ +1 – emlai

+0

Legende! Ich sehe, was du meinst, wenn man bedenkt, dass die Adresse für splitString dann geändert wird, wo immer "stress" beim ersten Aufruf von strtok steht. Erstmalige Verwendung von stackoverflow, eingeprägt –

5

Sie den Wert splitString ändern es zeigt nicht mehr auf den Speicherblock, der freigegeben werden soll, so dass die free() nichts tut, da zum Zeitpunkt, zu dem diese Zeile erreicht ist, splitStringNULL ist und free(NULL) definiert ist, nichts zu tun.

+0

_ so dass '' free() 'nichts tut" _ No, ruft 'free()' ruft undefiniertes Verhalten auf. Wenn das Argument nicht null ist, tut es nichts. – emlai

+0

Das Freigeben eines Nullzeigers ist kein undefiniertes Verhalten. Gemäß dem Standard passiert nichts, wenn Sie einen Nullzeiger übergeben –

+0

@AbhinavUpadhyay tatsächlich. – abligh

3

Innerhalb der while(splitSring != NULL) Schleife verwenden Sie strtok(3), die es ändert. Am Ende der Schleife splitString wird NULL sein und im Wesentlichen rufen Sie free(NULL), während der ursprünglich zugewiesene Speicher undicht.

3

ist keine direkte Antwort auf Ihre Frage, nur ein Vorschlag, der das Problem ganz vermeiden helfen kann:

Wenn strtok() und Familie verwenden, müssen Sie explizit Speicher nicht zuordnen für das Objekt, das Sie verwenden zu erfassen, den Rückgabewert:

char delim[] = {" \n\t"}; //or whatever delimitors you need 
char *tok = NULL; 

tok = strtok(stringToParse, delim); 
while(tok) 
{ 
    //do something with tok 
    ... 
    //get next token: 
    tok = strtok(NULL, delim); 
} 

Und es gibt keine Notwendigkeit tok wenn wie dargestellt verwendet zu befreien ist.

+0

Sinnvoll! Danke für die Aufklärung dort. –

Verwandte Themen