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

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

計(jì)算機(jī)程序基礎(chǔ)教程(08):C語言 - 函數(shù)

2023-03-06 02:12 作者:阿貍喜羊羊  | 我要投稿


【函數(shù)基礎(chǔ)】


函數(shù)用于將程序代碼進(jìn)行分類管理,將實(shí)現(xiàn)一些功能的代碼放在一個(gè)函數(shù)內(nèi),方便管理和修改,并且其它函數(shù)禁止使用本函數(shù)的數(shù)據(jù)(可通過指針參數(shù)繞過這一限制)。


函數(shù)外只能定義數(shù)據(jù),不能修改數(shù)據(jù),所有涉及程序執(zhí)行邏輯相關(guān)的代碼必須放在函數(shù)內(nèi)部。

函數(shù)外定義的數(shù)據(jù)稱為全局?jǐn)?shù)據(jù),所有函數(shù)都能使用。

函數(shù)內(nèi)定義的數(shù)據(jù)稱為局部數(shù)據(jù),只有本函數(shù)可以使用。


?● 函數(shù)之間的通信


一個(gè)函數(shù)可以跳轉(zhuǎn)到另一個(gè)函數(shù)執(zhí)行,調(diào)用者使用call指令跳轉(zhuǎn)到一個(gè)函數(shù),被調(diào)用者執(zhí)行完畢后使用ret指令返回,當(dāng)然有些函數(shù)可能無需返回。


兩個(gè)函數(shù)之間跳轉(zhuǎn)執(zhí)行時(shí),可能有通信需求,調(diào)用者需要向被調(diào)用者傳遞一些數(shù)據(jù)、或者被調(diào)用者執(zhí)行完畢后需要向調(diào)用者傳遞一些數(shù)據(jù),函數(shù)之間的通信可以有多種方式,最簡(jiǎn)單的方式就是通過全局變量中轉(zhuǎn),一方將通信數(shù)據(jù)寫入全局變量,另一方讀取全局變量獲得通信數(shù)據(jù),但是這種方式無法保密,所有函數(shù)都可以讀寫全局變量,為了解決此問題,C語言提供了參數(shù)和返回值,實(shí)現(xiàn)兩個(gè)函數(shù)之間的保密通信。


參數(shù)是函數(shù)內(nèi)的特殊局部數(shù)據(jù),它由當(dāng)前函數(shù)定義、調(diào)用者進(jìn)行賦值,用于實(shí)現(xiàn)調(diào)用者向被調(diào)用者傳遞數(shù)據(jù),參數(shù)可以沒有,有可以有多個(gè),可以是變量也可以是常量。

返回值用于實(shí)現(xiàn)被調(diào)用者向調(diào)用者傳遞數(shù)據(jù),返回值只能有一個(gè),通過寄存器傳遞。



main函數(shù)是自定義代碼的執(zhí)行入口,我們編寫的代碼從main函數(shù)開始執(zhí)行,main函數(shù)的返回值為int類型,一般返回一個(gè)0,作用是告知操作系統(tǒng)此程序正常執(zhí)行完畢,沒有出現(xiàn)異常情況。




【輸入輸出函數(shù)】


操作系統(tǒng)的主要作用有兩個(gè):

1.管理程序的運(yùn)行。

2.提供程序需要的基礎(chǔ)功能,供程序調(diào)用執(zhí)行。


操作系統(tǒng)提供了一些可被程序調(diào)用的基礎(chǔ)功能,稱為系統(tǒng)調(diào)用,Linux程序使用終端輸出功能時(shí)可通過如下代碼實(shí)現(xiàn):



rax、rdi,設(shè)置需要使用的系統(tǒng)調(diào)用,這里使用終端輸出功能。

rsi,設(shè)置要輸出數(shù)據(jù)的指針。

rdx,設(shè)置輸出字符串的長(zhǎng)度,不包含末尾空字符,UTF8字符集漢字占3個(gè)字節(jié)。

syscall指令,發(fā)出一個(gè)內(nèi)中斷,系統(tǒng)內(nèi)核接收到內(nèi)中斷后,根據(jù)寄存器中的參數(shù)執(zhí)行系統(tǒng)調(diào)用。


