国产成人精品三级麻豆,色综合天天综合高清网,亚洲精品夜夜夜,国产成人综合在线女婷五月99播放,色婷婷色综合激情国产日韩

當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 學(xué)習(xí)筆記 > 嵌入式學(xué)習(xí)筆記:C高級函數(shù)快速學(xué)

嵌入式學(xué)習(xí)筆記:C高級函數(shù)快速學(xué) 時間:2018-09-12      來源:未知

c高級可以說是就比較難了,尤其是c高級函數(shù)這是學(xué)習(xí)的難點(diǎn),那么如何快速學(xué)c高級函數(shù)呢,下面總結(jié)了一些函數(shù)知識點(diǎn)及案例,可以快速學(xué)哦。

1.1定義

返回值類型 函數(shù)名(類型 形參, 類型 形參, ...)

{

語句

語句

return 返回值

}

函數(shù)名:標(biāo)識符:用一眼要能看懂函數(shù)的功能的標(biāo)識符來表示函數(shù)名

返回值類型:需要返回的返回值類型

當(dāng)不需要返回值時,返回值類型為void,return后邊需要加返回值

當(dāng)返回值類型為指針時,稱為指針函數(shù)

形參: 接收外部參數(shù)的局部變量

不需要接收參數(shù)時, 寫為void

6.2函數(shù)的調(diào)用

變量 = 函數(shù)名(實(shí)參1, 實(shí)參2, ......);

實(shí)參:傳給函數(shù)的變量或常量值。

運(yùn)行過程:為形參分空間,把實(shí)參賦值給形參

運(yùn)行函數(shù)中的程序

返回調(diào)用函數(shù),運(yùn)行調(diào)用點(diǎn)的下一行

補(bǔ)充:多窗口:vsp

1.3函數(shù)的作用范圍

1.3.1 提前聲明,擴(kuò)大定義域(extern)

實(shí)例:

1.3.2 在文件中,調(diào)用另一個文件中定義的函數(shù)

編譯命令:gcc a.c b.c -g:編譯兩個文件的時候,執(zhí)行依然是a.out

1.3.3. 禁止別的文件調(diào)用本文件的函數(shù)(static)

注意:用了statics的話,不同文件中是可以存在相同的文件名的。

stati將函數(shù)的作用范圍限制在本文件中

1.4變量的作用范圍(這里詳細(xì)的打開內(nèi)存分配的部分及逆行講解)

1.4.1. 定義

全局變量:定義在函數(shù)外的變量,也可以理解為定義在{}外的變量。

局部變量:定義在函數(shù)內(nèi)的變量,也可以理解為定義在{}內(nèi)的變量。

需要定義在{}的開始。

1.4.2 作用域(默認(rèn)作用范圍)

全局變量:從定義開始到文件的結(jié)束

局部變量:從定義開始到與之前一個對應(yīng)的{ }結(jié)束。

注意:小作用范圍的變量,屏蔽大作用范圍的變量

解釋:

這里的擴(kuò)大作用范圍是針對全局變量來說的,局部變量不能擴(kuò)大

方法:1)使用的位置在定義之前

2)使用的位置子其他文件

3)限制全局變量的作用范圍到默認(rèn)作用域

4)函數(shù)的作用域是從定義開始,到本文件結(jié)束(針對文件來說)

實(shí)例:

1.5內(nèi)存的分配

1.5.1.程序未運(yùn)行時(size a.out可以看到信息)

text:存放CPU可執(zhí)行的機(jī)器指令,由于程序被經(jīng)常使用,防止其被意外修改,代碼區(qū)通常是只讀的。

data: 存放被初始化的全局變量、靜態(tài)變量(全局靜態(tài)變量和局部靜態(tài)變量)、常量數(shù)據(jù)(如字符串常量)。

Bss:存放未初始化的全局變量 (初始化成0,計算機(jī)并不認(rèn)為這是做了初始化操作,所以初始化成0的全局變量會被放在bss區(qū)中)

注意:BSS區(qū)的數(shù)據(jù)在程序開始執(zhí)行之前被內(nèi)核初始化為0或空指針(NULL)。

具體:

1.5.2.程序運(yùn)行時

程序運(yùn)行時占用5個區(qū):代碼區(qū)、初始化數(shù)據(jù)區(qū)/靜態(tài)數(shù)據(jù)區(qū)、未初始化數(shù)據(jù)區(qū)、堆區(qū)、棧區(qū)

