簡體   English   中英

如何從函數返回字符串文字

[英]How to return a string literal from a function

關於從函數返回字符串文字或字符串我總是很困惑。 我被告知可能存在內存泄漏,因為您不知道何時會刪除內存?

例如,在下面的代碼中,如何實現foo()以使代碼的輸出是“Hello World”?

void foo (       )              // you can add parameters here.
{

}

int main ()
{
    char *c;
    foo (    );
    printf ("%s",c);
    return 0;
}

另外,如果foo()的返回類型不是void,但是你可以返回char* ,它應該是什么?

我假設我們無法修改main。 為了使您的程序在沒有泄漏的情況下工作,您需要具有靜態存儲的東西:

void foo(char*& pC)  // reference
{
    static char theString[] = "thingadongdong";

    pC = theString;
}

但實際上,這不是非常傳統的C ++代碼。 你會使用std::stringstd::cout ,所以你不必擔心內存:

std::string foo(void)
{
    return "better thingadongdong";
}

int main(void)
{
    // memory management is done
    std::cout << foo() << std::endl;
}

如果你想知道某些東西是否需要手動解除分配,那就錯了。

由於舊的char *使用已被棄用,你能不能簡單地使用字符串?

const char* func1 () {return "string literal";}

string func2 () {return "another string literal";}

這兩種工作都很好,沒有編譯器警告。

然而

char* func3 () {return "yet another string literal";}

根本不會編譯。 也不會

char* func4 () {return &"a ref to a string literal?";}

Stroustrup在“The C ++ Programming Language”(第三版)中說:

“字符串文字是靜態分配的,因此從函數返回一個是安全的。

const char* error_message (int i)`
{
//...
return "range error";
}

調用error_messages()后,內存保持范圍錯誤不會消失。“

因此,程序中的每個字符串文字都分配在自己的小內存中,該內存持續一段時間(即靜態分配)。 將const放在char *前面讓編譯器知道你不打算(並且不能)改變那個字符串文字的小內存可能是危險的,所以盡管從字符串文字轉換為char *,它們仍然允許這個賦值滑動已棄用。

返回到字符串必須將字符串文字復制到string類型的對象中,即調用者負責的內存。

無論哪種方式都沒有內存泄漏:每個字符串文字都有自己的內存,在程序終止時清理; 返回const char *返回一個指向文字內存的指針(知道你不能改變它); 並返回一個字符串,將一個副本復制到調用者代碼中存在的字符串對象中,該字符串對象由調用者清理。

雖然看起來有點丑陋的符號,但我猜他們離開了const char *來保留廉價替代品(不涉及副本)。

關於從函數返回字符串文字或字符串我總是很困惑。

不可變的文字字符串

據我了解,如果返回類型聲明為const,則可以直接返回字符串文字,以聲明該字符串不打算更改。 這意味着您無需擔心字符串/內存泄漏的生命周期。

可變的,非文字的字符串

但是,如果需要可以就地更改的字符串,則需要考慮字符串的生命周期以及存儲它的內存分配的大小。 這成為一個問題,因為您不能再為每次調用函數輕松地返回包含字符串的相同內存,因為之前的使用可能已經改變了該內存的內容,和/或可能仍在使用中。 因此,必須分配新的內存來保存返回的字符串。

這是發生泄漏的可能性,以及需要在何處進行分配和解除分配的選擇。 您可以讓函數本身在文檔中分配內存和狀態,並在其中規定調用者必須在不再需要時釋放內存(防止泄漏)。 這意味着該函數可以簡單地返回char *。

另一種選擇是將一些內存傳遞給調用者分配的函數,並讓函數將字符串放在該內存中。 在這種情況下,調用者既分配又負責釋放該內存。

最后,我提到在使用可變字符串時需要管理內存和字符串的大小。 對於最初由函數設置的字符串,以及在釋放內存之前在函數之后進行的任何更改,分配都必須足夠大。 如果不能正確執行此操作可能會導致緩沖區溢出,方法是將字符串寫入long以適合最初分配的內存; 這對您的計划的健康和安全極為危險。 它可能導致很難發現的錯誤和安全漏洞(因為錯誤的來源 - 溢出 - 可以遠離程序失敗時看到的症狀)。

像這樣的東西:

void foo(char ** pChar)
{
    // Make sure the string is shorter
    // than the buffer
    *pChar = new char[256];
    strcpy(*pChar,"Hello World!");
}

然后像這樣稱呼它:

foo(&c);

正如評論中所提到的,要小心你存儲的字符串小於緩沖區,否則你會得到...堆棧溢出! (雙關語)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM