最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

第 14 講:函數(shù)

2021-09-13 19:14 作者:SunnieShine  | 我要投稿

What is 函數(shù)?

學(xué)過數(shù)學(xué)的人都知道,數(shù)學(xué)有一種函數(shù)表示方法,叫 f(x)%20%3D%20%5Ctext%7Bexpression%7D?的東西,其中等號右邊應(yīng)當(dāng)填入一個表達(dá)式(expression)。

C 語言和數(shù)學(xué)的函數(shù)差不太多,不過 C 語言是為編程服務(wù)的,所以 C 語言可能還會廣義化數(shù)學(xué)上的函數(shù)。C 語言里,函數(shù)其實是“一個過程”,這個“過程”下會執(zhí)行一系列的操作,比如輸入輸出、循環(huán)等等。不過和數(shù)學(xué)相同的地方是,C 語言函數(shù)在執(zhí)行完畢這一系列語句時,會有一個函數(shù)值(返回值),這個值就是這個“過程”最后的執(zhí)行結(jié)果。比如說 f(x) = x^2 + 2x + 3 的式子,我們可以這么去寫C語言。

首先我們發(fā)現(xiàn),在 int main(void) 前,還有一段代碼獨立于它而存在。它寫成 int f(int x),而里面只有一句話,是用類似于 main 里的 return 0; 差不太多的寫法,也用了 return 單詞?,F(xiàn)在來解釋一下它是什么意思。

因為它和數(shù)學(xué)不同,定義域和值域不像數(shù)學(xué)那樣,實數(shù)范圍包含整數(shù)和小數(shù),人可以靈活處理,電腦不能,所以電腦的定義域內(nèi)整數(shù)和小數(shù)是區(qū)分開的,因此必定要為變量名和函數(shù)值先定下一個取值范圍,再來寫操作。定義定義域和值域時,即寫出操作過程之中,定義域的取值范圍(我們一般用整數(shù),所以 int 足夠了);而值域,即函數(shù)值,一定根據(jù)剛才的計算公式,得到的是也應(yīng)是 int,所以還是 int。所以,分別寫在對應(yīng)位置上。

然后你對照這個寫法和剛才 f(x) = x^2 + 2x + 3,你就會發(fā)現(xiàn),其實 return 語句下就寫的是這個表達(dá)式。這是因為,return 語句專門用于獲取函數(shù)的函數(shù)值(返回值)。因為這個數(shù)學(xué)函數(shù)在編程里面肯定只有這樣一個操作(得到數(shù)值結(jié)果),所以在 C 語言里,f 函數(shù)里只有 return 這一句話。

然后在 main 里,我們要使用這個函數(shù)功能的話,就可以這么寫。

特別注意那句話,我們使用 f 函數(shù)了,但是因為那個函數(shù)最后是一個結(jié)果,所以我們可以直接當(dāng)成一個數(shù)來寫進(jìn)printf 之中,輸出這個數(shù)。我們想要把這個手動輸入的i當(dāng)成自變量放進(jìn) f 函數(shù)之中得到結(jié)果。所以是這么寫的。當(dāng)然了,也可以分寫兩句話:

這樣要好理解一些,不過其實都一樣。

當(dāng)然,我們可以這么去想這個問題:輸入一個值,然后得到 ?f(x) 函數(shù)值,然后輸出結(jié)果。這樣的三個部分的操作,都可以同時丟進(jìn) C 語言的這個 f 函數(shù)之中。數(shù)學(xué)就不可以,C 語言就可以,而這就是因為,C 語言里的函數(shù)是執(zhí)行一系列的操作,不一定只求一個值就完了,不過,這樣執(zhí)行輸入輸出了,也就不必再去糾結(jié)它程序結(jié)果的函數(shù)值了(因為結(jié)果已經(jīng)輸出了,根本就不需要再單獨給這個程序一個函數(shù)值),這樣的“只執(zhí)行一系列語句”的函數(shù),我們可以為值域部分寫上 void 一詞(void 一詞就是空白、沒有的意思)。

看看這個程序和之前的程序,不同之處有三個:第一是 int f(int x) 改變?yōu)榱?void f();第二是最后末尾的 return 語句什么結(jié)果都沒有,只是一個單獨的 return 單詞;第三是 main 之中,使用 f s函數(shù)時的寫法,括號是空的,啥都沒有,然后就直接分號結(jié)尾了。