(1)代碼區(qū)(text)

代碼區(qū)指令根據(jù)程序設(shè)計流程依次執(zhí)行,對于順序指令,則只會執(zhí)行一次,如果反復(fù),則需使用跳轉(zhuǎn)指令,如果進(jìn)行遞歸,則需借助棧來實(shí)現(xiàn)。

代碼區(qū)包括操作碼和要操作的對象(或?qū)ο蟮牡刂芬?,如果是立即數(shù)(即具體的數(shù)值,如2),將直接包含在代碼中;如果是局部數(shù)據(jù),將在棧中分配空間,然后引用該數(shù)據(jù)的地址;如果是BSS區(qū)和數(shù)據(jù)區(qū),在代碼中同樣引用該數(shù)據(jù)的地址。

(2) 全局初始化數(shù)據(jù)區(qū)/靜態(tài)數(shù)據(jù)區(qū)(data)

在編譯的時候就會初始化,并且只初始化一次。上面已經(jīng)說過,在程序編譯時,該區(qū)域已經(jīng)被分配好了,這塊內(nèi)存在程序的整個運(yùn)行期間都存在,當(dāng)程序結(jié)束時,才會被釋放。

(3)未初始化數(shù)據(jù) 區(qū)(BSS):在運(yùn)行時改變其值。初始化0不算初始化。

(4)棧區(qū)(stack)

存放函數(shù)的參數(shù)值和局部變量,由編譯器自動分配釋放,其操作方式類似于數(shù)據(jù)結(jié)構(gòu)的棧。其特點(diǎn)是不需要程序員去考慮內(nèi)存管理的問題,很方便;同時棧的容量很有限,在Linux系統(tǒng)中,棧的容量只有8M,并且當(dāng)相應(yīng)的范圍結(jié)束時(如函數(shù)),局部變量就不能再使用。

(5)堆區(qū)(heap)

有些操作對象只有在程序運(yùn)行時才能確定,這樣編譯器在編譯時就無法為他們預(yù)先分配空間,只有程序運(yùn)行時才分配,這就是動態(tài)內(nèi)存分配。堆區(qū)就是用于動態(tài)內(nèi)存分配(如malloc的動態(tài)內(nèi)存分配),堆在內(nèi)存中位于bss區(qū)和棧區(qū)之間,一般由程序員申請和釋放(free釋放或程序停止)。

實(shí)例:

注意:

(1):堆區(qū)的內(nèi)存需要程序員自己釋放。

(2):棧區(qū)在范圍結(jié)束時,編譯器就會釋放了,所以要注意棧區(qū)中數(shù)據(jù)的生命周期。

(3):棧區(qū)容量有限,注意不要使用超大局部變量,比如超大數(shù)組。

(4):bss區(qū)中的數(shù)據(jù),你不進(jìn)行初始化的話,系統(tǒng)會幫我們初始化成0。但其他區(qū)域的數(shù)據(jù),系統(tǒng)不會為我們做什么,尤其注意堆區(qū)和棧區(qū)中的數(shù)據(jù),未經(jīng)初始化的變量則有可能是臟數(shù)據(jù)。

1.6變量的生命周期

1.6.1分類

1. data和bss中的變量的生命周期:程序的開始到程序的結(jié)束。==>全局變量,靜態(tài)(全局/局部)變量

2. 棧中的變量的生命周期:函數(shù)的開始到函數(shù)的結(jié)束。==>局部變量,形參

6.6.2對靜態(tài)局部變量的說明:

有時希望函數(shù)中的局部變量的值在函數(shù)調(diào)用結(jié)束后不消失而保留原值,即其占用的存儲單元不釋放,在下一次該函數(shù)調(diào)用時,該變量保留上一次函數(shù)調(diào)用結(jié)束時的值。這時就應(yīng)該指定該局部變量為靜態(tài)局部變量(static local variable)。

(1) 靜態(tài)局部變量在靜態(tài)存儲區(qū)內(nèi)分配存儲單元。在程序整個運(yùn)行期間都不釋放。而自動變量(即動態(tài)局部變量)屬于動態(tài)存儲類別,存儲在動態(tài)存儲區(qū)空間(而不是靜態(tài)存儲區(qū)空間),函數(shù)調(diào)用結(jié)束后即釋放。

