複製鏈接
請複製以下鏈接發送給好友

返回值

(函數)

鎖定
一個函數的函數名既是該函數的代表,也是一個變量。由於函數名變量通常用來把函數的處理結果數據返回給調用函數,即遞歸調用,所以一般把函數名變量稱為返回值,函數的返回值類型是在定義函數時指定的。 [1] 
中文名
返回值
外文名
return
類    型
函數中定義
返    回
函數處理結果
用    途
返回函數處理結果進行下一步處理

返回值公式簡介

函數可以有返回值,也可以沒有返回值。
(1)沒有返回值的函數:功能只是完成一個操作,應將返回值類型定義為void,函數體內可沒有return語句。
(2)有返回值的函數:函數的最後會有一個返回值return,可以用來獲取該函數執行結果返回給該函數,讓外部調用該函數的。
返回值可指定,如果不指定默認返回None。 [2] 
函數的返回值類型是在定義函數時指定的。return 語句中表達式的類型應與定義函數時指定的返回值類型一致。如果不一致,則以函數定義時的返回值類型為準,對 return 語句中表達式的類型自動進行轉換,然後再將它返回給主調函數使用。
在調用函數時,如果需要從被調函數返回一個值供主調函數使用,那麼返回值類型必須定義成非 void 型。此時被調函數中必須包含 return 語句,而且 return 後面必須要有返回值,否則就是語法錯誤。
一個函數中可以有多個 return 語句,但並不是所有的 return 語句都起作用。執行到哪個 return 語句,就是哪個 return 語句起作用,該 return 語句後的其他語句都不會執行。 [1] 

返回值return 工作原理

被調函數運行結束後才會返回主調函數,但是被調函數運行結束後系統為被調函數中的局部變量分配的內存空間就會被釋放。也就是説,return 返回的那個值在被調函數運行一結束就被釋放掉了,那麼它是怎麼返回給主調函數的呢?
事實上在執行 return 語句時系統是在內部自動創建了一個臨時變量,然後將 return 要返回的那個值賦給這個臨時變量。所以當被調函數運行結束後 return 後面的返回值真的就被釋放掉了,最後是通過這個臨時變量將值返回給主調函數的。而且定義函數時指定的返回值類型實際上指定的就是這個臨時變量的類型。
這也是為什麼當 return 語句中表達式的類型和函數返回值類型不一致時,將 return 的類型轉換成函數返回值類型的原因。return 語句實際上就是將其後的值賦給臨時變量,所以它要以臨時變量的類型為準,即函數返回值的類型。 [1]  [2] 

返回值C++中的返回值

