2008-09-19 55 views
17

Tôi nghĩ rằng tôi đã rút gọn đối với trường hợp cơ bản nhất:Malloc bên trong một cuộc gọi chức năng dường như được trả tự do khi trở về?

int main(int argc, char ** argv) { 
    int * arr; 

    foo(arr); 
    printf("car[3]=%d\n",arr[3]); 
    free (arr); 
    return 1; 
} 

void foo(int * arr) { 
    arr = (int*) malloc(sizeof(int)*25); 
    arr[3] = 69; 
} 

Kết quả là thế này:

> ./a.out 
car[3]=-1869558540 
a.out(4100) malloc: *** error for object 0x8fe01037: Non-aligned pointer 
         being freed 
*** set a breakpoint in malloc_error_break to debug 
> 

Nếu bất cứ ai có thể làm sáng tỏ nơi hiểu biết của tôi là không, nó muốn được đánh giá cao.

Trả lời

47

Bạn vượt qua con trỏ bởi giá trị, chứ không phải bằng tham khảo, vì vậy bất cứ điều gì bạn làm với arr bên trong foo sẽ không tạo sự khác biệt bên ngoài hàm foo. Như m_pGladiator đã viết một cách là để khai báo một tham chiếu đến con trỏ như thế này (chỉ có thể có trong C++ btw C không biết về tài liệu tham khảo.):

int main(int argc, char ** argv) { 
    int * arr; 

    foo(arr); 
    printf("car[3]=%d\n",arr[3]); 
    free (arr); 
    return 1; 
} 

void foo(int * &arr) { 
    arr = (int*) malloc(sizeof(int)*25); 
    arr[3] = 69; 
} 

khác (tốt hơn IMHO) Cách thứ nhất là không vượt qua được con trỏ như một đối số nhưng để trả về một con trỏ:

int main(int argc, char ** argv) { 
    int * arr; 

    arr = foo(); 
    printf("car[3]=%d\n",arr[3]); 
    free (arr); 
    return 1; 
} 

int * foo(void) { 
    int * arr; 
    arr = (int*) malloc(sizeof(int)*25); 
    arr[3] = 69; 
    return arr; 
} 

Và bạn có thể chuyển con trỏ tới con trỏ. Đó là cách C đi qua tham chiếu. Làm phức tạp cú pháp một chút nhưng cũng - đó là cách C là ...

int main(int argc, char ** argv) { 
    int * arr; 

    foo(&arr); 
    printf("car[3]=%d\n",arr[3]); 
    free (arr); 
    return 1; 
} 

void foo(int ** arr) { 
    (*arr) = (int*) malloc(sizeof(int)*25); 
    (*arr)[3] = 69; 
} 
+0

Tôi có thể nói, vui lòng không truyền giá trị trả lại của malloc? Nó không phải là bắt buộc và có thể ẩn các lỗi. – freespace

+0

@freespace, đó là một thói quen tôi đã phát triển qua nhiều năm. Mỗi một và sau đó tôi phải gửi mã của tôi thông qua các công cụ phân tích mã tĩnh, và họ phàn nàn về việc không đưa con trỏ. –

+0

Xin lỗi vì đã để bạn treo mà không trả lời: không có cách nào tốt để tìm câu trả lời trong nhận xét trừ khi tôi bình chọn tất cả các ý kiến ​​của tôi :) Tôi đã để lại câu trả lời trong http://stackoverflow.com/questions/108768/needless- pointer-casts-in-C# 108781 – freespace

6

Bạn đã cấp phát arr trong foo, nhưng giá trị con trỏ đó được lưu trữ trong ngăn xếp cuộc gọi. Nếu bạn muốn làm điều này, làm điều đó như thế này:

void foo(int ** arr) { 
    *arr = (int *)malloc(sizeof(int) * 25); 
    (*arr)[3] = 69; 
} 

Và trong chính, chỉ cần vượt qua một con trỏ đến foo (như foo (& arr))

0

Bạn không thể thay đổi giá trị của các đối số của bạn (arr) nếu nó không được thông qua trong bằng cách tham khảo (&). Nói chung, bạn sẽ muốn trả về con trỏ, vì vậy phương pháp của bạn phải là:

arr = foo();

Juju xấu để cố gắng chỉ định lại đối số; Tôi không khuyến nghị giải pháp (&).

3

foo nhận bản sao cục bộ của con trỏ int, bộ nhớ alloactes và rò rỉ bộ nhớ khi nó nằm ngoài phạm vi.

Một cách để sửa lỗi này để có được foo để trả lại con trỏ:

int * foo() { 
    return (int*) malloc(sizeof(int)*25); 
} 

int main() { 
    int* arr = foo(); 
} 

khác là để vượt qua foo một con trỏ đến một con trỏ

void foo(int ** arr) { 
    *arr = malloc(...); 
} 

int main() { 
    foo(&arr); 
} 

Trong C++ nó là đơn giản để sửa đổi foo để chấp nhận một tham chiếu đến một con trỏ. Thay đổi duy nhất bạn cần trong C++ là thay đổi foo thành

void foo(int * & arr) 
1

Vì bạn đang chuyển con trỏ theo giá trị, con trỏ arr bên trong chính không trỏ đến bộ nhớ được cấp phát. Điều này có nghĩa là hai điều: bạn đã có một rò rỉ bộ nhớ (NO, bộ nhớ không được giải phóng sau khi hàm foo hoàn thành), và khi bạn truy cập vào con trỏ arr bên trong chính bạn đang truy cập một số phạm vi tùy ý của bộ nhớ, do đó bạn không Không nhận được 3 in ra và do đó miễn phí() từ chối làm việc. Bạn may mắn là bạn không nhận được lỗi phân đoạn khi truy cập arr [3] bên trong chính.

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