2015-10-05 34 views
5

Sto provando a imparare un paio di cose (proprio come un hobby) e sto cercando di imparare a usare Valgrind. Tuttavia questo non sembra avere senso per me. Sembra che Valgrind stia dicendo che i byte sono persi quando li sto allocando con calloc prima ancora di usare qualsiasi cosa! Qualcuno può spiegare cosa sta succedendo qui e perché il secondo programma ha funzionato? Ho compilato i programmi in modalità di debug in Eclipse ed eseguito Valgrind nell'eseguibile di debug.Perché Valgrind mostra una perdita di memoria su un'istruzione calloc

Ecco il programma:

1 #include <stdlib.h> 
2 #include <stdio.h> 
3 #include <string.h> 
4 
5 int main(void) { 
6 
7  char* origstr = calloc(37, sizeof(char*)); 
8  char* newsubstr = calloc(9, sizeof(char*)); 
9 
10 origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 
11 
12 strncpy(newsubstr, origstr + 8, 8); 
13 printf("SubString is: %s\n", newsubstr); 
14 
15 free(newsubstr); 
16 free(origstr); 
17 return 0; 
18 } 

Ed ecco cosa Valgrind mi dà:

$ valgrind --tool=memcheck --leak-check=full ./test 
==25404== Memcheck, a memory error detector 
==25404== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. 
==25404== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info 
==25404== Command: ./test 
==25404== 
SubString is: BrownFox 
==25404== Invalid free()/delete/delete[]/realloc() 
==25404== at 0x4C29E90: free (vg_replace_malloc.c:473) 
==25404== by 0x400665: main (test.c:16) 
==25404== Address 0x4006f8 is not stack'd, malloc'd or (recently) free'd 
==25404== 
==25404== 
==25404== HEAP SUMMARY: 
==25404==  in use at exit: 296 bytes in 1 blocks 
==25404== total heap usage: 2 allocs, 2 frees, 368 bytes allocated 
==25404== 
==25404== 296 bytes in 1 blocks are definitely lost in loss record 1 of 1 
==25404== at 0x4C2AD10: calloc (vg_replace_malloc.c:623) 
==25404== by 0x4005FC: main (test.c:7) 
==25404== 
==25404== LEAK SUMMARY: 
==25404== definitely lost: 296 bytes in 1 blocks 
==25404== indirectly lost: 0 bytes in 0 blocks 
==25404==  possibly lost: 0 bytes in 0 blocks 
==25404== still reachable: 0 bytes in 0 blocks 
==25404==   suppressed: 0 bytes in 0 blocks 
==25404== 
==25404== For counts of detected and suppressed errors, rerun with: -v 
==25404== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) 

Se rimuovo le due affermazioni free(), ecco cosa Valgrind mi dà:

$ valgrind --tool=memcheck --leak-check=full ./test 
==25597== Memcheck, a memory error detector 
==25597== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. 
==25597== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info 
==25597== Command: ./test 
==25597== 
SubString is: BrownFox 
==25597== 
==25597== HEAP SUMMARY: 
==25597==  in use at exit: 368 bytes in 2 blocks 
==25597== total heap usage: 2 allocs, 0 frees, 368 bytes allocated 
==25597== 
==25597== 72 bytes in 1 blocks are definitely lost in loss record 1 of 2 
==25597== at 0x4C2AD10: calloc (vg_replace_malloc.c:623) 
==25597== by 0x4005BF: main (test.c:8) 
==25597== 
==25597== 296 bytes in 1 blocks are definitely lost in loss record 2 of 2 
==25597== at 0x4C2AD10: calloc (vg_replace_malloc.c:623) 
==25597== by 0x4005AC: main (test.c:7) 
==25597== 
==25597== LEAK SUMMARY: 
==25597== definitely lost: 368 bytes in 2 blocks 
==25597== indirectly lost: 0 bytes in 0 blocks 
==25597==  possibly lost: 0 bytes in 0 blocks 
==25597== still reachable: 0 bytes in 0 blocks 
==25597==   suppressed: 0 bytes in 0 blocks 
==25597== 
==25597== For counts of detected and suppressed errors, rerun with: -v 
==25597== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) 

Ora, se eseguo questo programma:

1 #include <stdlib.h> 
2 #include <stdio.h> 
3 #include <string.h> 
4 
5 int main(void) { 
6 
7 char* origstr; 
8 char* newsubstr = calloc(9, sizeof(char*)); 
9 
10 origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 
11 
12 strncpy(newsubstr, origstr + 8, 8); 
13 printf("SubString is: %s\n", newsubstr); 
14 
15 free(newsubstr); 
16 
17 return 0; 
18 } 

Esso mostra tutto va bene:

$ valgrind --tool=memcheck --leak-check=full ./test 
==25862== Memcheck, a memory error detector 
==25862== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. 
==25862== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info 
==25862== Command: ./test 
==25862== 
SubString is: BrownFox 
==25862== 
==25862== HEAP SUMMARY: 
==25862==  in use at exit: 0 bytes in 0 blocks 
==25862== total heap usage: 1 allocs, 1 frees, 72 bytes allocated 
==25862== 
==25862== All heap blocks were freed -- no leaks are possible 
==25862== 
==25862== For counts of detected and suppressed errors, rerun with: -v 
==25862== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

