MikeHK
Lv 5
MikeHK 發問時間: 電腦與網際網路程式設計 · 7 年前

有誰可以說明下回傳指標為何不會出問題?

內容是這樣

int *func()

{

int a = 100;

return &a;

}

或是這樣

char* get_error_description(error_code_t error_code)

{

char *a="12345";

return a;

}

回傳後馬上使用指標內容, 或一段 code 後才用回傳的資料.

這樣不會出問題嗎?

已更新項目:

不好意思我改名字, 這暱稱太多人用了, Mike 改 MikeHK

2 個已更新項目:

感謝 退隱江湖 及 prisoner 的說明, 這部分看起來很清楚, 有一些答案,

我舉的例子可能不太好, 可否在幫忙下個例子

char* get_error_description()

{

char a[32];

strcpy( a, "12345");

return a;

}

3 個已更新項目:

顯然的 a[32] 是放 stack, 是否也不該使用?

求證了下=>

1.上式 "12345" 也放在 .rdata 區=> 所以這樣做, 寫程式的人自行考慮下!

2.同 prisoner 提的前面那個例子, 回傳的是 .rdata 區, 你無法改他.

errDesp[1] = '\0'; //有問題

4 個已更新項目:

附記:

寫了N 年的程式, 只知道不這樣用, 今天搞得最清楚, 不過以後我也不會這樣用.

這邊高手很多, 再感謝這些高手.

這板留二天就結案, 有問題的人, 是否趁機在意見欄裡問問!

5 個解答

評分
  • 7 年前
    最佳解答

    第一個函式的寫法顯然有很大的問題,原因就如同版大所述:a 是 local 變數。

    因為 local 變數是儲存在堆疊(stack)區中,隨時都有可能會被其它的資料蓋過。

    當函式呼叫結束後也代表著其中的 local 變數的生命期結束,

    此時就不應該再去存取已經結束生命的變數,

    雖說立即使用回傳值時似乎不會出問題(因為還來不及被其它資料蓋過),

    但是只要再呼叫過其它的函式後,該位址的內容就幾乎可以保證一定會被破壞了。

    所以這種寫法完全不值得鼓勵。(某些好心的 compiler 甚至還會出現警告)我想版大最主要想問的應該是第二個函式的寫法會不會有問題吧?

    答案是:沒有問題。

    為了簡化起見,我們就只要解釋 char *a = "12345"; 這一行就好了。

    變數 a 本身雖然也是一個 local 變數,但因為它是一個指標 (char *),

    且函式所傳回的也是該指標的值(即位址),所以重點就變成:

    該「位址」到底能不能在函式呼叫結束後,合法地被使用呢?

    因為 a 被指向 "12345" 的位址,而 "12345" 是個常數字串,

    在經過 compile/link 後它的儲存位置就已經被確定了

    (通常會是在 .rdata section,即唯讀資料區),所以在程式的整個執行期間,

    該位址一直都是存在且不變的。 (唯讀區還會順便保護資料不被改變)綜合上述,因為兩個函式都是傳回一個「位址」,

    所以能不能合法使用就要看該位址到底是屬於哪個區域了。

    若是屬於堆疊(stack)區就不能用 -- 至少強烈不建議。

    若是該位址是屬於一直存在的區域 (例如全域或 static 變數),那麼就可以放心使用。如果您可以將兩個函式的回傳值(即位址)印出來比較一下的話,

    就會發現它們的位址應該會差蠻遠的。

    希望對您有幫助!

    2013-06-17 15:26:48 補充:

    補充的問題的確也是不該這樣使用,

    因為函式回傳的是 a (在 stack 中) 的位址,

    而不是 "12345" (在 .rdata 中) 的位址。

    另外,因為原題中並看不出有要討論 const 的意思 (那又是另一大主題),

    因此為了簡化起見並未多加著墨,以致引起一些疑慮。

    以原題的第二個函式為例,如果可以預知回傳的會是一個唯讀資料的話,

    那麼將函式宣告成 const char* ... 會是比較好的做法。

    反之,如果回傳的資料是需要可以修改的話,那就得用不同的思維來重新規劃了。

  • MikeHK
    Lv 5
    7 年前

    static 是公用變數, 函是結束也還在那, 不會有問題, 玄的是 Local 變數,

    蠻多習慣這樣用的人,

  • 7 年前

    請問阿旺

    是怎麼判斷時機要加或不加static?

    thanks

  • 7 年前

    會不會出問題? 那要看 她在被傳回後怎麼 與何時 被用到

    2013-06-17 05:23:55 補充:

    可不可用是一回事 該不該用是另一回事

    ANS001所說的 都是implementation (or OS) dependent 就算是可以用 不該用就不要用

    不然為神要OOP又要public又要 private就是要防指一群聰明人 愛用不該用的

    2013-06-17 05:27:27 補充:

    >>我想版大最主要想問的應該是第二個函式的寫法會不會有問題吧?

    >>答案是:沒有問題。

    當然有問題 如下:

    char *errDesp = get_error_description(400);

    errDesp[1] = '\\0'; //有問題

  • 您覺得這個回答如何?您可以登入為回答投票。
  • ㄚ旺
    Lv 5
    7 年前

    static int a = 100;

還有問題?馬上發問,尋求解答。