2015-10-05 27 views
5

Tôi đang cố gắng tìm hiểu một vài điều (giống như sở thích) và cố gắng học cách sử dụng Valgrind. Tuy nhiên điều này dường như không có ý nghĩa với tôi. Có vẻ như Valgrind đang nói rằng các byte bị mất khi tôi phân bổ chúng với calloc trước khi tôi thậm chí sử dụng bất cứ điều gì! Ai đó có thể giải thích những gì đang xảy ra ở đây và tại sao chương trình thứ hai lại hoạt động? Tôi đã biên dịch các chương trình trong chế độ gỡ rối trong Eclipse và chạy Valgrind trên thực thi gỡ rối.Tại sao Valgrind hiển thị rò rỉ bộ nhớ trên một tuyên bố calloc

Dưới đây là các chương trình:

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 } 

Và đây là những gì Valgrind mang lại cho tôi:

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

Nếu tôi loại bỏ hai) báo cáo (miễn phí, đây là những gì Valgrind mang lại cho tôi:

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

Bây giờ, nếu tôi chạy chương trình này:

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 } 

Nó cho thấy tất cả mọi thứ chỉ là tốt:

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

Tại sao nó mà tôi có thể không calloc (phân bổ) origstr và sau đó cung cấp cho nó một cái gì đó? Điều gì sẽ xảy ra nếu tôi muốn phân bổ biến đó và trong quá trình của chương trình, hãy cho nó một phần của biến nào đó trong biến chuỗi khác hoặc sử dụng nó để nắm bắt kết quả của hàm khác trả về một chuỗi? Sau đó tôi sẽ phải xử lý nó như tôi đã làm newsubstr?

Điều này hơi khó hiểu với tôi vì vậy ai đó có thể giải thích cách hoạt động của nó để tôi có thể hiểu nó tốt hơn?

+0

Bạn đang mất (rò rỉ) 'cái calloc() 'con trỏ ed với nhiệm vụ trên đường dây 10 – Kninnug

+0

' origstr = "TheQuickBrownFoxJumpedOverTheLazyDog";' Điều này không _not_ thiết lập các nội dung của 'origstr'; nó đặt 'origstr' để trỏ đến phần chỉ đọc của bộ nhớ có chứa chuỗi chữ. Bộ nhớ mà bạn đã cấp trước đó vào 'origstr' bị mất và bạn không thể gọi' free' trên chuỗi ký tự. –

Trả lời

7
origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 

Bằng cách này, bạn đổi thành số origstr trỏ đến. Sau origstr này không trỏ đến khối bộ nhớ được phân bổ bởi calloc.

Và bạn free bộ nhớ không được phân bổ bởi calloc hoặc các chức năng tương tự, do đó gây ra lỗi trong chương trình của bạn.

Sử dụng strcpy để sao chép chuỗi origstr -

strcpy(origstr,"TheQuickBrownFoxJumpedOverTheLazyDog"); 

và sau đó bạn có thể free con trỏ của bạn origstr.

+0

Tôi đang sử dụng strncpy (newsubstr, origstr + 8, 8); bởi vì những gì tôi đang làm ở đó là lấy một chuỗi con của chuỗi gốc (ví dụ: "BrownFox").Tôi nghĩ rằng đây sẽ là cách dễ nhất để đi về nó (dựa trên một số điều tôi đã đọc). –

+0

@RavenLX Sau đó, có thể bạn có thể có một chuỗi chữ, Nhưng điều đó sẽ làm cho hằng số đó. Và tôi cũng nghĩ bạn đã rõ ràng về 'calloc' rằng bạn sử dụng lượng bộ nhớ lớn. 'calloc (37,1);' có thể đã làm điều đó cho bạn. – ameyCU

2

Vì có rò rỉ bộ nhớ. Bạn gán lại con trỏ, nó thực sự không chính xác để free() nó như bạn có nó.

Để sao chép nội dung vào phân bổ con trỏ sử dụng strcpy()

strcpy(origstr, "TheQuickBrownFoxJumpedOverTheLazyDog"); 

Hãy xem cách:

  1. Bạn yêu cầu bộ nhớ với calloc()

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

    điều này là sai vì nhiều lý do

    1. Bạn đang phân bổ không gian cho 9 con trỏ, không phải 9 ký tự.
    2. Bạn không thực sự cần calloc() vì bạn sẽ ghi đè nội dung ngay lập tức, sử dụng malloc().
  2. Bạn ghi đè lên con trỏ với một chuỗi chữ

    origstr = "TheQuickBrownFoxJumpedOverTheLazyDog"; 
    

    bây giờ bạn bị mất tài liệu tham khảo để con trỏ trở lại sớm hơn bởi calloc() và bạn có thể không thể free() nó, bạn chỉ nên free() con trỏ trở lại bởi malloc()/calloc()/realloc().

Sự thật là, bạn không cần phải calloc() con trỏ oristring, calloc()/malloc() không được sử dụng để cho phép bạn gán cho một con trỏ, nhưng để ghi vào bộ nhớ được trỏ đến bởi con trỏ, hoặc tốt hơn, để trỏ đến một số bộ nhớ bạn có thể đọc/ghi từ/đến.

+2

Nếu điều này "* Bạn không thực sự cần calloc() *" đề cập đến 'newsubstr', nó không đúng cho mã được hiển thị bởi OP. '0'-initialising' calloc() 'cơ bản là cần thiết, vì' strncpy() 'không * không * sao chép một terminator' 0'. – alk

4

Bằng cách chỉ định các chuỗi chữ để origstr bạn không sao chép chuỗi nhưng chỉ cần thay đổi giá trị origstr s, do đó làm mất con trỏ đến calloc. free ing origstr hiện đang gây ra hành vi không xác định.

Sử dụng strcpy hoặc strncpy để thực sự lưu trữ chuỗi trên heap. Nhưng thực sự giảm calloc cho origstr là đủ.


Ghi chú:

  • như @LeeDanielCrocker đề cập trong các ý kiến ​​để câu trả lời này, bạn có thể dùng để phân bổ không gian cho char s, không phải cho char* s, giảm kích thước của bộ nhớ phân bổ mạnh. Bạn nên thay thế sizeof(char*) bằng sizeof(char) (a.k.a. 1).
+0

Ngoài ra, anh ta phân bổ quá nhiều bộ nhớ: một chuỗi gồm 37 ký tự chỉ cần 38 byte (một số phụ cho số không kết thúc). Bạn đang cấp phát bộ nhớ cho 37 con trỏ ký tự; con trỏ có thể lớn đến 8 byte, đó là lý do tại sao khối bạn đang mất quá lớn. –

+0

@LeeDanielCrocker Ồ, điểm tốt. Sẽ thêm điều đó. – Downvoter

+0

Chuỗi chính nó chỉ có 36 ký tự, đó là lý do tại sao tôi đã sử dụng 37 ký tự (để bao gồm ý tưởng rằng sẽ có một terminator null). Tôi giả định rằng các terminator null được tự động đưa vào. Nhưng có lẽ nó không phải là? Tôi biết bây giờ tôi nên sử dụng strcpy vì vậy tôi nên sao chép vào nó "TheQuickBrownFoxJumpedOverTheLazyDog \ 0"? Điều đó có vẻ hơi lạ với tôi vì một lý do nào đó. –

Các vấn đề liên quan