Perché è che non posso calloc (assegnare) origstr e poi dargli qualcosa? Cosa succede se volessi allocare quella variabile e nel corso del programma dargli una parte di ciò che è in un'altra variabile stringa o usarla per catturare il risultato di un'altra funzione che restituisce una stringa? Dovrei quindi gestirlo come ho fatto a newsubstr?

Questo è un po 'di confusione per me, quindi qualcuno può spiegare come funziona così posso comprenderlo meglio?

+0

Stai perdendo (perdite) il 'calloc()' puntatore ed con l'assegnazione on line 10. – Kninnug

+0

'origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";' Questo non _NON_ impostare i contenuti di 'origstr'; imposta 'origstr' in modo che punti a una sezione di sola lettura della memoria che contiene la stringa letterale. La memoria che hai precedentemente assegnato a 'origstr' si perde e non puoi chiamare' free' su string letterali. –

risposta

7
origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 

In questo modo si passa a ciò a origstr punti. Dopo questo, origstr non punta al blocco di memoria allocato da calloc.

E la memoria free non allocata da calloc o funzioni simili, causando quindi errori nel programma.

Usa strcpy per copiare stringa origstr -

strcpy(origstr,"TheQuickBrownFoxJumpedOverTheLazyDog"); 

e quindi si può free il puntatore origstr.

+0

Sto usando strncpy (newsubstr, origstr + 8, 8); perché quello che sto facendo è quello di ottenere una sottostringa della stringa originale (ad esempio "BrownFox").Ho pensato che questo sarebbe il modo più semplice per farlo (basato su alcune cose che ho letto). –

+0

@RavenLX Allora forse potresti avere una stringa letterale, ma sarebbe una costante. E inoltre penso che tu sia chiaro su 'calloc' che usi una grande quantità di memoria. 'calloc (37,1); potrebbe averlo fatto per te. – ameyCU

2

Perché c'è una perdita di memoria. Riassegnare il puntatore, in realtà non è corretto a free() come lo hai tu.

Per copiare il contenuto per l'utilizzo del puntatore assegnato strcpy()

strcpy(origstr, "TheQuickBrownFoxJumpedOverTheLazyDog"); 

Vediamo come:

  1. voi richiesta di memoria con calloc()

    origstring = calloc(9, sizeof(char*)) 
    

    questo è sbagliato per molteplici ragioni

    1. Si sta allocando spazio per i puntatori 9, non 9 caratteri.
    2. Non hai davvero bisogno di calloc() perché sovrascrivi immediatamente il contenuto, usa malloc().
  2. si sovrascrive il puntatore con una stringa letterale

    origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 
    

    ora hai perso riferimento al puntatore restituito in precedenza da calloc() e non è possibile possibile free(), si dovrebbe solo free() puntatori ritorno in malloc()/calloc()/realloc().

La verità è che non c'è bisogno di calloc() il puntatore oristring, calloc()/malloc() non sono utilizzati per consentire di assegnare a un puntatore, ma di scrivere la memoria a cui punta il puntatore, o meglio, per indicare un po 'di memoria che puoi leggere/scrivere da/a.

+2

Se questo "* Non hai veramente bisogno di calloc() *" si riferisce a 'newsubstr', non è corretto per il codice mostrato dall'OP. L'inizializzazione '0' di' calloc() 'è essenzialmente necessaria, dato che' strncpy() 'non * copia * un terminatore' 0'. – alk

4

Assegnando la stringa letterale per origstr si non si copiare la stringa, ma basta cambiare origstr s valore, perdendo così il puntatore calloc. free ing origstr ora causa un comportamento non definito.

Utilizzare strcpy o strncpy invece di memorizzare realmente la stringa sull'heap. Ma in realtà il calo di calloc per origstr dovrebbe essere sufficiente.


Note:

  • come @LeeDanielCrocker accennato nei commenti a questa risposta, probabilmente destinato a allocare spazio per char s, non per char* s, diminuendo la dimensione della memoria allocata drasticamente. È necessario sostituire sizeof(char*) con un sizeof(char) (a.k.a. 1).
+0

Inoltre, sta allocando troppa memoria: una stringa di 37 caratteri richiede solo 38 byte (un extra per lo zero finale). Stai allocando memoria per puntatori a 37 caratteri; i puntatori possono essere grandi come 8 byte ciascuno, motivo per cui il blocco che stai perdendo è così grande. –

+0

@LeeDanielCrocker Oh, buon punto. Lo aggiungeremo. – Downvoter

+0

La stringa stessa ha solo 36 caratteri ed è per questo che ho usato 37 (per includere l'idea che ci sarà un terminatore null). Supponevo che il terminatore null venisse automaticamente inserito. Ma forse non lo è? Ora so che dovrei usare strcpy quindi dovrei copiarlo "TheQuickBrownFoxJumpedOverTheLazyDog \ 0"? Mi sembrava piuttosto strano per qualche motivo. –