(2) 為靜態(tài)局部變量賦初值是在編譯時進(jìn)行值的,即只賦初值一次,在程序運(yùn)行時它已有初值。以后每次調(diào)用函數(shù)時不再重新賦初值而只是保留上次函數(shù)調(diào)用結(jié)束時的值。而為自動變量賦初值,不是在編譯時進(jìn)行的,而是在函數(shù)調(diào)用時進(jìn)行,每調(diào)用一次函數(shù)重新給一次初值,相當(dāng)于執(zhí)行一次賦值語句。

(3) 如果在定義局部變量時不賦初值的話,對靜態(tài)局部變量來說,編譯時自動賦初值0(對數(shù)值型變量)或空字符(對字符型變量)。而對自動變量來說,如果不賦初值,則它的值是一個不確定的值。這是由于每次函數(shù)調(diào)用結(jié)束后存儲單元已釋放,下次調(diào)用時又重新另分配存儲單元,而所分配的單元中的值是不確定的。

(4) 雖然靜態(tài)局部變量在函數(shù)調(diào)用結(jié)束后仍然存在,但其他函數(shù)是不能引用它的,也就是說,在其他函數(shù)中它是“不可見”的。

具體解釋:

初始化全局變量未初始化全局變量局部變量靜態(tài)全局變量靜態(tài)局部變量

占用存儲空間data

bss棧datadata

初始化次數(shù)初始化一次

初始化一次每次調(diào)用都初始化初始化一次初始化一次

作用域默認(rèn)作用域,可擴(kuò)大默認(rèn)作用域,可擴(kuò)大默認(rèn)作用域默認(rèn)作用域默認(rèn)作用域

生命周期程序開始->程序結(jié)束 程序開始->程序結(jié)束定義開始,函數(shù)結(jié)束程序開始->程序結(jié)束程序開始->程序結(jié)束

補(bǔ)充:register變量

register int r_local = 6;要求編譯器盡量放在寄存器,register變量是不能做取地址操作的

register使用寄存器變量會提升速度,也并不是說我們盡可能地多地定義register變量就能加快程序的運(yùn)行速度,畢竟CPU中寄存器是有限的,

如果你把變量指定為register變量,意味著可用于別的用途的寄存器就減少了,如程序運(yùn)算產(chǎn)生的中間結(jié)果,它們的應(yīng)用又很頻繁,

在寄存器不足的情況下,只好借助于內(nèi)存,這樣反倒會降低程序的運(yùn)算速度。

在現(xiàn)今的C版本中,大多已沒有定義register變量的必要,因?yàn)榫幾g程序忽略register修飾符,而根據(jù)寄存器的使用情況和變量的情況決定是否把變量解釋為register變量。

1.7函數(shù)的傳參

1.7.1 指針參數(shù)

補(bǔ)充:還有種應(yīng)用場景,就是需要使用結(jié)構(gòu)體作為參數(shù)的時候,因?yàn)樾螀⑾牡氖菞5目臻g,棧的空間是有限的,如果結(jié)構(gòu)體比較大,一般不建議直接將結(jié)構(gòu)體作為形參,而是通過指針對其進(jìn)行訪問。

1.7.2 數(shù)組參數(shù)

int atoil(char str[10])

int atoil(char str[])

int atoil(char *str)

這三種定義的形式不同,但是達(dá)到的效果是一模一樣的,不管使用哪一種定義,編譯器都會將其轉(zhuǎn)換成第三種形式。

1.8指針函數(shù) VS 函數(shù)指針

1.8.1 指針函數(shù)(pointfunc.c)

確定方法:

(1)確定目標(biāo)類型 int buf[5]

(2)確定指針類型 在目標(biāo)類型基礎(chǔ)上加* 加在變量名位置 int (*)[5]

(3)定義指針變量 int (*p)[5]

實(shí)例:

1.8.2 函數(shù)指針:首先是指針,指向的是函數(shù)。

(1) 定義

void swap(int *a, int *b)

void (*pfunc)(int *, int *);

(2) 賦值

pfunc = &swap;

pfunc = swap; (函數(shù)名, 就是函數(shù)的指針常量)

注意:函數(shù)類型和函數(shù)指針類型兼容,上邊兩種定義形式可以隨便選擇使用

(3) 調(diào)用