至于第一點,是因為我們剛才說到,它執(zhí)行的是一系列的操作,而結(jié)果已經(jīng)在中間輸出過了,所以不需要對末尾再寫出函數(shù)值,所以為這種函數(shù)用 void。至于括號里面為啥也沒有數(shù)值了呢?因為括號不需要數(shù)值了,因為輸入的數(shù)據(jù)值已經(jīng)在函數(shù)里面體現(xiàn)了,何必非要寫在上面括號里面去呢,這個函數(shù)功能根本就不需要用到這個 x 了,所以為了表示它是函數(shù),就只有一個空的括號而已;

第二點是因為,函數(shù)既然沒有函數(shù)值結(jié)果了,但因為要結(jié)束這個函數(shù),所以需要 return 作為結(jié)尾,表示函數(shù)執(zhí)行完畢。當(dāng)然了,這種末尾直接結(jié)束的函數(shù),是可以不寫這個 return; 語句的。但如果你想中途結(jié)束程序,就必須加上這句話,來表示在某個中間執(zhí)行結(jié)果下就結(jié)束這個函數(shù)的運行;

第三點是因為,剛才我們是當(dāng) f 函數(shù)是一個數(shù)值來處理的。但是現(xiàn)在 f 函數(shù)只是一個執(zhí)行輸入、求結(jié)果和輸出三個操作的過程,所以要使用它直接寫上去就可以了。


參數(shù)的定義

在 C 語言之中,我們稱函數(shù)使用的小括號內(nèi)的變量(可以有一個,也可以有很多個)叫參數(shù)。這一點來說,它和數(shù)學(xué)不太一樣,數(shù)學(xué)里的參數(shù)往往指的是函數(shù)表達(dá)式里不同于自變量的數(shù)值(如 f(x)%20%3D%20ax%5E2%20%2B%20bx%20%2B%20c?之中的字母 a、b、c)。

這里要提兩個定義,考試要考的:

  • 形參(Parameter):函數(shù)的第一句話里,小括號內(nèi)的變量;

  • 實參(Argument):函數(shù)內(nèi)使用形參的這些變量。

理解也很好理解。

小括號里寫 void?

最后需要你注意的是,在小括號里也要寫 void,這是為什么呢?

如果我們知道這個函數(shù)不應(yīng)該有參數(shù),那么就在小括號里寫上 void 關(guān)鍵字來告訴編譯器,這個函數(shù)不需要任何參數(shù)。如果你不寫它,往往程序也可以正常執(zhí)行,但少見有些情況會出現(xiàn)內(nèi)存泄漏和內(nèi)存溢出的問題和 bug,導(dǎo)致很嚴(yán)重的錯誤。

所以為了安全起見,我們習(xí)慣在不需要參數(shù)的函數(shù)里,小括號里添加 void 關(guān)鍵字。


main 函數(shù)剖析

main 究竟是什么東西

我們經(jīng)常聽到老師提起“main 函數(shù)”這個說法。它其實也是一個函數(shù)。理解起來也很容易:因為它執(zhí)行的是一系列的操作。不過它更為特殊一些:所有 C 語言程序都需要從 main 的第一句開始執(zhí)行。注意哈,這里說的是“執(zhí)行”,后面會告訴大家,編譯(從 C 語言翻譯為機器識別的二進(jìn)制代碼串的過程)則是從最上面第一句開始的,跟 main 無關(guān)。


main 的返回值

那么,為什么 main 它也有函數(shù)值?main 有函數(shù)值的原因在于,為了大家方便查 bug 才搞的機制。讓程序完整無誤不出錯地走一遍,默認(rèn)為 0,表示沒錯;但如果中途出現(xiàn)某種錯誤了,比如沒有賦值就使用變量啊這種,就會報錯,這個時候程序會直接終止 main,而不是調(diào)過錯誤的語句繼續(xù)往下走。這個時候,終止了 main 必然會直接得到返回值(函數(shù)值),這個時候為了方便查錯,我們就把這樣可以導(dǎo)致同一類出錯情況的返回值給它規(guī)定成同一個返回值(函數(shù)值),這樣開發(fā)人員就不會很頭痛,從頭開始找錯。

你需要記住一點,DevCpp 軟件在沒有為變量賦值時就使用變量時,main 的函數(shù)值為 3221225477。


main 的參數(shù)

另外,main 函數(shù)里有時候有一坨東西,有時候又沒有,是什么情況。

  • int main();

  • int main(int argc, char *argv[]);

