2011-01-28 37 views
31
#include <stdio.h> 

int foo1(void) 
{ 
    int p; 
    p = 99; 
    return p; 
} 

char *foo2(void) 
{ 
    char buffer[] = "test_123"; 
    return buffer; 
} 

int *foo3(void) 
{ 
    int t[3] = {1,2,3}; 
    return t; 
} 

int main(void) 
{ 
    int *p; 
    char *s; 

    printf("foo1: %d\n", foo1()); 
    printf("foo2: %s\n", foo2()); 
    printf("foo3: %d, %d, %d\n", p[0], p[1], p[2]); 
    return 0; 
} 

Khi tôi biên dịch này với gcc -ansi -pedantic -W -Wall các vấn đề biên dịch thông điệp cảnh báo cho foo2() và foo3():trở về một biến địa phương từ hàm trong C

warning: function returns address of local variable 

tôi nghĩ rằng nó không được phép trả lại một biến cục bộ, nhưng foo1() hoạt động tốt và có vẻ như có một sự khác biệt lớn giữa việc trả về con trỏ tới một đối tượng cục bộ và chính đối tượng đó.

Ai đó có thể làm sáng tỏ vấn đề này? Cảm ơn trước!

Trả lời

21

Vấn đề ở đây là khi bạn tạo biến cục bộ được cấp phát trên ngăn xếp và do đó không khả dụng khi hàm kết thúc thực thi (triển khai thay đổi tại đây). Cách thích hợp hơn là sử dụng malloc() để đặt trước bộ nhớ không phải cục bộ. sự nguy hiểm ở đây là bạn phải deallocate (free()) tất cả mọi thứ bạn phân bổ sử dụng malloc(), và nếu bạn quên, bạn tạo ra một rò rỉ bộ nhớ.

+0

Một mối nguy hiểm khác là nếu bạn không đặt lại (ví dụ: 'memset') bộ nhớ được cấp phát, nó có thể làm rò rỉ thông tin từ ngăn xếp. – jweyrich

5

Biến bất kỳ có một số khoảng trống trong bộ nhớ. Một con trỏ tham chiếu không gian đó. Không gian mà các biến cục bộ chiếm được deallocated khi gọi hàm trả về, có nghĩa là nó có thể và sẽ được tái sử dụng cho những thứ khác. Kết quả là, các tham chiếu đến không gian đó sẽ hướng đến một thứ hoàn toàn không liên quan. Mảng trong C được thực hiện như con trỏ, do đó, gió này áp dụng cho chúng. Và các mảng liên tục được khai báo trong một hàm cũng được tính là cục bộ.

Nếu bạn muốn sử dụng mảng hoặc con trỏ khác ngoài phạm vi của hàm mà hàm được tạo, bạn cần sử dụng malloc để đặt chỗ cho nó. Không gian dành riêng cho việc sử dụng malloc sẽ không được phân bổ lại hoặc tái sử dụng cho đến khi nó được phát hành rõ ràng bằng cách gọi miễn phí.

+2

+1. Trong thực tế điều này có nghĩa là bạn cần phải phân bổ một giá trị trả về trên heap thay vì trên stack. Bạn cần sử dụng malloc hoặc similair trên "mảng" mà bạn muốn trả về. Hoặc tốt hơn hết, lấy một con trỏ đến một bộ đệm + chiều dài đệm như các tham số. – stefan

+0

@stefan: Vâng, đó là một điểm tốt. Tôi đã thêm nhiều đề xuất hơn về cách giải quyết vấn đề này cho câu trả lời. –

+1

'Mảng trong C được thực hiện như con trỏ' là một quá đơn giản; nó là ranh giới chấp nhận được cho bối cảnh, nhưng có sự khác biệt lớn giữa mảng và con trỏ (cũng như rất nhiều điểm tương đồng). –

15

Đối với foo1(), bạn trả lại sao chép của biến cục bộ, chứ không phải biến cục bộ.

Đối với các chức năng khác, bạn trả lại bản sao của con trỏ thành biến cục bộ. Tuy nhiên, biến cục bộ đó được deallocated khi hàm kết thúc, vì vậy bạn kết thúc với các vấn đề khó chịu nếu bạn cố gắng tham chiếu nó sau đó.

0

Có bạn đang trả về một mảng, đó thực sự là một con trỏ phía sau hậu trường, đến địa chỉ của vị trí bộ nhớ mà nội dung của biến mà bạn đã khởi tạo được lưu trữ. Vì vậy, nó cảnh báo bạn rằng nó có thể không được khá hữu ích để trả lại kết quả như vậy, khi bạn thực sự có thể có nghĩa là một trong những giá trị mảng thay thế.

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