1. 程式人生 > >c/c++排坑(4) -- c/c++中返回區域性變數

c/c++排坑(4) -- c/c++中返回區域性變數

返回c語言中的區域性變數

先看一段程式碼猜猜,列印值:

#include <iostream>
using namespace std;
char * func();
int main()
{
    char *buf = func();
    cout << "buf:" << buf << endl;
}
char * func()
{
    char buffer[3];
    buffer[0] = '1';
    buffer[1] = '2';
    buffer[2] = '3';
    return buffer;
}

或許你已經猜到了,會列印亂碼的值。原因是返回了一個區域性的變數,而區域性變數再離開函式體之後就不存在了,char 指標指向不明的空間。那麼如何改進這玩意兒呢?

  • 返回一個指向字串常量的指標。
char * func() { return "123"; } 
  • 使用全域性宣告的陣列。
    這適用於自己建立的字串情況,也很簡單易用。它的缺點在於任何人都有可能在任何時候修改這個全域性陣列,而且該函式的下一次呼叫也會覆蓋該陣列的內容。
  • 使用靜態陣列。
    這就可以防止任何人修改這個值,但是該函式的下一次呼叫將覆蓋整個陣列的內容,所以呼叫者必須在此之前使用或備份資料的內容。和全域性陣列一樣,大型緩衝區如果閒置不用是非常浪費記憶體空間的。
char * func()
{
    static char buffer[3];
    buffer[0] = '1';
    buffer[1] = '2';
    buffer[2] = '3';
    return buffer;
}
  • 顯示分配一些記憶體,儲存返回的值。整個方法其實挺不錯的,但是缺點也非常明顯,程式設計師必須承擔記憶體管理的責任。我的天,在函式外還能想著給函式內的記憶體做釋放的傢伙得多變態。所以...嗯...我是受不了這種做法。
char * func()
{
    char * buffer = malloc(10);
    ...
    return buffer;
}
  • 呼叫者分配記憶體來儲存函式的返回值。為了提高安全性,呼叫者應該同時指定緩衝區的大小。
char * func(char * result, int size)
{
    ...
    strncpy(result, "something", size);
}

buffer = malloc(size);
func(buffer, size);
...
free(buffer);

如果程式設計師可以在同一程式碼中同時進行malloc和free操作,記憶體管理是較為輕鬆的。

C++的一些情況

C++中當然在普通情況下和c無異。但是考慮如下程式碼,看看會列印啥:

#include <iostream>
#include <string>

using namespace std;
string func1();

int main()
{
    string str = func1();
    cout << "str:" << str << endl;
}
string func1()
{
    string str("str123");
    return str;
}

哈哈,顯然你已經猜到不會列印亂碼了。為啥同樣是區域性變數,string型別不會列印亂碼呢。這是因為在C++中,返回的時候會有一個臨時變數來儲存這個返回值哦。同樣的在輸入的時候也是通過生成臨時變數傳參的。考慮如下程式碼:

void func(Object obj)
{
    ...
}

如果Object 是一個複雜的物件,那麼其實是非常影響效能的,可考慮改成如下的程式碼:

void func(const Object &obj)
{
    ...
}

咦,是不是很熟悉呢。其實很多程式碼都是這樣做的哈。這裡的const表示不可修改,其實const關鍵字還真是容易讓人理解錯呢,將const理解成readonly大多數情況下不會錯。

See you next time. Happy Coding!!!
我的github