2013-03-03 19 views
5

Tôi đang bối rối với việc sử dụng free() liên quan đến cấu trúc dữ liệu trong C.Confused bởi malloc và hành vi tự do

Nếu tôi đã cấu trúc dữ liệu sau đây:

struct Person { 
    char *name; 
    int age; 
    float weight; 
    float height; 
}; 

Tôi đang phân bổ bộ nhớ cho các cấu trúc qua malloc(), tương tự như vậy: struct Person *me = malloc(sizeof(struct Person));

Sau khi tôi đang thực hiện với việc sử dụng cấu trúc của tôi (ngay trước khi kết thúc chương trình), tôi tiến tới giải phóng bộ nhớ được phân bổ như sau:

free(person_pointer->name); 
free(person_pointer); 

Giải phóng bộ nhớ rằng name điểm con trỏ đến là cần thiết để hiểu biết của tôi, bởi vì nếu tôi chỉ miễn phí person_pointerTôi chỉ giải phóng bộ nhớ đã được phân bổ để lưu trữ các cấu trúc dữ liệu và các thành viên của nónhưng không phải là bộ nhớ được chỉ ra bởi các thành viên con trỏ của cấu trúc.

Tuy nhiên, việc triển khai của tôi valgrind dường như cho thấy rằng free() đầu tiên không hợp lệ.

Vì vậy, câu hỏi của tôi tóm tắt: Khi tôi giải phóng bộ nhớ mà cấu trúc chiếm thông qua một con trỏ, tôi có nên miễn phí bộ nhớ mà các con trỏ thành viên trỏ tới hay không?

EDIT: Đây là toàn bộ mã của tôi:

#include <stdio.h> 
#include <stdlib.h> 

struct Person { 
    char *name; 
    int age; 
    float weight; 
    float height; 
}; 

int main(int argc, char **argv) 
{ 
    struct Person *me = malloc(sizeof(struct Person)); 
    me->name = "Fotis"; 
    me->age = 20; 
    me->height = 1.75; 
    me->weight = 75; 

    printf("My name is %s and I am %d years old.\n", me->name, me->age); 
    printf("I am %f meters tall and I weight %f kgs\n", me->height, me->weight); 

    free(me->name); 
    free(me); 

    return 0; 
} 
+0

@ Tôi làm malloc(). Tôi sẽ chỉnh sửa câu hỏi để làm rõ điều này. – NlightNFotis

+0

@Mat Chỉ cần cập nhật câu hỏi với phương thức phân bổ của tôi. Nếu bạn cần thêm thông tin, tôi có thể đăng toàn bộ mã của tôi, đó là một chương trình khá nhỏ, tuy nhiên từ bây giờ tôi sẽ không làm như vậy vì mục đích rõ ràng. – NlightNFotis

+1

+1 cho trường hợp thử nghiệm hoàn chỉnh, sử dụng Valgrind, v.v. –

Trả lời

5
me->name = "Fotis"; 

/* ... */ 

free(me->name); 

Quy tắc là:

1 malloc = 1 free 

Bạn đã không sử dụng malloc trên me->name, vì vậy bạn không cần phải free.

BTW, me->name phải thuộc loại const char *.

1

Khi bạn làm

me->name = "Fotis"; 

Con trỏ name không alloced bởi malloc, nó trỏ tới một biến ngăn xếp được lưu trữ trong bảng chuỗi của tập tin nhị phân của bạn tại thời gian biên dịch, do đó bạn có thể không được tự do nó.

Quy tắc chung là: Chỉ miễn phí những gì bạn đã bỏ phiếu.

Tuy nhiên, bạn không thể cập nhật chuỗi chỉ đọc này.

Nếu bạn đã làm điều gì đó như:

me->name = strdup("Fotis"); 

Kể từ strdup hiện một malloc (xem hướng dẫn), bạn phải giải phóng nó, và bạn có thể cập nhật các chuỗi sau khi tạo nó.

1

Có bạn phải giải phóng toàn bộ bộ nhớ của con trỏ bên trong cấu trúc nếu bạn đã phân bổ chúng.

Cũng đảm bảo bạn giải phóng các thành viên trước khi bạn giải phóng cấu trúc.

Cách đơn giản để nhớ là giải phóng chúng theo thứ tự ngược lại mà bạn đã phân bổ.

1

Vấn đề là bạn đã không thực sự malloc'ed tên char * bên trong cấu trúc của bạn.

struct Person *me = malloc(sizeof(struct Person)); 
me->name = strdup("Fotis"); 
... 
free(me->name); 
free(me); 
return (0); 

Khi bạn viết này

me->name = "Fotis"; 

Bạn không thực sự malloc, những điểm tên con trỏ tới một chồng biến kiểu const char *, mà không malloc'ed.

+3

'strdup' không phải là hàm thư viện chuẩn. Có lẽ tốt nhất không nên giới thiệu nó ... –

+0

Chuỗi chữ được lưu trữ tĩnh, không phải trên ngăn xếp. Một con trỏ đến nó sẽ hợp lệ trong bất kỳ hàm nào ở bất kỳ đâu trong chương trình. – teppic