指向臨時變數的指標的返回

來源:互聯網
上載者:User

一直以為對於函數返回的指標瞭解得還可以,但是真實不用不知道,一用嚇一跳。今天在一篇部落格上面看到如下兩段代碼,部落格的作者給出了一個問題,但是並沒有解釋為什麼不同。自己通過實驗給出瞭解釋,但是不知道對不對,僅供參考!

下面是個錯誤的例子:
char* get_str(void)
{
    char str[] = {"abcd"};
     return str;
}
int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%s\n", p);
     return 0;
}

下面這個例子沒有問題,大家知道為什麼嗎?
char* get_str(void)
{
    char* str = {"abcd"};
     return str;
}
int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%s\n", p);
     return 0;
}
我在linux環境下面驗證了作者的說法,的確是那樣,上面一個有錯,下面一個正確。問題就出在一個用的是數群組類型,而另外一個用的是指標類型(從側面亦可以看出並不是有些大學老師說的那樣char str[]等價於char* str),由於棧裡面的變數都是臨時的。當前函數執行完成時,相關的臨時變數和參數都被清除了。不能把指向這些臨時變數的指標返回給調用者,這樣的指標指向的資料是隨機的,會給程式造成不可預料的後果。但是指標卻有所不同,指標的地址在棧上,但是它所指向的內容卻是在堆上面,所以並沒有被清除。這就是為什麼一個正確一個錯誤的原因。

其實這部落格提前寫了一天,我並沒有發表,因為怕自己理解得有錯,所以跟部落格的作者寫信交流下了,下面貼出我們的信件內容,希望對需要的朋友有所協助:

 

 問:
大家都知道,棧裡面的變數都是臨時的。當前函數執行完成時,相關的臨時變數和參數都被清除了。不能把指向這些臨時變數的指標返回給調用者,這樣的指標指向的資料是隨機的,會給程式造成不可預料的後果。
下面是個錯誤的例子:
char* get_str(void)
{
    char str[] = {"abcd"};
     return str;
}
int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%s\n", p);
     return 0;
}

下面這個例子沒有問題,大家知道為什麼嗎?
char* get_str(void)
{
    char* str = {"abcd"};
     return str;
}
int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%s\n", p);
     return 0;
}
我在linux環境下跑了,對代碼做了點修改,相應的修改和運行結果如下:
#include <stdio.h>
char* get_str(void)
{
    char str[] = {"abcd"};
     return str;
}
int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%d/n", *p);
     printf("%d/n", *(p+1));
     return 0;
}
運行結果:
[root@localhost singnode]# ./ss
97
-12
 
#include <stdio.h>
char* get_str(void)
{
    char* str = {"abcd"};
     return str;
}
int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%d/n", *p);
     printf("%d/n", *(p+1));
     return 0;
}
運行結果:
[root@localhost singnode]# ./cc
97
98

對於這樣的運行結果是不是因為指標的地址雖然是在棧上,但是它指向的內容卻是在堆上面,所以並沒有被清除。而數組的地址和內容都是在棧上面(首地址除外),所以出錯。而對於     printf("%d/n", *p);能夠輸出正確的97,是因為首地址被當成指標來處理了,所以它的內容儲存在堆上面,而其它的值儲存在棧上面則被清除,從而產生了隨機值,如-12。

(在此解釋下我最初的理解,紅字部分,一開始我並不知道數組返回的p也是正確的值,只是在調用printf語句後p的值才被破壞掉了,所以這是我之前根據運行結果來做的解釋,在此糾正下。)

 

答:

int main(int argc, char* argv[])
{
    char* p = get_str();
     printf("%d/n", *p);
     printf("%d/n", *(p+1));
     return 0;
}
運行結果:
[root@localhost singnode]# ./cc
97
98

對於這樣的運行結果是不是因為指標的地址雖然是在棧上,但是它指向的內容卻是在堆上面,所以並沒有被清除。而數組的地址和內容都是在棧上面(首地址除外),所以出錯。

答:是的。

而對於     printf("%d/n", *p);能夠輸出正確的97,是因為首地址被當成指標來處理了,所以它的內容儲存在堆上面,而其它的值儲存在棧上面則被清除,從而產生了隨機值,如-12。

答:

    char* p = get_str();
此時p指向的內容還沒有破壞,你可以在調試器中看一下。
     printf("%d/n", *p);
此時因為調用了printf,所以p就被破壞了。

     printf("%d/n", *(p+1));

即使再調用:
     printf("%d/n", *p);
結果也是錯誤的。

 

這是最後寫的回信:

非常感謝!我驗證了下,如下:
(gdb) print p
$2 = 0xbffff703 "dbcd"
(gdb) s
98
12      printf("%d/n", *p);
(gdb) print p
$3 = 0xbffff703 "��/017m"
(gdb)
在調用printf之前的p內容還沒有被破壞掉,但是調用printf之後就被破壞了

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.