C 語言解剖課 你真的完全理解函式返回值嗎?

Mondo 科技 更新 2024-02-05

函式是語言程式設計的基本單位,每個有意義的函式都必須產生輸入和輸出行為。 本文的主題不是討論函式,而是詳細剖析我們忽略的函式返回值的特徵是什麼。

之所以寫這個話題,是因為這兩天我和公司裡幾位新入職的程式設計師聊了聊,他們都是今年剛畢業的大學生,都說基本功紮實,基本功紮實,至少專業課程還是很不錯的。

當然,我們必須談談語言。 我不知道我是否不說話,但當我談論它時,我很震驚。 幾個人,甚至他們每個人都能分辨出函式的返回值。 在他們的理解中,函式通過返回值返回資料,另乙個是通過指標將資料帶出來。 讓他們再詳細說明一下,他們會不知所措。

我問他們輸入引數是什麼,輸出引數是什麼,他們都不知道。 原因是沒有語法... 這意味著他們肯定不知道什麼是語義,什麼是語法。

因此,我決定今天就和大家一起分析一下“函式的返回值”,本文應該以本文為起點。

每個人都知道函式的組成:函式名稱、返回值型別、引數列表和函式體。 函式通過引數列表輸入引數,用 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日,合肥寫。 優質作者名單

相關問題答案

    C 語言解剖課 指標陣列和陣列指標很愚蠢,分不清?

    本來,在我看來,指標陣列 和 陣列指標 是兩個彼此不相近的知識點。因為前者的 主語 是陣列,而後者的 主語 是指標,所以主體是不同的。雖然陣列可以看作是被 const 修改的指標 常量型指標 但這只是為了理解,陣列是在堆疊上分配的,指標指向的記憶體一般是動態分配的,更多的是在堆上,使用起來比較仔細和...

    C和C語言,你知道多少?

    C 和C是軟體開發領域廣泛使用的兩種程式語言。對於那些對計算機程式設計感興趣的人來說,理解和掌握這兩種語言非常重要,無論你是剛剛開始學習習程式設計,還是已經是乙個有經驗的開發人員,了解兩者之間的關係對你未來的職業生涯都會有很大的幫助。.C 和C的區別 物件導向與面向過程。C 是一種物件導向的程式語言...

    元旦假期,你的工作電話真的可以完全靜音嗎?

    馬上就要過元旦了,相信很多朋友都已經放假了。元旦放假三天,忙碌了一年後,可以稍作休息,與親朋好友共度新年。假期總是乙個好時機,因為它們是你自己的休息時間。讓我們忙碌一下,停下來享受一下,做一些我們想做的事情。但這個時候,作為工人的你,真的能徹底脫掉工作嗎?更具體地說,您的工作電話真的可以完全靜音嗎?...

    你真的了解維生素C嗎

    可以說我們對維生素C很感興趣 這已經足夠熟悉了。但你真的明白嗎?維生素也被稱為 抗壞血酸是一種水溶性維生素。由營養學會推薦。不同人群的每日維生素C攝入量。 毫克,持續 至 年, 毫克,持續 至 年 歲 毫克, 歲 毫克 懷孕和哺乳期間 毫克 維生素C有什麼作用?提高身體的免疫力。維生素C能增強中性粒...

    本文將教你如何在 C 語言中使用浮點數

    在 C 中,float 是一種用於儲存浮點數的資料型別,即帶有小數部分的數字。以下是使用 float 型別的基本方法 宣告浮點變數 float myfloat 宣告乙個名為 myfloat 的浮點變數。分配 myfloat . 遺囑 分配給 myfloat 或者與宣告同時初始化 float myfl...