創(chuàng)建一個(gè)源代碼文件a.c,將上述代碼保存在文件中,之后在終端內(nèi)輸入如下命令:gcc -masm=intel a.c,之后輸入 ./a.out 執(zhí)行程序,將會(huì)在終端內(nèi)輸出“阿貍”。


在高級(jí)編程語言中通過內(nèi)嵌匯編代碼的方式使用系統(tǒng)調(diào)用顯然太過繁瑣,C語言編譯器提供了一個(gè)函數(shù)庫(kù),其實(shí)有些函數(shù)封裝了系統(tǒng)調(diào)用,我們可以使用這些函數(shù)實(shí)現(xiàn)輸入輸出。


?● 輸出函數(shù) - printf


輸出函數(shù)可以向終端發(fā)送一些字符數(shù)據(jù),終端接收到這些數(shù)據(jù)后進(jìn)行顯示,最常用的是printf函數(shù),原型如下:



參數(shù)format,設(shè)置輸出字符串的指針。

執(zhí)行成功返回輸出字符的數(shù)量,執(zhí)行失敗返回-1。



使用終端輸出功能時(shí),往往需要將一些數(shù)值數(shù)據(jù)轉(zhuǎn)換為對(duì)應(yīng)的字符編碼、然后合并到輸出字符串中,此時(shí)可以在輸出字符串中添加一些格式字符,之后將需要輸出的數(shù)值數(shù)據(jù)定義為參數(shù),常用格式字符如下:


%c,將一個(gè)字符合并到輸出字符串中,不進(jìn)行轉(zhuǎn)換。

%s,將一個(gè)字符串合并到輸出字符串中,不進(jìn)行轉(zhuǎn)換。


%hd,將2字節(jié)的有符號(hào)數(shù)轉(zhuǎn)換為對(duì)應(yīng)的字符、并合并到輸出字符串中。

%d,同上,操作4字節(jié)數(shù)據(jù)。

%ld,同上,操作8字節(jié)數(shù)據(jù)。


%hu,將2字節(jié)的無符號(hào)數(shù)轉(zhuǎn)換為對(duì)應(yīng)的字符、并合并到輸出字符串中。

%u,同上,操作4字節(jié)數(shù)據(jù)。

%lu,同上,操作8字節(jié)數(shù)據(jù)。


%f,將float浮點(diǎn)數(shù)轉(zhuǎn)換為對(duì)應(yīng)的字符、并合并到輸出字符串中,小數(shù)部分默認(rèn)顯示6位。

%lf,同上,操作double浮點(diǎn)數(shù)。



有些字符編碼起控制作用,不用來顯示,比如回車、換行,這些字符需要使用轉(zhuǎn)義字符表示。

有些字符與C語言關(guān)鍵詞重復(fù),不能直接編寫,這些字符也需要使用轉(zhuǎn)義字符表示。

常用轉(zhuǎn)義字符如下:


\r,表示回車

\n,表示換行,在linux中可以使用換行表示“換行+回車”兩種功能。

\0,表示空字符

\t,表示水平空白

\v,表示垂直空白

\b,表示退格

\',表示 ' 符號(hào)

\",表示 " 符號(hào)

\?,表示 ? 符號(hào)

\\,表示 \ 符號(hào)



?● 輸入函數(shù) - scanf


用戶可以在終端內(nèi)輸入一個(gè)字符串傳遞給程序,之后程序使用輸入函數(shù)讀取這些數(shù)據(jù),最常用的輸入函數(shù)是scanf,原型如下:



參數(shù)format,指定一個(gè)字符串,存儲(chǔ)格式字符(與printf對(duì)應(yīng)、功能相反),用于將用戶輸入的字符轉(zhuǎn)換為對(duì)應(yīng)的數(shù)值數(shù)據(jù),設(shè)置了幾個(gè)格式字符就需要額外添加幾個(gè)變量指針作為參數(shù),接收轉(zhuǎn)換后的數(shù)據(jù)。




