柚子快報(bào)邀請(qǐng)碼778899分享:開發(fā)語言 C語言-函數(shù)
柚子快報(bào)邀請(qǐng)碼778899分享:開發(fā)語言 C語言-函數(shù)
一、函數(shù)的概念
其實(shí)在C語?也引?函數(shù)(function)的概念,有些翻譯為:?程序,?程序這種翻譯更加準(zhǔn)確?些。C語?中的函數(shù)就是?個(gè)完成某項(xiàng)特定的任務(wù)的??段代碼。這段代碼是有特殊的寫法和調(diào)??法的。C語?的程序其實(shí)是由?數(shù)個(gè)?的函數(shù)組合?成的,也可以說:?個(gè)?的計(jì)算任務(wù)可以分解成若?個(gè)較?的函數(shù)(對(duì)應(yīng)較?的任務(wù))完成。同時(shí)?個(gè)函數(shù)如果能完成某項(xiàng)特定任務(wù)的話,這個(gè)函數(shù)也是可以復(fù)?的,提升了開發(fā)軟件的效率。 在C語?中我們?般會(huì)?到兩類函數(shù): ? 庫函數(shù) ? ?定義函數(shù)
二、庫函數(shù)
(2.1)標(biāo)準(zhǔn)庫和頭文件
C語?標(biāo)準(zhǔn)中規(guī)定了C語?的各種語法規(guī)則,C語?并不提供庫函數(shù);C語?的國際標(biāo)準(zhǔn)ANSI C規(guī)定了?些常?的函數(shù)的標(biāo)準(zhǔn),被稱為標(biāo)準(zhǔn)庫,那不同的編譯器?商根據(jù)ANSI提供的C語?標(biāo)準(zhǔn)就給出了?系列函數(shù)的實(shí)現(xiàn)。這些函數(shù)就被稱為庫函數(shù)。 我們前?內(nèi)容中學(xué)到的 printf 、 scanf 都是庫函數(shù),庫函數(shù)的也是函數(shù),不過這些函數(shù)已經(jīng)是現(xiàn)成的,我們只要學(xué)會(huì)就能直接使?了。有了庫函數(shù),?些常?的功能就不需要程序員??實(shí)現(xiàn)了,?定程度提升了效率;同時(shí)庫函數(shù)的質(zhì)量和執(zhí)?效率上都更有保證。 各種編譯器的標(biāo)準(zhǔn)庫中提供了?系列的庫函數(shù),這些庫函數(shù)根據(jù)功能的劃分,都在不同的頭?件中進(jìn)?了聲明。 有數(shù)學(xué)相關(guān)的,有字符串相關(guān)的,有?期相關(guān)的等,每?個(gè)頭?件中都包含了,相關(guān)的函數(shù)和類型等信息,庫函數(shù)的學(xué)習(xí)不?著急?次性全部學(xué)會(huì),慢慢學(xué)習(xí),各個(gè)擊破就?。
庫函數(shù)相關(guān)頭?件:C 標(biāo)準(zhǔn)庫頭文件 - cppreference.com
(2.2)庫函數(shù)的使用方法
庫函數(shù)的學(xué)習(xí)和查看?具很多,?如: C/C++官?的鏈接:https://zh.cppreference.com/w/c/header cplusplus.com:C library - C++ Reference
這里舉例?pow 函數(shù)的使用:
庫函數(shù)是在標(biāo)準(zhǔn)庫中對(duì)應(yīng)的頭?件中聲明的,所以庫函數(shù)的使?,務(wù)必包含對(duì)應(yīng)的頭?件,不包含是可能會(huì)出現(xiàn)?些問題的。
注:pow函數(shù)是用來算一個(gè)數(shù)的N次冪的,該函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是底數(shù),第二個(gè)參數(shù)是次冪。例如上述代碼中計(jì)算的就是2的三次冪。
三、自定義函數(shù)
(3.1)函數(shù)的語法形式
其實(shí)?定義函數(shù)和庫函數(shù)是?樣的,形式如下:
? ret_type? 是?來表?函數(shù)計(jì)算結(jié)果的類型,有時(shí)候返回類型可以是 void ,表?什么都不返回
? fun_name? 是為了?便使?函數(shù);就像?的名字?樣,有了名字?便稱呼,函數(shù)有了名字?便調(diào) ?,所以函數(shù)名盡量要根據(jù)函數(shù)的功能起的有意義。
? 小括號(hào)中放的是形式參數(shù),函數(shù)的參數(shù)就相當(dāng)于,??中送進(jìn)去的原材料,函數(shù)的參數(shù)也可以是 void ,明確表?函數(shù)沒有參數(shù)。如果有參數(shù),要交代清楚參數(shù)的類型和名字,以及參數(shù)個(gè)數(shù)。
? { } 括起來的部分被稱為函數(shù)體,函數(shù)體就是完成計(jì)算的過程。
(3.2)函數(shù)的舉例
這里寫?個(gè)加法函數(shù),完成2個(gè)整型變量的加法操作。我們根據(jù)要完成的功能,給函數(shù)取名Add,函數(shù)Add需要接收2個(gè)整型類型的參數(shù),函數(shù)計(jì)算的結(jié)果也是整型。
上述代碼,主函數(shù)中對(duì)Add函數(shù)進(jìn)行調(diào)用完成num1和num2的相加并返回結(jié)果存到 ret 中,再打印到屏幕上。例如:
四、形參和實(shí)參
以我們剛才寫的代碼為例:
(4.1)實(shí)參
在上?代碼中,第6~10?是 Add 函數(shù)的定義,有了函數(shù)后,再第16?調(diào)?Add函數(shù)的。我們把第16?調(diào)?Add函數(shù)時(shí),傳遞給函數(shù)的參數(shù) num1 和num2,稱為實(shí)際參數(shù),簡稱實(shí)參。實(shí)際參數(shù)就是真實(shí)傳遞給函數(shù)的參數(shù)。
(4.2)形參
在上?代碼中,第6?定義函數(shù)的時(shí)候,在函數(shù)名 Add 后的括號(hào)中寫的 x 和 y ,稱為形式參數(shù),簡稱形參。為什么叫形式參數(shù)呢?實(shí)際上,如果只是定義了 Add 函數(shù),?不去調(diào)?的話, Add 函數(shù)的參數(shù) x和 y 只是形式上存在的,不會(huì)向內(nèi)存申請(qǐng)空間,不會(huì)真實(shí)存在的,所以叫形式參數(shù)。形式參數(shù)只有在函數(shù)被調(diào)?的過程中為了存放實(shí)參傳遞過來的值,才向內(nèi)存申請(qǐng)空間,這個(gè)過程就是形式的實(shí)例化。
(4.3)實(shí)參和形參的關(guān)系
雖然我們提到了實(shí)參是傳遞給形參的,他們之間是有聯(lián)系的,但是形參和實(shí)參各?是獨(dú)?的內(nèi)存空間。這個(gè)現(xiàn)象是可以通過調(diào)試來觀察的。請(qǐng)看下?的代碼和調(diào)試演?:
我們?cè)谡{(diào)試的過程中可以觀察到,x和y確實(shí)得到了num1和num2的值,但是x和y的地址和num1和num2的地址是不?樣的,所以我們可以理解為形參是實(shí)參的?份臨時(shí)拷?。
五、return語句
在函數(shù)的設(shè)計(jì)中,函數(shù)中經(jīng)常會(huì)出現(xiàn)return語句,這?講?下return語句使?的注意事項(xiàng)。
? return后邊可以是?個(gè)數(shù)值,也可以是?個(gè)表達(dá)式,如果是表達(dá)式則先執(zhí)?表達(dá)式,再返回表達(dá)式的結(jié)果。
? return后邊也可以什么都沒有,直接寫 return; 這種寫法適合函數(shù)返回類型是void的情況。
? return返回的值和函數(shù)返回類型不?致,系統(tǒng)會(huì)?動(dòng)將返回的值隱式轉(zhuǎn)換為函數(shù)的返回類型。
? return語句執(zhí)?后,函數(shù)就徹底返回,后邊的代碼不再執(zhí)?。
? 如果函數(shù)中存在if等分?的語句,則要保證每種情況下都有return返回,否則會(huì)出現(xiàn)編譯錯(cuò)誤。
六、數(shù)組做函數(shù)參數(shù)
在使?函數(shù)解決問題的時(shí)候,難免會(huì)將數(shù)組作為參數(shù)傳遞給函數(shù),在函數(shù)內(nèi)部對(duì)數(shù)組進(jìn)?操作。例如:寫兩個(gè)函數(shù),一個(gè)對(duì)數(shù)組進(jìn)行賦值,另一個(gè)對(duì)數(shù)組進(jìn)行打印。
這?的set_arr函數(shù)要能夠?qū)?shù)組內(nèi)容進(jìn)?設(shè)置,就得把數(shù)組作為參數(shù)傳遞給函數(shù),同時(shí)函數(shù)內(nèi)部在設(shè)置數(shù)組每個(gè)元素的時(shí)候,也得遍歷數(shù)組,需要知道數(shù)組的元素個(gè)數(shù)。所以我們需要給set_arr傳遞2個(gè)參數(shù),?個(gè)是數(shù)組,另外?個(gè)是數(shù)組的元素個(gè)數(shù)。仔細(xì)分析print_arr也是?樣的,只有拿到了數(shù)組和元素個(gè)數(shù),才能遍歷打印數(shù)組的每個(gè)元素。想要實(shí)現(xiàn)這兩個(gè)函數(shù),我們還需要知道數(shù)組傳參的?個(gè)重點(diǎn)知識(shí):
? 函數(shù)的形式參數(shù)要和函數(shù)的實(shí)參個(gè)數(shù)匹配 ? 函數(shù)的實(shí)參是數(shù)組,形參也是可以寫成數(shù)組形式的 ? 形參如果是?維數(shù)組,數(shù)組??可以省略不寫 ? 形參如果是?維數(shù)組,?可以省略,但是列不能省略 ? 數(shù)組傳參,形參是不會(huì)創(chuàng)建新的數(shù)組的 ? 形參操作的數(shù)組和實(shí)參的數(shù)組是同?個(gè)數(shù)組
根據(jù)上述的信息,我們就可以實(shí)現(xiàn)這兩個(gè)函數(shù):
七、嵌套調(diào)用和鏈?zhǔn)皆L問
(7.1)嵌套調(diào)用
嵌套調(diào)?就是函數(shù)之間的互相調(diào)?,每個(gè)函數(shù)就??個(gè)樂?零件,正是因?yàn)槎鄠€(gè)樂?的零件互相?縫的配合才能搭建出精美的樂?玩具,也正是因?yàn)楹瘮?shù)之間有效的互相調(diào)?,最后寫出來了相對(duì)?型的程序。
假設(shè)我們計(jì)算某年某?有多少天?,如果要函數(shù)實(shí)現(xiàn),可以設(shè)計(jì)2個(gè)函數(shù): ? is_leap_year():根據(jù)年份確定是否是閏年 ? get_days_of_month():調(diào)?is_leap_year確定是否是閏年后,再根據(jù)?計(jì)算這個(gè)?的天數(shù)
這?段代碼,完成了?個(gè)獨(dú)?的功能。代碼中反應(yīng)了不少的函數(shù)調(diào)?:
? main 函數(shù)調(diào)? scanf 、 printf 、 get_days_of_month
? get_days_of_month 函數(shù)調(diào)? is_leap_year 未來的稍微??些代碼都是函數(shù)之間的嵌套調(diào)?,但是函數(shù)是不能嵌套定義的。
(7.2)鏈?zhǔn)皆L問
所謂鏈?zhǔn)皆L問就是將?個(gè)函數(shù)的返回值作為另外?個(gè)函數(shù)的參數(shù),像鏈條?樣將函數(shù)串起來就是函數(shù)的鏈?zhǔn)皆L問。例如:
如果把Add函數(shù)的返回值直接作為printf函數(shù)的參數(shù)呢?這樣就是?個(gè)鏈?zhǔn)皆L問的例?了。
八、函數(shù)的聲明和定義
(8.1)單個(gè)文件
?般我們?cè)谑?函數(shù)的時(shí)候,直接將函數(shù)寫出來就使?了。
上面代碼中,5~9行是函數(shù)的定義,15行是函數(shù)的調(diào)用。這種場(chǎng)景下是函數(shù)的定義在函數(shù)調(diào)?之前,沒啥問題。
那如果我們將函數(shù)的定義放在函數(shù)的調(diào)?后邊,如下:
這個(gè)代碼在VS2022上編譯,會(huì)出現(xiàn)下?的警告信息:
這是因?yàn)镃語?編譯器對(duì)源代碼進(jìn)?編譯的時(shí)候,從第??往下掃描的,當(dāng)遇到第12?的Add函數(shù)調(diào)?的時(shí)候,并沒有發(fā)現(xiàn)前?有Add的定義,就報(bào)出了上述的警告。怎么解決這個(gè)問題呢?就是函數(shù)調(diào)?之前先聲明?下Add這個(gè)函數(shù),聲明函數(shù)只需要交代清楚:函數(shù)名,函數(shù)的返回類型和函數(shù)的參數(shù)。例如:
第5行就是函數(shù)聲明,函數(shù)聲明中參數(shù)只保留類型,省略掉名字也是可以的。代碼變成這樣就能正常編譯了。
(8.2)多個(gè)文件
?般在企業(yè)中我們寫代碼時(shí)候,代碼可能?較多,不會(huì)將所有的代碼都放在?個(gè)?件中;我們往往會(huì)根據(jù)程序的功能,將代碼拆分放在多個(gè)?件中。?般情況下,函數(shù)的聲明、類型的聲明放在頭?件(.h)中,函數(shù)的實(shí)現(xiàn)是放在源?件(.c)?件中。如下:
add.h (函數(shù)聲明,頭文件包含)
add.c (函數(shù)定義)
test.c (函數(shù)調(diào)用)
VS2022界面展示:
(8.3)static和extern
static 和?extern? 都是C語?中的關(guān)鍵字。 static 是 靜態(tài)的 的意思,可以?來: ? 修飾局部變量 ? 修飾全局變量 ? 修飾函數(shù) extern 是?來聲明外部符號(hào)的。
在講解 static 和 extern 之前再講?下:作?域和?命周期。
作?域(scope)是程序設(shè)計(jì)概念,通常來說,?段程序代碼中所?到的名字并不總是有效(可?)的,?限定這個(gè)名字的可?性的代碼范圍就是這個(gè)名字的作?域。 1. 局部變量的作?域是變量所在的局部范圍。 2. 全局變量的作?域是整個(gè)?程(項(xiàng)?)。
?命周期指的是變量的創(chuàng)建(申請(qǐng)內(nèi)存)到變量的銷毀(收回內(nèi)存)之間的?個(gè)時(shí)間段。
1. 局部變量的?命周期是:進(jìn)?作?域變量創(chuàng)建,?命周期開始,出作?域?命周期結(jié)束。
2. 全局變量的?命周期是:整個(gè)程序的?命周期。
(8.3.1)static修飾局部變量
代碼一:
代碼二:
代碼1:print_i函數(shù)中的局部變量i是每次進(jìn)?print_i函數(shù)先創(chuàng)建變量(?命周期開始)并賦值為0,然后++,再打印,出函數(shù)的時(shí)候變量?命周期將要結(jié)束(釋放內(nèi)存)。代碼2:我們從輸出結(jié)果來看,i的值有累加的效果,其實(shí)print_i函數(shù)中的i創(chuàng)建好后,出函數(shù)的時(shí)候是不會(huì)銷毀的,重新進(jìn)?函數(shù)也就不會(huì)重新創(chuàng)建變量,直接上次累積的數(shù)值繼續(xù)計(jì)算。結(jié)論:static修飾局部變量改變了變量的?命周期,?命周期改變的本質(zhì)是改變了變量的存儲(chǔ)類型,本來?個(gè)局部變量是存儲(chǔ)在內(nèi)存的棧區(qū)的,但是被 static 修飾后存儲(chǔ)到了靜態(tài)區(qū)。存儲(chǔ)在靜態(tài)區(qū)的變量和全局變量是?樣的,?命周期就和程序的?命周期?樣了,只有程序結(jié)束,變量才銷毀,內(nèi)存才回收。但是作?域是不變的。
使?建議:未來?個(gè)變量出了函數(shù)后,我們還想保留值,等下次進(jìn)?函數(shù)繼續(xù)使?,就可以使?static修飾。
(8.3.2)static修飾全局變量
代碼一:
代碼二:
extern 是?來聲明外部符號(hào)的,如果?個(gè)全局的符號(hào)在A?件中定義的,在B?件中想使?,就可以使? extern 進(jìn)?聲明,然后使?。 代碼1正常,代碼2在編譯的時(shí)候會(huì)出現(xiàn)鏈接性錯(cuò)誤。
結(jié)論: ?個(gè)全局變量被static修飾,使得這個(gè)全局變量只能在本源?件內(nèi)使?,不能在其他源?件內(nèi)使?。本質(zhì)原因是全局變量默認(rèn)是具有外部鏈接屬性的,在外部的?件中想使?,只要適當(dāng)?shù)穆暶骶涂梢允?;但是全局變量被 static 修飾之后,外部鏈接屬性就變成了內(nèi)部鏈接屬性,只能在??所在的源?件內(nèi)部使?了,其他源?件,即使聲明了,也是?法正常使?的。
使?建議:如果?個(gè)全局變量,只想在所在的源?件內(nèi)部使?,不想被其他?件發(fā)現(xiàn),就可以使?static修飾。
(8.3.3)static修飾函數(shù)
代碼一:
代碼二:
代碼1是能夠正常運(yùn)?的,但是代碼2就出現(xiàn)了鏈接錯(cuò)誤。
其實(shí) static 修飾函數(shù)和 static 修飾全局變量是?模?樣的,?個(gè)函數(shù)在整個(gè)?程都可以使?,被static修飾后,只能在本?件內(nèi)部使?,其他?件?法正常的鏈接使?了。 本質(zhì)是因?yàn)楹瘮?shù)默認(rèn)是具有外部鏈接屬性的,這使得函數(shù)在整個(gè)?程中只要適當(dāng)?shù)穆暶骶涂梢员皇?。但是被 static 修飾后變成了內(nèi)部鏈接屬性,使得函數(shù)只能在??所在源?件內(nèi)部使?。
使?建議:?個(gè)函數(shù)只想在所在的源?件內(nèi)部使?,不想被其他源?件使?,就可以使? static 修飾。
柚子快報(bào)邀請(qǐng)碼778899分享:開發(fā)語言 C語言-函數(shù)
推薦閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。