2010-08-29 5 views
7

Nel mio progetto ho un metodo che crea una stringa da interi (usando strcat) e la scrive in un file. Sfortunatamente ha una perdita di memoria. Mentre rintracciavo quella perdita, ho semplificato il mio codice al seguente. Non riesco a localizzarlo o addirittura a ripararlo. Questo è il codice:Dove si trova la perdita di memoria in questo codice e come risolverlo?

#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 rendimenti:

==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) 

Dove è la perdita di memoria e come posso risolvere il problema?

risposta

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

I valori letterali stringa sono "\ 0" terminati automaticamente, non è necessario aggiungerlo.

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

La prima volta free() è chiamato, è liberando il valore iniziale di uscita, che è un puntatore a una stringa letterale "\0". Chiamata free() su qualcosa di diverso da un puntatore valido tornato da *alloc() o NULL è un comportamento indefinito.

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

rapporti valgrind:

==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 

Questa non è una perdita di memoria; è un valido free().

+0

+1 per spiegazioni chiare. – RBerteig

3

La vostra applicazione si blocca cercando di liberare ("\ 0"). (Solo una nota, se vuoi una stringa vuota, "" è sufficiente, "\ 0" è in realtà la stringa \ 0 \ 0.

Invece di usare malloc e strcpy, guarda a realloc, fa tutto ciò che vuoi ma meglio :) Ma molto probabilmente vuoi costruire la tua stringa in avanti (contatore = 0; contatore < 5; count ++) invece di andare indietro

+3

Tranne che il failloc fallito restituisce NULL, quindi devi controllare se ci sono perdite nel caso in cui tu faccia 'p = realloc (p, new_size)'. –

+0

@Roger: fallire 'realloc' probabilmente significa che il programma deve terminare con grazia. Non pensare che una perdita di memoria sia quindi di grande importanza. –

+0

Non è difficile individuare la perdita potenziale con 'realloc', basta mantenere una copia del puntatore originale attraverso la chiamata in modo che possa essere liberata. Oppure, supponiamo che un "realloc" fallito significhi la fine del mondo, e appena esci. Personalmente mi piace usare 'assert()' per quel controllo, poiché si assicura che l'uscita sia un errore notevole. – RBerteig

4

Il tuo codice è rotto. Il primo passaggio, si imposta oldmemory su output in cui l'output punta alla memoria che non era allocata nell'heap. Successivamente, tenterai di liberare questa memoria. Questo genera l'errore valgrind sulla liberazione della memoria che non è stata allocata tramite malloc. Quindi, la memoria originale che hai assegnato non viene mai liberata.

+0

Penso che lui/lei sappia che è rotto. Non c'è bisogno di essere scortese a riguardo. –

+0

WTF? In che modo ciò che ho scritto è stato maleducato? Penso che tu abbia impostato il tuo rilevatore di sensibilità un po 'troppo alto. O sono scortese per averlo fatto notare. Forse lo sai già. – sizzzzlerz

+0

Lol non è necessario iniziare a votare a caso le mie domande, cagna –

1

Se si desidera utilizzare questo algoritmo, lo spazio iniziale per quello che i punti di uscita dovrebbero essere assegnati con malloc, questa convenzione:

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

Le stringhe non sono allocati con malloc, e di conseguenza non può essere free 'ed, che è la fonte del tuo problema.