我們經(jīng)??吹竭@兩種寫法。第一種表示 main 沒有參數(shù);第二種則是有兩個參數(shù)。這兩個參數(shù)是什么呢?其實,這兩個參數(shù)指的是你在使用 cmd 命令行對程序操作時,產(chǎn)生的參數(shù)。

比如我們在使用 Linux 下的命令:rm(remove)命令時,總會在網(wǎng)上看到資料說:

或者

有時候還可以省略這個星號。先不管是什么東西。我們來說明一下。

rm 是這個命令的名字(它實際上是一個程序名,功能是刪除文件),而我們習(xí)慣性寫上的 -rf 參數(shù),其實是刪除文件需要的參數(shù)。-rf 表示遞歸刪除文件,且不保留痕跡。所以這里的 -rf 其實就是在執(zhí)行這個 rm 程序在進(jìn)入 main 里的參數(shù),-rf 是第二個參數(shù)的數(shù)值。

為了達(dá)到程序執(zhí)行的功能,有些時候會在調(diào)用程序和進(jìn)入 main 前就要傳遞一系列的參數(shù)進(jìn)去。這個時候我們可以為 main 設(shè)定這兩個參數(shù),就可以達(dá)到效果;第一個參數(shù)表明在執(zhí)行命令行時,參數(shù)的個數(shù);第二個則是參數(shù)的具體寫法。目前你知道這個用途就可以了,因為參數(shù)的后者 char *argv[] 是一個字符串?dāng)?shù)組,這一點在這里闡述是超綱的,所以不在這里敘述。


函數(shù)的定義

聲明格式

當(dāng)函數(shù)放在 main 下的時候,在編譯時,因為 main 會從上到下執(zhí)行語句,但執(zhí)行過程之中,發(fā)現(xiàn)有些東西沒有聲明,自然就不能用。比如這樣:

這個時候在語句執(zhí)行到 printf 時,發(fā)現(xiàn) f 是前文里沒有看到過的函數(shù),這個時候就會給出警告。所以函數(shù)的聲明就需要放在執(zhí)行 main 前面(即 #include 命令和 int main(void) 之前)。所以應(yīng)寫成這樣:

甚至可以寫在執(zhí)行語句前一句處:

都可以。


聲明函數(shù)的原理

從原理上講,函數(shù)的聲明是什么東西呢?C 語言是一種面向過程的編程語言(Process Oriented Programming,簡稱 POP),這種編程語言就是按照流程一步一步執(zhí)行即可,無需考慮其它因素。但為了代碼書寫的方便,C 語言為我們提供了兩種可定義和聲明的元素:變量(含數(shù)組變量以及后面要說到的指針變量)和函數(shù)。變量和函數(shù)的相似之處就是都需要定義出來才能使用(即先定義后使用)。像是 C 語言這樣,如果我們嘗試把其它的函數(shù)寫在 main 之后,按照順次執(zhí)行,就會遇到無法解析的函數(shù)名稱,于是我們肯定需要聲明(也叫定義)這個函數(shù)了。

那么,聲明格式和函數(shù)名一致,是為了保證簡單易懂。把函數(shù)名寫在中間,左邊寫返回值,右邊寫參數(shù),并用小括號把所有參數(shù)括起來,這樣便是一個完整的函數(shù)變量的定義。所以實際上,從這個角度出發(fā),函數(shù)也可以被視作一種特殊的變量類型。不過它和普通變量不同的是,它往往寫在最外面(全局范圍),一般不寫在函數(shù)執(zhí)行邏輯里,是因為這樣書寫,就不好看到它們。


函數(shù)內(nèi)的變量

變量的生命周期和函數(shù)的銷毀

變量分為多種:外部變量、內(nèi)部變量(函數(shù)內(nèi)變量)等。它們各自有不同用途,所以會被放在不同的位置。不過,要知道,它們的生命周期也不同。

變量會在函數(shù)用完時被銷毀,main 也是一樣。如果程序執(zhí)行完畢時,即 main 也執(zhí)行完畢,里面的所有變量都會直接蒸發(fā),變得不存在。其他函數(shù)也是。所以我們來看這個函數(shù):

很顯然,這個寫法是交換兩個數(shù)據(jù)用的。但是函數(shù)在執(zhí)行完后,變量就會不復(fù)存在。所以交換完后,變量就會消失,使得交換之后的結(jié)果也不能繼續(xù)使用。所以,換句話說:

輸出語句其實是沒有任何變化的,即兩處 printf 函數(shù)的輸出結(jié)果都是 a = 2、b = 3。這一點要引起額外注意。這是因為,在執(zhí)行交換函數(shù) swap 后,它僅交換了在 swap 函數(shù)里的 ab 變量,而并沒有對 main 函數(shù)里的 ab 作出任何影響,因為函數(shù)傳遞數(shù)值的模式是值傳遞,即只會把數(shù)值內(nèi)容復(fù)制一份然后丟到 swap 里來用,所以實際上它交換的其實是復(fù)制后的副本,而真正的元素卻沒有發(fā)生改變。在交換后,函數(shù)被銷毀,交換的副本也被同時銷毀,所以原本的變量根本就沒有發(fā)生任何的變化。

另外,如果把變量寫在函數(shù)外部的話,這樣的變量在程序 main 執(zhí)行的過程之中,只要 main 沒有銷毀(程序沒有結(jié)束),變量就會一直存在。

最后,還有一個冷門的知識點。


大括號封閉變量

雖然是同一個變量名字,但變量不同,并且有一個變量是用大括號括起來的,雖然這個大括號看起來好像不知道到底是什么用途。這里的大括號只有一個用:封閉變量。這個大括號內(nèi)部的變量外部是無法使用的,而內(nèi)部的輸出語句也只是會找到最近的變量名作輸出。所以就是 2 了;而外部的輸出語句輸出的 a,由于大括號封閉變量的關(guān)系,內(nèi)部的 2 完全不可能被外部的這個輸出語句的 a看到,所以根本不可能是 2,所以是相對于這個內(nèi)部的 a 外面的這個 4。

這告訴了我們,之前用于分割語義的大括號,它的原理到底是如何的。


一些修飾函數(shù)內(nèi)成員和參數(shù)的修飾符

static 修飾符

在函數(shù)里對一些普通變量修飾 static 修飾符,可以讓程序在反復(fù)調(diào)用這個函數(shù)時,這個變量都只會初始化一次,后續(xù)都直接用這個變量,而且函數(shù)被銷毀的時候,這個變量也不會被同時銷毀。

如果調(diào)用這個函數(shù)的話:

那么,首次 z 會被初始化為 10,隨后執(zhí)行 z += 3 使之變?yōu)?13,然后返回 13 + i。每一次 i 傳入的數(shù)值都不同,第一次是 0,第二次是 1,第三次是 2;而使用 f 函數(shù)時,z 第一次是 10(后自增 3,變?yōu)?13),第二次是 16,第三次則是 19。所以三次的輸出結(jié)果是 13 17 21。


