2013-08-04 25 views
12

Tôi không phải là một lập trình viên C, vì vậy tôi không phải là quen thuộc với C-string nhưng mới tôi phải sử dụng một thư viện C vì vậy đây là một rút ngắn phiên bản của mã của tôi để chứng minh vấn đề của tôi:Sử dụng C-string: "Địa chỉ của bộ nhớ ngăn xếp gắn liền với biến địa phương trả lại"

char** ReadLineImpl::my_completion() { 

    char* matches[1]; 


    matches[0] = "add"; 

    return matches; 

} 

tôi nhận được một cảnh báo:

cảnh báo - địa chỉ bộ nhớ ngăn xếp gắn liền với biến địa phương phù hợp với 'trở

Và ứng dụng của tôi dường như không hoạt động đúng cách (có thể là do cảnh báo này).

cảnh báo là gì và nó sẽ gây ra bất kỳ vấn đề?

+3

Bạn đang trả lại địa chỉ cho con trỏ ký tự đầu tiên được cấp phát trên ngăn xếp và không tồn tại sau khi bạn thoát khỏi hàm. –

Trả lời

19

Biến số char* matches[1]; được khai báo trên ngăn xếp và sẽ tự động được giải phóng khi khối hiện tại nằm ngoài phạm vi.

Điều này có nghĩa là khi bạn quay trở lại matches, bộ nhớ dành riêng cho matches sẽ được giải phóng và con trỏ của bạn sẽ trỏ đến thứ bạn không muốn.

Bạn có thể giải quyết việc này bằng nhiều cách, và một số trong số đó là:

  1. Khai matches[1] như static: static char* matches[1]; - này sẽ phân bổ không gian cho matches trên đống (điều này có thể cắn bạn nếu bạn sử dụng nó unappropriately, như tất cả các trường hợp của my_completion chức năng sẽ chia sẻ cùng một biến matches).

  2. Phân bổ không gian trong hàm gọi và vượt qua nó để my_completion chức năng: my_completion(matches):

    char* matches[1]; 
    matches = my_completion(matches); 
    
    // ... 
    
    char** ReadLineImpl::my_completion (char** matches) { 
        matches[0] = "add"; 
    
        return matches; 
    } 
    
  3. Phân bổ không gian trong gọi là chức năng trên đống (sử dụng malloc, calloc, và bạn bè) và vượt qua quyền sở hữu với chức năng người gọi, mà sẽ phải deallocate không gian này khi không cần thiết nữa (sử dụng free).

+0

Cảm ơn tôi đã hiểu. Điều tồi tệ nhất là đây là lần thứ hai có được loại vấn đề này :) anyways, cảm ơn bạn rất nhiều – khajvah

+0

Giả sử rằng đó là 'GNU readline', điều này sẽ gây ra sự cố, vì' readline' sẽ giải phóng bộ nhớ được trả về bởi chức năng hoàn thành. –

+0

@MatsPetersson Điều này có vẻ giống như readline - và trong trường hợp đó bạn là đúng. Tôi sẽ upvote câu trả lời của bạn! –

7

Khi bạn trả lại mảng matches, những gì bạn đang quay trở lại là địa chỉ của phần tử đầu tiên. Điều này được lưu trữ trên ngăn xếp bên trong my_completion. Khi bạn trở về từ my_completion mà nhớ được khai hoang và sẽ (rất có thể) cuối cùng sẽ được tái sử dụng cho cái gì khác, ghi đè lên các giá trị được lưu trữ trong matches - và có, mà cũng có thể là lý do tại sao ứng dụng của bạn không hoạt động - nếu nó không phải là đúng bây giờ, nó có thể sẽ là một khi bạn đã sửa một số vấn đề khác, hoặc thay đổi nó một chút, hoặc cái gì khác, bởi vì đây không phải là một trong những cảnh báo nhỏ mà bạn có thể bỏ qua một cách an toàn.

Bạn có thể sửa lỗi này trong một vài cách khác nhau.Rõ ràng nhất là chỉ cần sử dụng std::vector<char *> [hoặc tốt hơn chưa std::vector<std::string>] thay vì:

std::vector<std::string> ReadLineImpl::my_completion() 
{ 
    std::vector<std::string> strings; 
    strings.push_back("add"); 
    return strings; 
} 

Edit: Vì vậy, nếu thư viện đòi hỏi một char ** theo giao diện readline, sau đó sử dụng này:

char** ReadLineImpl::my_completion() 
{ 
    char **matches = static_cast<char **>malloc(1 * sizeof(char *)); 
    matches[1] = "add"; 
    return matches; 
} 

Đã giải quyết được vấn đề!

+0

Tôi sẽ sử dụng một vectơ làm lập trình C++ nhưng yêu cầu thư viện char **, vì vậy sau đó tôi phải chuyển sang char **. – khajvah

+0

Vì vậy, giả sử bạn đang sử dụng giao diện 'readline', thì bạn PHẢI cấp phát bộ nhớ với malloc, vì' readline' giải phóng nó sau này. Tôi sẽ chỉnh sửa. –

+0

Tốt, chỉ một điều, tôi đã phải sử dụng (char **) malloc (1 * sizeof (char *)) nhưng cảm ơn, câu trả lời của bạn tốt hơn, mặc dù tôi sẽ không thay đổi – khajvah

0

thay đổi

char* matches[1]; 

để

char *matches = new matches[1]; 
+0

Tại sao? Có lẽ, Bạn nên mô tả lý do để làm như vậy. –

0

Sử dụng đống thay vì ngăn xếp

Nó tốt hơn để cấp phát bộ nhớ trong heap cho trường hợp này bằng cách sử dụng:

int* someDataForParams(void *_params) { 

    ... 
    int* charCounts = calloc(96, sizeof(char*)); 
    ... 

    return charCounts; 
} 

96 chỉ là một chuỗi dài (Chỉ cần một số ma thuật)

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