return 語句終止當前正在執行的函數並將控制權返回到調用該函數的地方。return 語句有兩種形式:
return;
return expression;
不要返回局部對象的引用或指針:
函數完成后,它所占用的存儲空間也隨之被釋放掉。因此函數終止意味着局部變量的引用和指針將指向不再有效的內存區域:
一種典型的錯誤就是將一個指向局部變量的指針作為函數的返回值。由於該數組是局部變量,因此在函數返回時其數組空間已經作廢了,即指針應用一塊無意義的地址空間,所以不會有返回值。如果得到正常的值,只能是幸運的退出函數的時候,系統只是修改了棧頂的指針,並沒有清內存; 所以,是有可能正常訪問到局部變量的內存的。 但因為棧是系統自動管理的,所以該內存可能會被分配給其他函數,這樣,該內存的內容就會被覆蓋;不再是原來的值了。
1 #include <iostream> 2 using namespace std; 3 4 const string &cmp(void){ 5 const string s1 = "hdfl", s2 = "jflds"; 6 return s1 > s2 ? s1 : s2; 7 } 8 9 int main(void){ 10 const string s = cmp(); 11 // cout << s << endl;//錯誤,cmp 返回是一個指向被釋放的無效內存區的引用 12 return 0; 13 }
如前所述,返回局部對象的引用是錯誤的,同樣返回局部對象的指針也是錯誤的。一旦函數完成,局部對象被釋放,指針將指向一個不存在的對象。
引用返回左值:
函數的返回類型決定函數調用是否是左值。調用一個返回引用的函數得到左值,其他返回類型得到右值。所以能為返回類型是非常量引用的函數的結果賦值:
1 #include <iostream> 2 using namespace std; 3 4 char &gel(string &str, size_t indx){ 5 return str[indx]; 6 } 7 8 int main(void){ 9 string s("a value"); 10 cout << s << endl;//輸出 a value 11 gel(s, 0) = 'A';//將s[0]的值改成A 12 cout << s << endl;//輸出A value 13 return 0; 14 }
當然,如果函數返回的是常量引用,自然是不能給調用結果賦值的。
列表初始化返回值:
c++11 規定,函數可以返回花括號包圍的值的列表。類似於返回其他結果,此處的列表也用來對表示函數返回的臨時變量進行初始化。如果列表為空,臨時量執行值初始化,否則,返回的值由函數的返回類型決定:
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 vector<string> gel(void){ 6 return {"fjls", "fjsl", "gel", "yy"}; 7 } 8 9 int main(void){ 10 vector<string> s = gel(); 11 for(auto indx : s){ 12 cout << indx << endl; 13 } 14 return 0; 15 }
如果函數返回的是內置類型,則花括號包圍的列表中最多包含一個值,而且該值所占空間不應該大於目標類型的空間。如果函數返回的是類類型,由類本身定義初始值如何使用。
返回數組指針:
因為數組不能拷貝,所以函數不能返回數組。不過,函數可以返回數組的指針或引用:
1 #include <iostream> 2 using namespace std; 3 4 typedef int arrT[10];//arrT是一個類型別名,表示的類型是含有10個整數的數組 5 // using arrT = int[10];//arrT的等價聲明 6 typedef int arry[10][10]; 7 8 arrT* gel(arrT& x){//x是數組a的引用 9 return &x; 10 } 11 12 arrT& lou(arry& x){ 13 return x[0]; 14 } 15 16 int main(void){ 17 arrT a = {1, 2, 3}; 18 arrT *b = gel(a);//相當於b指向a 19 for(auto indx : *b){//b是一個指針,需要解引用 20 cout << indx << " "; 21 } 22 cout << endl; 23 // 輸出 1 2 3 0 0 0 0 0 0 0 24 arry c = {{1, 2, 3}}; 25 arrT &d = lou(c);//返回c的第一個數組元素的引用 26 for(auto indx : d){ 27 cout << indx << " "; 28 } 29 cout << endl; 30 // 輸出 1 2 3 0 0 0 0 0 0 0 31 return 0; 32 }
當然,不使用類型別名也是可以的,但是要麻煩一些。其聲明如下:
Type (*function(parameter_list))[dimension]
其中 Type 表示元素類型,dimension 表示數組的大小,類似於一般的數組指針聲明。(*function(parameter_list)) 兩端的括號必須存在,如果沒有則函數的返回類型將是指針的數組。
1 #include <iostream> 2 using namespace std; 3 4 int (*gel(int (&a)[10]))[10]{//注意:返回指針不能是局部對象 5 return &a; 6 } 7 8 int (&lou(int (&a)[10][10]))[10]{//注意:返回引用不能是局部對象 9 return a[0]; 10 } 11 12 int main(void){ 13 int a[10] = {1, 2, 3}; 14 int (*b)[10] = gel(a); 15 for(auto indx : *b){ 16 cout << indx << " "; 17 } 18 cout << endl; 19 //輸出 1 2 3 0 0 0 0 0 0 0 20 21 int c[10][10] = {{1, 2, 3}}; 22 int (&d)[10] = lou(c); 23 for(auto indx : d){ 24 cout << indx << " "; 25 } 26 cout << endl; 27 //輸出 1 2 3 0 0 0 0 0 0 0 28 return 0; 29 }
尾置返回類型:
在 c++11 中還有一種可以簡化上述 gel 函數聲明的方法,就是使用尾置返回類型。任何函數的定義都能使用尾置返回,但是這種形式對於返回類型比較復雜的函數最有效,比如返回類型是數組的指針或者數組的引用。尾置返回類型跟在形參列表后面並以一個 -> 符號開頭。為了表示函數真正的返回類型,我們在本應該出現返回類型的地方放置一個 auto:
1 #include <iostream> 2 using namespace std; 3 4 auto gel(int (&x)[10]) -> int(*)[10]{//使用尾置返回類型返回數組指針 5 return &x; 6 } 7 8 auto lou(int (&x)[10][10]) -> int(&)[10]{//使用尾置返回類型返回數組引用 9 return x[0]; 10 } 11 12 int main(void){ 13 int a[10] = {1, 2, 3}; 14 int (*b)[10] = gel(a); 15 for(auto indx : *b){//b是指針,需要解引用 16 cout << indx << " "; 17 } 18 cout << endl; 19 //輸出 1 2 3 0 0 0 0 0 0 0 20 21 int c[10][10] = {{1,2 , 3}}; 22 int (&d)[10] = lou(c); 23 for(auto indx : d){ 24 cout << indx << " "; 25 } 26 cout << endl; 27 //輸出 1 2 3 0 0 0 0 0 0 0 28 return 0; 29 }
使用 decltype:
還有一種情況,如果我們知道函數返回的指針將指向哪個數組,就可以使用 decltype 關鍵字聲明返回類型:
1 #include <iostream> 2 using namespace std; 3 4 int a[3]; 5 6 decltype(a) *gel(int (&x)[3]){ 7 return &x; 8 } 9 10 decltype(a) &lou(int (&x)[10][3]){ 11 return x[0]; 12 } 13 14 //注意:decltype(a)返回的只是一個數組,並不會將數組類型轉化成指針或者引用類型,所以還要再加一個指針或引用聲明符 15 16 int main(void){ 17 int b[] = {1, 2, 3}; 18 int (*c)[3] = gel(b); 19 for(auto indx : *c){ 20 cout << indx << " "; 21 } 22 cout << endl; 23 //輸出1 2 3 24 25 int d[10][3] = {{1, 2, 3}}; 26 int (&e)[3] = lou(d); 27 for(auto indx : e){ 28 cout << indx << " "; 29 } 30 cout << endl; 31 //輸出1 2 3 32 return 0; 33 }