Linux會(huì)為每個(gè)進(jìn)程創(chuàng)建一個(gè)標(biāo)準(zhǔn)輸入文件,存儲(chǔ)用戶在終端內(nèi)輸入的數(shù)據(jù),用戶的輸入以換行結(jié)束,當(dāng)scanf函數(shù)中使用了%c格式字符時(shí)、或者使用getchar輸入函數(shù)時(shí),標(biāo)準(zhǔn)輸入文件內(nèi)的數(shù)據(jù)并不會(huì)完全讀取,下次執(zhí)行輸入函數(shù)時(shí)會(huì)繼續(xù)讀取上次剩余的數(shù)據(jù),若不想使用之前剩余的數(shù)據(jù),可以使用如下代碼清空標(biāo)準(zhǔn)輸入文件。





【數(shù)據(jù)存儲(chǔ)方式】


?● 全局?jǐn)?shù)據(jù)


全局變量會(huì)分配一段專用的虛擬地址存儲(chǔ),可以稱其為全局變量段,全局變量段中未使用的部分操作系統(tǒng)全部設(shè)置為0,所以定義全局變量未賦值的話,默認(rèn)值為0。

全局常量也會(huì)分配一段專用的虛擬地址,可以稱其為全局常量段,此段虛擬地址對(duì)應(yīng)的內(nèi)存頁(yè)會(huì)被操作系統(tǒng)設(shè)置為只讀,修改其中的數(shù)據(jù)會(huì)被CPU禁止。在開啟編譯優(yōu)化后,某些常量也會(huì)轉(zhuǎn)換為立即數(shù)尋址,增加執(zhí)行速度。


?● 局部數(shù)據(jù)


局部變量(包括參數(shù))不需要在程序執(zhí)行期間一直存在,函數(shù)執(zhí)行完畢既刪除,操作系統(tǒng)為程序分配一個(gè)棧空間來存儲(chǔ),所有函數(shù)共用此??臻g,棧空間不會(huì)進(jìn)行初始化操作,定義局部變量不賦值的話,默認(rèn)值無法預(yù)測(cè)。

局部常量默認(rèn)使用棧存儲(chǔ),開始編譯優(yōu)化后會(huì)轉(zhuǎn)換為立即數(shù)尋址,對(duì)于長(zhǎng)度較大的常量字符串,為了增加程序的執(zhí)行速度,會(huì)存儲(chǔ)在全局常量段中。


?● 靜態(tài)局部變量


可以在定義局部變量時(shí)添加static關(guān)鍵詞,表示定義靜態(tài)局部變量,靜態(tài)局部變量在全局變量段中存儲(chǔ),所以它在程序執(zhí)行期間一直存在,它本質(zhì)上是在函數(shù)外定義的全局變量,但禁止其它函數(shù)使用,這個(gè)限制是由編譯器提供的,對(duì)程序進(jìn)行逆向分析并修改時(shí),并不存在任何限制。


靜態(tài)局部變量的作用是保存函數(shù)的執(zhí)行結(jié)果,當(dāng)此函數(shù)再次執(zhí)行時(shí),會(huì)直接取上次保留的結(jié)果使用。



上面的代碼等同于如下代碼,只不過編譯器禁止其它函數(shù)使用變量a。





【數(shù)組作為參數(shù)和返回值】


參數(shù)和返回值只能是單個(gè)的數(shù)據(jù),C語言將數(shù)組當(dāng)做多個(gè)數(shù)據(jù)的集合,而將結(jié)構(gòu)體當(dāng)做一個(gè)獨(dú)立的數(shù)據(jù)對(duì)待,所以兩者在作為參數(shù)和返回值時(shí)會(huì)有不同的命運(yùn)。


?● 結(jié)構(gòu)體作為參數(shù)


結(jié)構(gòu)體作為參數(shù)時(shí)會(huì)轉(zhuǎn)換為其所有成員作為參數(shù)。



編譯器會(huì)轉(zhuǎn)換為類似如下的代碼:



?● 數(shù)組作為參數(shù)


數(shù)組作為參數(shù)時(shí),編譯器會(huì)自動(dòng)轉(zhuǎn)換為其指針作為參數(shù),就比如printf的第一個(gè)參數(shù)為字符指針,但是我們直接使用字符串名為參數(shù)賦值也可以,編譯器會(huì)自動(dòng)轉(zhuǎn)換為指針。