例:
void backward(int n)
{
cout<<n%10;
if(n<10)
return;
else backward(n/10);
}
int main()
{
int n;
cout<<"輸入整數:"<<endl;
cin>>n;
cout<<"原整數:"<<n<<endl<<"反向數:";
backward(n);
cout<<endl;
return 0;
}
函數可以有返回值,只要 return 就可以給出一個,不過常常不用它,有兩個原因:
1、C/C++裏返回值是複製出去的,而對於大的對象,複製的代價很高;
2、有些對象是不能複製的,至少編譯器不知道怎麼複製,比如數組
於是有了下面這樣的函數:
bool GetObj(ObjType& obj);
bool Encode(const char* src, char* dest);
用一個參數來代替返回值,而返回值只是指示函數執行是否成功。
返回一個大對象是困難的,但這個困難存在於 C 程序中,而不是 C++ 程序中。 C 函數里較少通過返回一個指針來返回對象,因為:
1、如果指針指向棧變量,毫無疑問,要麼不用這個返回值,要麼是一個錯誤;
2、如果指針指向堆變量,需要用這個函數的程序員會好好的看文檔且足夠細心會調用 free,要麼就是內存泄漏;
3、如果指針指向 static 變量,那麼用這個函數的程序員牢牢記住“下次調用這個函數以後,上次的返回值也會跟着變”。
在C++裏直接返回裸指針的話,情況並不會有什麼起色,不過 C++ 有智能指針的,通常它們指向堆變量,佔用的空間和裸指針一樣大。考慮前面第一個函數,寫成:
std::auto_ptr<ObjType> GetObj();
返回值如果不要,作為臨時變量,會立即被析構,返回的對象被釋放;如果需要,就得賦值給另一個智能指針。總之不用程序員記得,編譯器會保證這個對象的釋放。
考慮第二個函數,稍微有一點麻煩,因為 auto_ptr 是不能用來持有數組的,不過,在C++的世界裏,std::string 幾乎總是比 char* 好用:
std::auto_ptr<std::string> Encode(const char* src);
最後考慮最麻煩的情況:
bool AssembleObjList(ObjType objList[], size_t length);
這種類型的函數無論是在 C標準庫裏,還是在各種操作系統的 API 裏,比比皆是,事實上它存在兩大缺陷:
1、如果需要的數量超出給出的,要麼是一個安全問題(經典的緩衝區溢出,如 strcpy),要麼是失敗,程序員不得不作出估計--眾所周知,程序員的估計能力比他們的薪水低得多;
2、如果執行成功,到底 Assemble 了多少個?
於是我們見到了這樣的函數:
bool AssembleObjList(ObjType objLIst[], size_t* lengthPtr);
這個函數通常是兩步調用的:
size_t length = 0;
AssembleObjList(0, &length);
ObjType* objList = new ObjType[length];
AssembleObjList(objList, &length);
for(size_t i=0; i<length; ++i)// 處理每個元素
這種形式能解決上面列出的兩個問題,但這實在是太麻煩。我的答案仍然是--C++程序員應該用C++的庫:
std::auto_ptr<std::vector<ObjType> > AssembleObjList();
又幹淨,又舒服!
C++標準庫里居然沒有一個可以持有數組的智能指針,所以 boost庫不錯,可以這樣:
std::pair<boost::scoped_array<ObjType>, size_t> AssembleObjList();
可惜這個並不比標準庫的解法更優秀--因為要返回數目的緣故,不過我個人更喜歡這個解,因為他更接近最優的解--傳説中的 trule 手法:
TruleVector<ObjType> AssembleObjList();
其中 TruleVector是這樣一個模板:它只有兩種操作,一是構造,二是自動轉型為 std::vector,而且它具有 “auto_ptr 式的所有權轉移語義”。也就是説,TruleVector除了作為數組型的返回值,你無法把他用於其它任何任務。
不過由於 std::vector具有值語義,所以寫的代碼還是稍微有一點不同尋常:
typedef std::vector<ObjType> ObjListType;
ObjListType list;
list.swap(AssembleObjList());
最後一句在有的產品上可能要寫成:
list.swap(static_cast<ObjListType>(AssembleObjList()));
這樣彆扭的原因,可以歸咎於C++庫裏缺一個引用語義的線性容器。 [3] 

返回值php中的返回值

值通過使用可選的返回語句返回。任何類型都可以返回,其中包括列表和對象。這導致函數立即結束它的運行,並且將控制權傳遞迴它被調用的行。 [4] 
例子 17-11. return()的用法
<?php
function square($num)
{
return $num * $num;
}
echo square(4); // outputs '16'.
?>
函數不能返回多個值,但為了獲得簡單的結果,可以返回一個列表。
例子 17-12. 返回一個數組以得到多個返回值
<?php
function small_numbers()
{
return array (0, 1, 2);
}
list ($zero, $one, $two) = small_numbers();
?>
從函數返回一個引用,必須在函數聲明和指派返回值給一個變量時都使用引用操作符 & :
例子 17-13. 由函數返回一個引用
<?php
function &returns_reference()
{
return $someref;
}
$newref =& returns_reference();
?>
參考資料
  • 1.    譚浩強 .C程序設計(第4版) :清華大學出版社 ,2010.6
  • 2.    尹寶林. C程序設計導引 :機械工業出版社 ,2013.5
  • 3.    索明何,邢海霞,方偉駿.C語言程序設計:機械工業出版社,2016.2
  • 4.    列旭松 陳文.PHP核心技術與最佳實踐(第2版): 機械工業出版社 ,2018.9