函式是語言程式設計的基本單位,每個有意義的函式都必須產生輸入和輸出行為。 本文的主題不是討論函式,而是詳細剖析我們忽略的函式返回值的特徵是什麼。
之所以寫這個話題,是因為這兩天我和公司裡幾位新入職的程式設計師聊了聊,他們都是今年剛畢業的大學生,都說基本功紮實,基本功紮實,至少專業課程還是很不錯的。
當然,我們必須談談語言。 我不知道我是否不說話,但當我談論它時,我很震驚。 幾個人,甚至他們每個人都能分辨出函式的返回值。 在他們的理解中,函式通過返回值返回資料,另乙個是通過指標將資料帶出來。 讓他們再詳細說明一下,他們會不知所措。
我問他們輸入引數是什麼,輸出引數是什麼,他們都不知道。 原因是沒有語法... 這意味著他們肯定不知道什麼是語義,什麼是語法。
因此,我決定今天就和大家一起分析一下“函式的返回值”,本文應該以本文為起點。
每個人都知道函式的組成:函式名稱、返回值型別、引數列表和函式體。 函式通過引數列表輸入引數,用 return 語句返回資料,或者從引數列表中的輸出引數返回資料。
傳入函式體資料的引數稱為輸入引數,傳出函式資料的引數稱為輸出引數。 讓我們從返回值開始。
如果返回值是資料本身,或者是某個特定的值,即值型別,那麼我們都知道這個資料實際上是函式主體中資料的副本。
當函式被執行時,函式物件因為被分配在堆疊上而被自動銷毀,所以任務完成,函式中資料使用的記憶體空間會被釋放並重新分配。 因此,在銷毀之前,會製作乙個副本並返回給呼叫方使用。 (我將在下一篇文章中詳細剖析記憶體布局,堆疊和堆會很清楚)。
返回值型別可以是單值資料,例如基於字元的變數、整數變數或實數變數。
char foo()
char c='a';
return c;
int bar()
int x = 3;
return x;
這兩個函式分別返回兩個單值型別:字元和整數。 它也可以是多值資料,例如結構。 乙個結構可以包含多個成員變數。 例如:
返回多個值。
typedef struct ;
return many;
請注意,字串不是值型別,而是下面描述的“指標型別”。 陣列也不是值型別,陣列本質上是乙個“常量指標”(不是常量指標),例如整數陣列
int array =;
它實際上是這樣的:
int * const array = (int)
這裡的陣列不能再由其他陣列分配,即它不能如下所示:
int other_array = ;
array = other_array;//error
想要了解詳情,在“段玉河語”賬號裡有關於常量指標和指標常量深度分析的文章。 正如你所看到的,陣列也是一種“指標型別”。
如果返回的資料是指標型別資料,則在函式執行結束時銷毀函式之前,指標型別資料的副本仍將傳遞給呼叫方。
請注意,這是大多數初學者反覆掉入坑的地方。
再次:在函式執行結束時,像值型別一樣,會生成乙個要返回的資料副本並傳遞給呼叫者,但這個資料(或副本)是指標型別,它的值儲存在實值型別資料所在的記憶體位址中(假設指標是一級指標), 注意,指標指向的值型別變數沒有“copy”,只有返回資料會生成副本,返回資料是指標。
例如:char* foo();
return array;
int* pointer_multiple_value_2()
return ptr;
當函式執行時,資料也會被銷毀,當呼叫方通過獲取的位址訪問位址所在的記憶體資料時,會造成異常。 結果如下(環境與 c11):
我們再來看乙個看似正常的情況:
typedef struct ;
return &many;
many* pointer_multiple_value_4()
return many;
這兩個函式的返回值都是結構指標,乙個指向單個結構變數,另乙個指向乙個結構陣列,函式執行後會像函式一樣被銷毀,導致返回的結構指標指向的記憶體塊行為未定義,程式有崩潰的風險。
這個**看似執行正常,但實際上很容易讓他崩潰,所以暫時不擴大。
所以,我們只需要做這個值型別,當函式被銷毀時,它仍然活著,而不是一起銷毀。
如果是字串常量,則儲存在唯讀區域,當函式被銷毀時,它仍然存在,可以繼續訪問。
char* foo();
return many;
此函式分配結構變數的空間,並使用復合文字分配值。 下面是乙個截圖:
請注意,在這個**截圖中,在 main 函式中,在程式退出之前,我使用了 free 函式釋放了函式 foo 中的許多指標。
這一步非常重要,在程式結束之前,一定要通過free功能釋放堆上的空間,否則會出現“記憶體洩漏”或“記憶體碎片”、“百搭指標”等可怕的問題。
到目前為止,我們只對“返回值”的資料型別進行了分析和剖析,並沒有將其與引數列表的特性相結合。
在下一篇文章中,我們將對函式的引數列表進行深入分析,例如“輸入引數”的特徵、“輸出引數”的特徵,以及如何為傳入和傳出資料定義一些引數。
研究引數列表將使我們編寫的函式更加安全可靠,並且 5 分鐘的編碼天數和 5 小時的 bug 將顯著減少。
段譽,2024年2月1日,合肥寫。 優質作者名單