2015-10-05 3 views
5

Ich versuche, ein paar Dinge zu lernen (nur als Hobby) und zu versuchen, Valgrind zu lernen. Das scheint mir jedoch keinen Sinn zu ergeben. Es scheint, dass Valgrind sagt, dass Bytes verloren gehen, wenn ich sie mit Callocs verteile, bevor ich überhaupt etwas benutze! Kann jemand erklären, was hier vor sich geht und warum das zweite Programm funktioniert? Ich habe die Programme im Debug-Modus in Eclipse kompiliert und Valgrind auf der ausführbaren Debug-Datei ausgeführt.Warum zeigt Valgrind einen Speicherverlust in einer Calloc-Anweisung

Hier ist das Programm:

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 } 

Und hier ist es, was Valgrind mir gibt:

$ 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) 
:

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

Wenn ich die beiden freien() Aussagen zu entfernen, ist hier, was Valgrind gibt mir

Nun, wenn ich dieses Programm ausführen:

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 } 

Es zeigt alles in Ordnung ist:

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

Warum ist es, dass ich nicht calloc (zuzuteilen) origstr und es dann etwas geben? Was wäre, wenn ich diese Variable zuweisen und im Verlauf des Programms einen Teil von dem geben würde, was in einer anderen String-Variablen ist, oder sie verwenden, um das Ergebnis einer anderen Funktion zu erfassen, die eine Zeichenkette zurückgibt? Würde ich dann damit umgehen müssen wie ich newsubstr?

Das ist ein bisschen verwirrend für mich, kann jemand erklären, wie das funktioniert, damit ich es besser verstehen kann?

+0

Sie verlieren (undichte) die 'calloc()' ed Zeiger mit der Zuordnung auf der Leitung 10. – Kninnug

+0

'origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";' Dieser Satz hat _NOT_ den Inhalt der 'origstr'; Es legt 'origstr' fest, um auf einen schreibgeschützten Speicherbereich zu zeigen, der das Zeichenfolgenliteral enthält. Der Speicher, den Sie zuvor in 'origstr' reserviert haben, ist verloren, und Sie können 'frei' nicht in String-Literalen aufrufen. –

Antwort

7
origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 

Dadurch ändern Sie, was zeigt. Danach zeigt nicht auf Speicherblock zugewiesen von calloc.

Und Sie free Speicher nicht von calloc oder ähnliche Funktionen zugeordnet, so dass Fehler in Ihrem Programm verursacht.

strcpy(origstr,"TheQuickBrownFoxJumpedOverTheLazyDog"); 

und dann können Sie free Ihren Zeiger origstr -

Verwenden strcpy Zeichenfolge origstr zu kopieren.

+0

Ich verwende strncpy (newsubstr, origstr + 8, 8); denn was ich da mache, ist eine Teilzeichenkette der ursprünglichen Zeichenkette (zB "BrownFox").Ich dachte, dies wäre der einfachste Weg (basierend auf einigen Dingen, die ich gelesen habe). –

+0

@RavenLX Dann könnten Sie vielleicht ein String-Literal haben, aber das würde diese Konstante machen. Und ich denke auch, dass du auf "Calloc" klar bist, dass du viel Speicher verwendest. "calloc (37,1);" hätte es für dich tun können. – ameyCU

2

Weil es ein Speicherleck gibt. Sie weisen den Zeiger zu, es ist tatsächlich falsch zu free() es als Sie es haben.

Um den Inhalt an den zugewiesenen Zeiger Verwendung strcpy()

strcpy(origstr, "TheQuickBrownFoxJumpedOverTheLazyDog"); 

Lassen Sie uns kopieren sehen, wie:

  1. Sie mit Speicher anfordern calloc()

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

    dies aus mehreren Gründen falsch ist

    1. Sie reservieren Platz für Zeiger, nicht 9 Zeichen.
    2. Sie brauchen nicht wirklich calloc(), weil Sie den Inhalt sofort überschreiben werden, verwenden Sie malloc().
  2. Sie überschreiben Sie den Zeiger mit einem Stringliteral

    origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 
    

    Sie jetzt Bezug verloren, um den Zeiger früher zurück von calloc() und Sie free() es nicht möglich, sollten Sie nur free() Zeiger zurückgeben von malloc()/calloc()/realloc().

Die Wahrheit ist, brauchen Sie nicht zu calloc() der oristring Zeiger, calloc()/malloc() Sie sind nicht verwendet, damit zu einem Zeiger zuweisen, sondern durch den Zeiger auf den Speicher, auf zu schreiben, oder besser, um auf etwas Speicher zu zeigen, von dem man lesen/schreiben kann.

+2

Wenn dieses "* Sie brauchen nicht wirklich calloc() *" bezieht sich auf "newsubstr", ist es nicht korrekt für den Code, der vom OP angezeigt wird. Die '0'-Initialisierung' calloc() 'ist im Wesentlichen notwendig, da' strncpy() '* keinen * 0'-Terminator kopiert. – alk

4

Durch die Stringliteral zu origstr Zuordnung Sie nicht kopieren Sie die Zeichenfolge tun, sondern nur origstr s Wert ändern, damit die Zeiger auf calloc zu verlieren. free Ing verursacht jetzt undefiniertes Verhalten.

Verwenden Sie stattdessen strcpy oder strncpy, um die Zeichenfolge wirklich auf dem Heap zu speichern. Aber eigentlich calloc für origstr fallen sollte ausreichen.


Hinweise:

  • als @LeeDanielCrocker in den Kommentaren zu dieser Antwort erwähnt, möchten wir Sie wahrscheinlich Platz für char s zuzuordnen, nicht für char* s, drastisch die Größe des zugeordneten Speichers verringert wird. Sie sollten die sizeof(char*) durch eine sizeof(char) (a.k.a. 1) ersetzen.
+0

Außerdem reserviert er viel zu viel Speicher: eine 37-stellige Zeichenfolge benötigt nur 38 Bytes (ein Extra für die abschließende Null). Sie reservieren Speicher für 37 Zeichenzeiger; Zeiger können so groß wie 8 Bytes sein, weshalb der Block, den du verlierst, so groß ist. –

+0

@LeeDanielCrocker Oh, guter Punkt. Will das hinzufügen. – Downvoter

+0

Die Zeichenfolge selbst besteht nur aus 36 Zeichen, weshalb ich 37 verwendet habe (um die Idee mit einzubeziehen, dass es einen Null-Terminator geben wird). Ich nahm an, dass der Null-Terminator automatisch eingefügt wird. Aber vielleicht ist es nicht? Ich weiß jetzt, ich sollte strcpy verwenden, also sollte ich es "TheQuickBrownFoxJumpedOverTheLazyDog \ 0" kopieren? Das sah aus irgendeinem Grund ziemlich komisch aus. –