2010-08-29 3 views
7

In meinem Projekt habe ich eine Methode, die eine Zeichenfolge aus Ganzzahlen (mit strcat) erstellt und schreibt sie in eine Datei. Leider hat es ein Speicherleck. Während ich dieses Leck nachverfolgte, vereinfachte ich meinen Code wie folgt. Ich kann es nicht finden oder reparieren. Dies ist der Code:Wo ist der Speicherverlust in diesem Code und wie man es repariert?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
int main(int argc, char* argv[]) 
{ 
char* output = "\0"; 
int counter = 5; 
    while(counter > 0) 
    { 
     char buffer[20]; 
     sprintf(buffer, "%u", counter); 
     char* temp; 
     temp = malloc((strlen(output) + strlen(buffer) + 1)); 
     strcpy(temp, buffer); 
     strcat(temp, output); 
     char* oldmemory = output; 
     output = temp; 
     free(oldmemory); 
     counter--; 
    } 
printf("output: %s\n", output); 
free(output); 
return 0; 
} 

Valgrind kehrt:

==7125== Memcheck, a memory error detector 
==7125== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al. 
==7125== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info 
==7125== Command: ./foo 
==7125== Parent PID: 4455 
==7125== 
==7125== Invalid free()/delete/delete[] 
==7125== at 0x4024B3A: free (vg_replace_malloc.c:366) 
==7125== by 0x8048662: main (foo.c:20) 
==7125== Address 0x8048780 is not stack'd, malloc'd or (recently) free'd 
==7125== 
==7125== 
==7125== HEAP SUMMARY: 
==7125==  in use at exit: 0 bytes in 0 blocks 
==7125== total heap usage: 5 allocs, 6 frees, 20 bytes allocated 
==7125== 
==7125== All heap blocks were freed -- no leaks are possible 
==7125== 
==7125== For counts of detected and suppressed errors, rerun with: -v 
==7125== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 15 from 8) 

Wo ist der Speicherverlust und wie kann ich es beheben?

Antwort

9
#include <stdio.h> 
#include <stdlib.h> 
int main(int argc, char* argv[]) 
{ 
char* output = "\0"; 

String-Literale werden '\ 0' automatisch beendet, Sie müssen sie nicht hinzufügen.

int counter = 5; 
    while(counter > 0) 
    { 
     char buffer[20]; 
     sprintf(buffer, "%u", counter); 
     char* temp; 
     temp = malloc((strlen(output) + strlen(buffer) + 1)); 
     strcpy(temp, buffer); 
     strcat(temp, output); 
     char* oldmemory = output; 
     output = temp; 
     free(oldmemory); 

Das erste Mal in dieser free() genannt wird, hat es den Anfangswert des Ausgangs befreien, die ein Zeiger auf einen Stringliteral "\0" ist. Der Aufruf von free() an einem anderen als einem gültigen Zeiger, der von oder NULL zurückgegeben wird, ist nicht definiert.

 counter--; 
    } 
printf("output: %s\n", output); 
free(output); 
return 0; 
} 

valgrind Berichte:

==7125== Invalid free()/delete/delete[] 
==7125== at 0x4024B3A: free (vg_replace_malloc.c:366) 
==7125== by 0x8048662: main (foo.c:20) 
==7125== Address 0x8048780 is not stack'd, malloc'd or (recently) free'd 

Dies ist nicht ein Speicherverlust; Es ist ein ungültiger free().

+0

+1 für klare Erklärungen. – RBerteig

3

Ihre App stürzt ab ("\ 0"). (Nur eine Anmerkung, wenn Sie eine leere Zeichenfolge möchten, "" ist genug, "\ 0" ist eigentlich die Zeichenfolge \ 0 \ 0.

Statt malloc und strcpy, schauen Sie sich realloc, es tut alles, was Sie wollen aber besser :) Aber Sie würden wahrscheinlich Ihre Zeichenfolge vorwärts (Zähler = 0; Zähler < 5; zählen ++) statt rückwärts gehen

+3

Außer dass fehlgeschlagenes realloc NULL zurückgibt, müssen Sie also auf Lecks achten, wenn Sie 'p = realloc (p, new_size)' ausführen. –

+0

@Roger: fehlgeschlagen 'Realloc' bedeutet wahrscheinlich, dass das Programm ordnungsgemäß beendet werden muss. Denken Sie nicht, dass ein Speicherleck dann von großer Relevanz ist. –

+0

Es ist nicht schwer, das potentielle Leck mit 'realloc' zu fangen, behalte einfach eine Kopie des ursprünglichen Zeigers über den Aufruf, so dass er freigegeben werden kann. Oder gehen Sie davon aus, dass ein fehlgeschlagener "realloc" das Ende der Welt bedeutet, und verlassen Sie ihn einfach. Ich persönlich benutze 'assert()' gerne für diese Überprüfung, da es sicherstellt, dass der Exit ein bemerkenswerter Fehler ist. – RBerteig

4

Ihr Code ist kaputt. Beim ersten Durchgang setzen Sie oldmemory so, dass der Ausgabepunkt in den Arbeitsspeicher ausgegeben wird, der nicht auf dem Heapspeicher zugewiesen wurde. Später versuchen Sie, diese Erinnerung freizugeben. Dies erzeugt den Valgrind-Fehler beim Freigeben von Speicher, der nicht über malloc zugewiesen wurde. Daher wird der ursprüngliche Speicher, den Sie zugewiesen haben, niemals freigegeben.

+0

Ich denke, er/sie weiß, dass es kaputt ist. Kein Grund, unhöflich zu sein. –

+0

WTF? Wie ist das, was ich geschrieben habe, unhöflich? Ich denke du hast deinen Empfindlichkeitsdetektor nur ein bisschen zu hoch eingestellt. Oder bin ich unhöflich, dass ich darauf hingewiesen habe? Vielleicht weißt du das schon. – sizzzzlerz

+0

Lol keine Notwendigkeit, nach dem Zufallsprinzip nach unten zu stimmen meine Fragen, Hündin –

1

Wenn Sie diesen Algorithmus zu verwenden, sollte mit malloc die die Anfangs Platz für welche Ausgangspunkte werden, so:

char *output = malloc(1); 
if(!output) { /* handle error */ } 
output[0] = '\0'; 
... rest of code as is ... 

Stringliterale nicht mit malloc zugeordnet und folglich nicht free sein kann 'ed, das ist die Quelle Ihres Problems.

Verwandte Themen