(*pfunc)(&a, &b);//將swap理解成函數(shù)

pfunc(&a, &b); //將swap理解成函數(shù)指針,這兩種調(diào)用隨便選擇,跟上邊的定義是沒有關(guān)系的。

實(shí)例:

補(bǔ)充:strcmp 比較字符串大小 qsort 可以快速排序

用法:

shrcmp

strcmp()函數(shù)是通過兩個字符串一個一個字符比較的(最多比較次數(shù)為第二個參數(shù)的長度+1)

例如strcmp("hello","here");

首先比較第一個字符'h'= 'h'相等

接著比較第二個字符'e'= 'e'相等

比較第三個字符 'l'>'e',返回一個正值

如果字符串完全相等會回0

qsort:

qsort是萬能數(shù)組排序函數(shù),必須要學(xué)會使用,簡單的數(shù)組自然不用說,這里主要討論一下字符串?dāng)?shù)組的使用。

首先看一下qsort的原型:

void qsort(void *base, size_t nmemb, size_t size,

int(*compar)(const void *, const void *));

正確使用這個函數(shù)要注意幾點(diǎn):

1.base要傳數(shù)組的首地址

2.size傳的是每個元素的大小

3.正確編寫compar函數(shù)

下面是實(shí)際應(yīng)用:

一個字符串?dāng)?shù)組:*str[MAX],假設(shè)里面現(xiàn)在保存了n個字符串了。

首先要正確理解什么是字符串?dāng)?shù)組,簡單的說,可以理解成它就是一個數(shù)組,只不過其中的元素是一串字符串,而訪問這些字符串,得用指針,也就是它們的地址,比如*name[]={"james","henry"},那么訪問其中的字符串就是name[0],name[1]...這里就有個容易混淆的地方了,對于字符串?dāng)?shù)組,那么每個元素的大小到底是多少呢?對name[0]來說,到底是字符串“james”的長度5,還是char*的大小4呢?答案應(yīng)該是4,因?yàn)樽址當(dāng)?shù)組里面保存的是各個字符串的指針,所以回到上面所說的第二點(diǎn)注意,用qsort的時候應(yīng)該要傳sizeof(char *);

第二,編寫compar函數(shù)比較字符串有地方要注意:

不能把strcmp本身傳給qsort,即不能寫strcmp(p,q),因?yàn)樾螀⑹莄onst void*類型,同理,寫成strcmp((char *)p, (char *)q);也是無效的;正確的寫法應(yīng)該是:strcmp(*(char **)p, *(char **)q);先強(qiáng)制轉(zhuǎn)換成char**,在用*減少一層間接尋址操作:

int compar_words(const void *p, const void *q)

{

return strcmp(*(char **)p, *(char **)q);

}

對于上面的應(yīng)用,最后使用qsort應(yīng)該是這樣:

qsort(str, n, sizeof(char *), compar);

實(shí)例:比較數(shù)組中的字符串的大小

 

1.9遞歸函數(shù)

定義:直接或間接調(diào)用自己

注意:遞歸程序的效率比較低,空間占用的也很多,唯一的理由是比較容易看懂。

例: 利用函數(shù)遞歸實(shí)現(xiàn)n!

1. 寫出遞歸通用項:n! = n * (n - 1)!

2. 寫出遞歸結(jié)束條件:n = 1

3. 代碼實(shí)現(xiàn):假設(shè)函數(shù)已經(jīng)寫好,可以用調(diào)用,不要去想計算機(jī)執(zhí)行的具體過程

4. 單步執(zhí)行, 掌握執(zhí)行流程

實(shí)例:實(shí)現(xiàn)階乘 將輸入的字符串反向輸出。

上一篇:嵌入式學(xué)習(xí)筆記:shell腳本學(xué)習(xí)從入門到精通

下一篇:嵌入式學(xué)習(xí)筆記:c語言結(jié)構(gòu)體定義和使用

熱點(diǎn)文章推薦
華清學(xué)員就業(yè)榜單
高薪學(xué)員經(jīng)驗(yàn)分享
熱點(diǎn)新聞推薦
前臺專線:010-82525158 企業(yè)培訓(xùn)洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠(yuǎn)見科技集團(tuán)有限公司 版權(quán)所有 ,京ICP備16055225號-5京公海網(wǎng)安備11010802025203號

回到頂部