天天看點

C語言的那些秘密之--函數傳回局部變量

一般的來說,函數是可以傳回局部變量的。 局部變量的作用域隻在函數内部,在函數傳回後,局部變量的記憶體已經釋放了。是以,如果函數傳回的是局部變量的值,不涉及位址,程式不會出錯。但是如果傳回的是局部變量的位址(指針)的話,程式運作後會出錯。因為函數隻是把指針複制後傳回了,但是指針指向的内容已經被釋放了,這樣指針指向的内容就是不可預料的内容,調用就會出錯。準确的來說,函數不能通過傳回指向棧記憶體的指針(注意這裡指的是棧,傳回指向堆記憶體的指針是可以的)。
下面以函數傳回局部變量的指針舉幾個典型的例子來說明:
           
#include <stdio.h> 
char *returnStr() 
{ 
    char *p="hello world!"; 
    return p; 
} 
int main() 
{ 
    char *str; 
    str=returnStr(); 
    printf("%s\n", str); 
    return ; 
}
           

這個沒有任何問題,因為”hello world!”是一個字元串常量,存放在隻讀資料段,把該字元串常量存放的隻讀資料段的首位址指派給了指針,是以returnStr函數退出時,該該字元串常量所在記憶體不會被回收,故能夠通過指針順利無誤的通路。

#include <stdio.h> 
char *returnStr() 
{ 
    char p[]="hello world!"; 
    return p; 
} 
int main() 
{ 
    char *str; 
    str=returnStr(); 
    printf("%s\n", str); 
    return ; 
} 
           

“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 ; 
} 
           

5: 數組是不能作為函數的傳回值的,原因是編譯器把數組名認為是局部變量(數組)的位址。傳回一個數組一般用傳回指向這個數組的指針代替,而且這個指針不能指向一個自動數組,因為函數結束後自動數組被抛棄,但可以傳回一個指向靜态局部數組的指針,因為靜态存儲期是從對象定義到程式結束的。如下:

int* func( void )
{
    static int a[];
    ........
    return a;
} 
           

6:傳回指向堆記憶體的指針是可以的

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

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

繼續閱讀