【轉】函數返回局部變數

來源:互聯網
上載者:User

標籤:

(看到C++ Primer(P.225)“return reference to local object”時有點懵,然後找到了這篇博文。)

 

一般的來說,函數是可以返回局部變數的。 局部變數的範圍只在函數內部,在函數返回後,局部變數的記憶體已經釋放了。因此,如果函數返回的是局部變數的值,不涉及地址,程式不會出錯。但是如果返回的是局部變數的地址(指標)的話,程式運行後會出錯。因為函數只是把指標複製後返回了,但是指標指向的內容已經被釋放了,這樣指標指向的內容就是不可預料的內容,調用就會出錯。準確的來說,函數不能通過返回指向棧記憶體的指標(注意這裡指的是棧,返回指向堆記憶體的指標是可以的)。
1. 返回局部變數的值

可以有兩種情況:返回局部自動變數和局部靜態變數,比如,

int func(){    int temp = 0;   // 返回局部自動變數的值    return temp;}

局部變數temp儲存在棧中,函數返回時會自動複製一份temp的copy給調用者,沒有問題。

int func(){    static int a = 1;   // 返回局部靜態變數的值    return a;}

局部變數a儲存在靜態(全域)儲存區中,從初始化後一直有效直到程式結束,僅分配一次記憶體,並且函數返回後,變數不會銷毀,沒有問題。

vector func(){    vector v;    v.push_back(0);    return v;}

返回的是v的值拷貝,沒有問題。

Person func(){    Person p1;    p1.name = "test";    return p1;}

返回的也是值拷貝,會調用Person類的拷貝建構函式,沒有問題。

2. 返回局部變數的指標

int* func(){    int temp = 0;   // 返回局部變數的地址    return &temp;}

前面討論過,局部變數temp儲存在棧中,函數返回時將已銷毀變數的地址返回給調用者,結果將是不可預知的。

int* func(){    static int temp = 1;    return &temp;}

局部變數temp儲存在靜態儲存區,返回指向靜態儲存區變數的指標是可行的。

char* func(){    char *p = "test";    return p;   // 返回指向常量字串的指標}

對於字串的特殊情況,由於字串test儲存在常量儲存區(不是靜態儲存區),因此函數返回一個指向常量的字串指標是可行的。

char* func(){    char str[] = "test";    return str; // 返回局部字串的指標}

這種情況下,str被初始化為字串局部變數,因此函數返回一個已銷毀的局部變數是不可行的。解決辦法就是將字串str聲明為static。

char* func(){    char *str = (char *)malloc(sizeof(char) * BUFFER_SIZE);    strcpy(str, "test");    return str;}

這種情況下,函數返回一個指向堆記憶體的指標,由於堆儲存區由程式員手動管理,因此這種做法是可行的,但是要防止出現記憶體泄露,函數調用完後需要手動釋放記憶體。這裡的sizeof作用於指標返回的是指標類型的長度1byte,而如果作用於數組返回的則是數組的長度。

char *temp = NULL;temp = func();// some operation...free(temp);

3. 返回局部變數的引用

int& func(){    int temp = 0;   // 返回局部變數的引用    return temp;}

由引用的概念可知,函數返回的是temp本身,而temp在函數返回後已銷毀,結果將是不可預知的。

補充:靜態全域變數和全域變數的區別

靜態全域變數只在當前檔案中可用,全域變數在其他檔案中也可用,需要用extern聲明。

全域變數和靜態變數如果沒有手動初始化,則預設由編譯器初始化為0。

1>

#include    char *returnStr()   {       char *p="hello world!";       return p;   }   int main()   {       char *str;       str=returnStr();       printf("%s\n", str);       return 0;   } 
這個沒有任何問題,因為"hello world!"是一個字串常量,存放在唯讀資料區段,把該字串常量存放的唯讀資料區段的首地址賦值給了指標,所以returnStr函數退出時,該該字串常量所在記憶體不會被回收,故能夠通過指標順利無誤的訪問。

 

2>

#include <stdio.h>   char *returnStr()   {       char p[]="hello world!";       return p;   }   int main()   {       char *str;       str=returnStr();       printf("%s\n", str);       return 0;   }   
"hello world!"是局部變數存放在棧中。當returnStr函數退出時,棧要清空,局部變數的記憶體也被清空了,所以這時的函數返回的是一個已被釋放的記憶體位址,所以有可能列印出來的是亂碼。 

 

3>

int func()  {        int a;        ....        return a;    //允許  }                       int * func()  {        int a;        ....        return &a;    //無意義,不應該這樣做  }   

局部變數也分局部自動變數和局部靜態變數,由於a返回的是值,因此返回一個局部變數是可以的,無論自動還是靜態,

因為這時候返回的是這個局部變數的值,但不應該返回指向局部自動變數的指標,因為函數調用結束後該局部自動變數

被拋棄,這個指標指向一個不再存在的對象,是無意義的。但可以返回指向局部靜態變數的指標,因為靜態變數的生存

期從定義起到程式結束。

 4>如果函數的傳回值非要是一個局部變數的地址,那麼該局部變數一定要申明為static類型。如下:
#include <stdio.h>   char *returnStr()   {       static char p[]="hello world!";       return p;   }   int main()   {       char *str;        str=returnStr();       printf("%s\n", str);         return 0;   }   
 5>數組是不能作為函數的傳回值的,原因是編譯器把數組名認為是局部變數(數組)的地址。返回一個數組一般用返回指向這個數組的指標代替,而且這個指標不能指向一個自動數組,因為函數結束後自動數組被拋棄,但可以返回一個指向靜態局部數組的指標,因為靜態儲存期是從對象定義到程式結束的。如下:
int* func( void )  {      static int a[10];      ........      return a;  }   

 

6>返回指向堆記憶體的指標是可以的

char *GetMemory3(int num)  {  char *p = (char *)malloc(sizeof(char) * num);  return p;  }  void Test3(void)  {  char *str = NULL;  str = GetMemory3(100);  strcpy(str, "hello");  cout<< str << endl;  free(str);  }  

 

程式在啟動並執行時候用 malloc 申請任意多少的記憶體,程式員自己負責在何時用 free釋放記憶體。動態記憶體的生存期由程式員自己決定,使用非常靈活。 

【轉】函數返回局部變數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.