因?yàn)榫幾g器自動(dòng)將數(shù)組參數(shù)轉(zhuǎn)換為指針,所以f函數(shù)操作的其實(shí)是main函數(shù)內(nèi)的數(shù)組,f函數(shù)修改數(shù)組后,main函數(shù)調(diào)用的也是修改后的值,最終main函數(shù)輸出9。


若我們不希望f函數(shù)的修改影響main函數(shù)內(nèi)的數(shù)組,可以在傳遞參數(shù)時(shí)創(chuàng)建數(shù)組的副本,將副本傳遞給f函數(shù),也可以將數(shù)組放在一個(gè)結(jié)構(gòu)體內(nèi),此時(shí)編譯器不會(huì)將數(shù)組轉(zhuǎn)換為指針,而是將數(shù)組內(nèi)所有元素當(dāng)做參數(shù)。



?● 結(jié)構(gòu)體作為返回值


返回值只能是單個(gè)數(shù)據(jù),在64位Linux程序中,整數(shù)型返回值使用rax寄存器保存,若返回一個(gè)結(jié)構(gòu)體,則編譯器自動(dòng)轉(zhuǎn)換為返回其指針,但函數(shù)執(zhí)行完畢后其使用的棧空間將被其它函數(shù)使用,此時(shí)局部結(jié)構(gòu)體的存儲(chǔ)地址將會(huì)被覆蓋,對(duì)于不同編譯器會(huì)使用不同方式解決此問題。


在GCC中,若返回一個(gè)局部結(jié)構(gòu)體實(shí)例,編譯器會(huì)自動(dòng)調(diào)整??臻g的使用情況,下一個(gè)函數(shù)會(huì)自動(dòng)避開此結(jié)構(gòu)體使用的棧空間,防止被覆蓋。

在VC++中,若返回一個(gè)局部結(jié)構(gòu)體實(shí)例,會(huì)自動(dòng)為此函數(shù)創(chuàng)建一個(gè)結(jié)構(gòu)體指針參數(shù),通過指針修改接收返回值的結(jié)構(gòu)體,從而實(shí)現(xiàn)結(jié)構(gòu)體的返回。



VC++編譯器會(huì)轉(zhuǎn)換為類似如下的代碼:



?● 數(shù)組作為返回值


C語言將數(shù)組當(dāng)做一個(gè)數(shù)據(jù)的集合,而返回值只能是單個(gè)數(shù)據(jù),所以數(shù)組不能直接返回,若需返回?cái)?shù)組,可以使用如下方式:


1.通過全局?jǐn)?shù)組進(jìn)行通信,無需返回。

2.函數(shù)內(nèi)定義一個(gè)指針參數(shù),接收調(diào)用者定義的一個(gè)局部數(shù)組進(jìn)行使用,無需返回。

3.函數(shù)內(nèi)定義一個(gè)指針參數(shù),通過指針修改對(duì)方函數(shù)內(nèi)的數(shù)組實(shí)現(xiàn)返回,就像VC++編譯器返回結(jié)構(gòu)體那樣。

4.將數(shù)組放在結(jié)構(gòu)體內(nèi)返回。


通過指針參數(shù)返回:



通過結(jié)構(gòu)體返回:




注:在VC++中可以直接返回局部數(shù)組的指針,在開啟內(nèi)聯(lián)函數(shù)功能時(shí)會(huì)正確執(zhí)行,但是這種方式是錯(cuò)誤的,不要被內(nèi)聯(lián)函數(shù)所迷惑。


計(jì)算機(jī)程序基礎(chǔ)教程(08):C語言 - 函數(shù)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
昭平县| 鹤峰县| 宁远县| 平原县| 柳江县| 札达县| 钦州市| 拉萨市| 临沧市| 呼图壁县| 九龙坡区| 拉萨市| 托克托县| 孟村| 西青区| 平塘县| 曲水县| 全州县| 神农架林区| 乌海市| 禄丰县| 镇雄县| 阿瓦提县| 疏勒县| 冷水江市| 弥勒县| 吉首市| 永新县| 年辖:市辖区| 西城区| 乌拉特前旗| 稷山县| 灵宝市| 海伦市| 海口市| 福鼎市| 万宁市| 湖南省| 高密市| 武宣县| 沈阳市|