auto 修飾符

實際上,所有在函數(shù)里聲明的變量,都是 auto 的,也就是說,你不寫它們,都會被默認(rèn)添加這個修飾符。這種修飾符表示這個變量在棧內(nèi)存進(jìn)行分配。所謂的棧內(nèi)存分配,就是跟著函數(shù)走。函數(shù)死亡,它就死亡,你就無法再使用里面的資源了。

如果你不想讓它消失,請在函數(shù)里對這個變量使用 static 修飾符,表示它不跟著函數(shù)銷毀而銷毀。


register 修飾符

這個修飾符雖然現(xiàn)在說還為時尚早,但這個修飾符并不需要任何的語法依托。它表示這個變量將在執(zhí)行期間直接丟到寄存器里。這個操作就為了一個字:快。我們都知道,程序的分配的變量都是在內(nèi)存里的,而執(zhí)行這些程序,還是得被提取出來,丟進(jìn) CPU 里挨著執(zhí)行它們。如果我們最初就把它們丟進(jìn)了寄存器里,由于寄存器就在 CPU 里,所以這樣執(zhí)行起來,就會比其它變量算得更快。所以,我們?nèi)绻堑每紤]性能的話,我們會把常用的簡單類型變量直接丟進(jìn)寄存器里,方式就是添加 register 修飾符在定義語句之前就可以了。


第 14 講:函數(shù)的評論 (共 條)

分享到微博請遵守國家法律
吉首市| 屯留县| 通海县| 娱乐| 清涧县| 巧家县| 合川市| 宜都市| 丹寨县| 逊克县| 开化县| 乐业县| 开江县| 西贡区| 象州县| 依安县| 浙江省| 游戏| 龙陵县| 基隆市| 班戈县| 晋州市| 伊宁县| 远安县| 陵水| 三原县| 盐亭县| 平江县| 东丽区| 镇雄县| 中超| 常州市| 合阳县| 定南县| 金川县| 中方县| 彩票| 阿拉善左旗| 乐安县| 莱芜市| 河东区|