《單片機原理及其C語言程序設(shè)計》課件-第4章_第1頁
《單片機原理及其C語言程序設(shè)計》課件-第4章_第2頁
《單片機原理及其C語言程序設(shè)計》課件-第4章_第3頁
《單片機原理及其C語言程序設(shè)計》課件-第4章_第4頁
《單片機原理及其C語言程序設(shè)計》課件-第4章_第5頁
已閱讀5頁,還剩128頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第4章MCS-51單片機的C程序設(shè)計基礎(chǔ)4.1基本概念4.2變量和常量4.3運算符和表達式4.4控制語句4.5函數(shù)4.6數(shù)組和指針4.7結(jié)構(gòu)與共用體本章小結(jié)

C語言被稱為中級語言,這是因為它和匯編語言類似,能直接訪問計算機底層資源,同時它又具備了高級語言的各種優(yōu)點。首先作為中級語言,C允許對位、字節(jié)和地址這些計算機功能中的基本成分進行操作,其次C語言程序非常容易移植,甚至可以設(shè)計出能同時運行在Linux、UNIX和Windows等操作系統(tǒng)上的軟件。

C語言作為一種結(jié)構(gòu)化語言。使用的設(shè)計方法為模塊化設(shè)計方法,每個子問題求解的步驟被定義為模塊。在C語言中,其函數(shù)就是模塊化的體現(xiàn),函數(shù)之間是相互獨立的,函數(shù)內(nèi)的數(shù)據(jù)只能通過接口進行傳遞。數(shù)據(jù)與代碼是分離的,數(shù)據(jù)在各個函數(shù)之間通過接口傳遞,因此,設(shè)計良好的函數(shù)能夠在多個程序間反復(fù)使用,構(gòu)成了代碼復(fù)用的基礎(chǔ)。

4.1基本概念

學(xué)習(xí)新的程序設(shè)計語言的最佳途徑是編寫程序。編寫C語言程序在某種意義上來說就好像是用磚蓋房子:首先打好地基,然后使用沙子和水泥把磚堆砌起來,最后建成房子。每個C語言程序至少有一個主函數(shù),即main()函數(shù)。它是C語言程序的基礎(chǔ),是程序代碼執(zhí)行的起點。所有的函數(shù)都是通過main()函數(shù)直接或間接調(diào)用的。

main()函數(shù)通常被認為是最低級的任務(wù),因為它是啟動該程序系統(tǒng)所調(diào)用的第一個函數(shù)。在很多的情況下,main()函數(shù)都只包含很少的語句,這些語句的作用僅僅是初始化和指導(dǎo)從一個函數(shù)到另一個函數(shù)的程序操作。

一個最簡單的嵌入式C語言程序如下:

4.2變量和常量

4.2.1變量類型變量是通過用于指示變量類型和大小的保留字和跟在保留字后面的標識符來聲明的,如

變量和常量存儲在微控制器的存儲器中,編譯器需要知道為每個變量預(yù)留多少存儲地址,而不浪費存儲器空間,因此程序員必須聲明變量,同時指明變量的大小和類型。表4-1列出了單片機所用的C51語言中支持的幾種變量類型及其大小。

注:

(1)?Bit:位標量。

(2)?SFR:特殊功能寄存器。

(3)?SFR16:16位特殊功能寄存器。

(4)?Sbit:可尋址位。

這樣在以后的程序語句中就可以用P1_1來對P1.1引腳進行讀寫操作了。通常編程者可以直接使用系統(tǒng)提供的預(yù)處理文件,里面已定義好各特殊功能寄存器的簡單名字,直接引用即可。當然用戶也可以編寫自己的定義文件。關(guān)于數(shù)據(jù)類型轉(zhuǎn)換等相關(guān)操作在后面的課程或程序?qū)嵗袑⒂兴峒啊?/p>

4.2.2變量的作用域

變量的作用域是指變量在程序中可訪問的范圍。變量可被聲明為局部變量或全局變量,相應(yīng)地,具有局部作用域或全局作用域。

1.局部變量

局部變量是在創(chuàng)建函數(shù)時由函數(shù)分配存儲器的空間,這些變量不能被其他的函數(shù)訪問,其作用域只限于所聲明的函數(shù)內(nèi)部。同一個局部變量可以在多個函數(shù)中聲明,而不會引起沖突,因為編譯器會將這些變量視為每個函數(shù)的一部分。

2.全局變量

全局變量是由編譯器分配的存儲器空間,可被程序內(nèi)所有的函數(shù)訪問。全局變量能被任何函數(shù)修改,并且會保持全局變量的值,以便其他函數(shù)可以使用。

全局變量在main()函數(shù)開始執(zhí)行時進行了清零,此操作通常由編譯器產(chǎn)生的啟動代碼執(zhí)行,對于程序員來說是不可見的。

下面的代碼演示了變量的作用域:

4.2.3常量

常量有固定值,在程序執(zhí)行時不會改變。在很多情況下常量是經(jīng)過編譯之后的程序本身的一部分,位于只讀存儲器(ROM)中,不被分配到可變隨機存儲器(RAM)中。在賦值

運算

中,數(shù)字3是常量,可以由編譯器直接編碼到加法操作中。

常量同樣可以是字符形式或字符串形式:

文本IloveMCU51和字符'A'存儲在ROM中,不會被改變。也可以通過保留字const來聲明常量,并且定義其類型和大小。

把變量指定為常量,可使該變量存儲在ROM中,而不是RAM中,這樣有利于節(jié)省有限的RAM空間。

1.數(shù)值型常量

數(shù)值型常量可以通過指定基數(shù)的形式來聲明,使程序更具有可讀性。

(1)無前綴的十進制形式(如123,0,-89等)。

(2)前綴為0b的二進制形式(如0b0010)。

(3)前綴為0x的十六進制形式(如0xff)。

(4)前綴為o的八進制形式(如o171)。

2.字符型常量

字符型常量可以是可打印字符(比如0~9,a~z),也可以是無法打印出來的字符(如換行符、回車符或者制表符)。可打印字符型常量可以由單引號引起來,不可以顯示的控制字符,可以在該字符前面加一個反斜杠(\)組成專用轉(zhuǎn)義字符。常用轉(zhuǎn)義字符表如表4-2所示。

3.字符串型常量

字符串型常量由雙引號內(nèi)的字符組成,如"hello","OK"等。當引號內(nèi)沒有字符時為空字符串。在使用特殊字符時同樣要使用轉(zhuǎn)義字符如雙引號。在C中字符串常量是作為字符類型數(shù)組來處理的,在存儲字符串時系統(tǒng)會在字符串尾部加上\o轉(zhuǎn)義字符以作為該字符串的結(jié)束符,所以字符串常量"A"和字符常量'A'?是不同的,前者在存儲時多占用一個字節(jié)的空間。

4.2.4枚舉和定義

在C語言程序中,可讀性是十分重要的。C語言提供了枚舉類型和定義類型,這使程序員能夠用有意義的名字或其他更為有意義的短語來代替數(shù)字。

舉數(shù)據(jù)類型就是把某些整型常量的集合用一個名字表示,其中的整型常量就是這種枚舉類型變量的可取的合法值。枚舉類型的兩種定義格式如下:

(1)?enum枚舉名{枚舉值列表}變量列表;

例:enumTFFlag{False,True}TFF;

(2)?enum枚舉名{枚舉值列表};

emum枚舉名變量列表;

例:enumWeek{Sun,Mon,Tue,Wed,Thu,Fri,Sat};

enumWeekOldWeek,NewWeek;

看了上面的例子,就會發(fā)現(xiàn)枚舉值不用賦值就能使用,這是因為在枚舉列表中,每一項名稱代表一個整數(shù)值,在默認的情況下,編譯器會自動為每一項賦值,第一項賦值為0,第二項為1……如Week中的Sun為0,F(xiàn)ri為5。C語言也允許對各項值作初始化賦值,要注意的是在對某項值初始化后,它的后續(xù)各項值也隨之遞增,如:

enumWeek{Mon=1,Tue,Wed,Thu,Fri,Sat,Sun};

上例的枚舉就使Week值從1到7,這樣的賦值也符合我們?nèi)粘I钪袑χ艽螘r序關(guān)系的定義。使用枚舉就如變量一樣,但在程序中不能為其賦值。

定義類型在某種程度上同枚舉類型相似,因為定義允許用一個文本串代替另一個文本串,例如:

語句#defineucharunsignedchar的作用是使編譯器在遇到單詞uchar時用unsignedchar來代替。注意#defineucharunsignedchar這一行的結(jié)束沒有分號。

#define是預(yù)處理程序指令。預(yù)處理程序指令實際上不是C語言語法的一部分,但是它們同樣得到了廣泛的接受與使用。程序的預(yù)處理與實際程序的編譯是分開進行的,預(yù)處理在編譯開始之前進行。

4.2.5存儲類型

1.自動變量

自動變量是指在函數(shù)內(nèi)部說明的變量,一般常被稱為局部變量,用關(guān)鍵字auto進行說明,當auto省略時,對應(yīng)的都被認為是局部變量。

局部變量在函數(shù)調(diào)用時自動產(chǎn)生,但不會自動初始化,隨著函數(shù)調(diào)用的結(jié)束,變量也就自動消失了,下次調(diào)用此函數(shù)時局部變量再自動產(chǎn)生,還要再次賦值,退出時又自動消失。自動類型的變量聲明如下:

2.靜態(tài)變量

static稱為靜態(tài)變量。根據(jù)變量的類型又可以分為靜態(tài)局部變量和靜態(tài)全程變量。

(1)靜態(tài)局部變量。

靜態(tài)局部變量與局部變量的區(qū)別在于:在函數(shù)退出時,靜態(tài)局部變量始終存在,但不能被其他函數(shù)使用,當再次進入該函數(shù)時,該變量將保存上次的結(jié)果。

(2)靜態(tài)全程變量。

C語言允許將大型程序分成若干獨立模塊文件分別編譯,然后將所有模塊的目標文件連接在一起,從而提高編譯速度,同時也便于軟件的管理和維護。靜態(tài)全程變量就是指只在定義它的源文件中可見,而在其他源文件中不可見的變量。它與全程變量的區(qū)別是:全程變量可以再說明為外部變量(extern),被其他源文件使用,而靜態(tài)全程變量卻不能再被說明為外部的,即只能被所在的源文件使用,如:

3.外部變量

extern稱為外部變量。為了使變量除了在定義它的源文件中可以使用外,還能被其他文件使用就必須將全程變量通知每一個程序模塊文件,此時可用extern來說明。

4.寄存器變量

寄存器變量與自動變量類似,它只能應(yīng)用于整型和字符型變量。定義符register說明的變量被編譯器存儲在CPU的寄存器中,而不是像普通的變量那樣存儲在內(nèi)存中,這樣可以提高運算速度。但是編譯器只允許同時定義兩個寄存器變量,一旦超過兩個,編譯程序會自動地將超過限制數(shù)的目的寄存器變量當作非寄存器變量來處理,因此寄存器變量常用在同一變量名頻繁出現(xiàn)的地方。

5.C51的數(shù)據(jù)存儲類型

C51允許將變量或常量定義成不同的存儲類型。C51允許的存儲類型主要包括data、bdata、idata、pdata、xdata和code等,它們和單片機的不同存儲區(qū)相對應(yīng)。C51的存儲類型與MCS-51單片機的實際存儲空間的對應(yīng)關(guān)系如表4-3所示。

以下是變量常見存儲類型的例子(C51支持ANSIC和C++的注釋方法):

(1)?chardatavar1;/*字符變量var1被定義為data型,被分配在片內(nèi)RAM中*/

(2)?bitbdataflags;//位變量flags被定義為bdata型,定位在片內(nèi)RAM中的位尋址區(qū)

(3)?floatidatax,y,z;//浮點型變量x、y和z被定義為idata存儲類型,定位在片內(nèi)

//RAM中,并只能用間接尋址方式進行訪問

(4)?unsignedintpdatadimension;//無符號整型變量dimension被定義為pdata型,定位

//在片外數(shù)據(jù)存儲區(qū),相當于用MOVX@Ri訪問

如果在變量定義時略去存儲類型標志符,編譯器會自動默認存儲類型。默認的存儲類型由SMALL、COMPACT和LARGE存儲模式指令限制。例如,若表明charvar1在SMALL存儲模式下,var1被定位在data存儲區(qū);在COMPACT模式下,var1被定位在idata存儲區(qū);在LARGE模式下,var1被定位在xdata存儲區(qū)中。存儲模式及其說明如表4-4所示。

4.3運算符和表達式

4.3.1賦值運算符和算術(shù)運算符“=”這個符號大家不會陌生,在C語言中它的功能是給變量賦值,稱之為賦值運算符,它的作用是將數(shù)據(jù)賦給變量,如x=10。利用賦值運算符將一個變量與一個表達式連接起來的式子為稱賦值表達式,在表達式后面加“;”便構(gòu)成了賦值語句。使用“=”的賦值語句格式如下:變量=表達式;

示例如下:

4.3.2邏輯運算符和關(guān)系運算符

1.邏輯運算符及其優(yōu)先級

邏輯運算是對變量進行邏輯與運算、或運算及非運算。C51提供以下三種邏輯運算符:

&&(邏輯與):條件式1&&條件式2。

||(邏輯或):條件式1||條件式2。

!(邏輯非):!條件式1。

(1)邏輯與:是指當條件式1“與”條件式2都為真時結(jié)果為真(非0值),否則為假(0值)。也就是說運算會先對條件式1進行判斷,如果為真(非0值),則繼續(xù)對條件式2進行判斷,當結(jié)果也為真時,邏輯運算的結(jié)果為真(值為1),如果結(jié)果不為真時,邏輯運算的結(jié)果為假(0值)。如果在判斷條件式1時就不為真的話,就不用再判斷條件式2了,而直接給出運算結(jié)果為假。

(2)邏輯或:是指只要兩個運算條件中有一個為真時,運算結(jié)果就為真,只有當條件式都不為真時,邏輯運算結(jié)果才為假。

(3)邏輯非:是指把邏輯運算結(jié)果值取反,也就是說如果條件式的運算值為真,進行邏輯非運算后則結(jié)果變?yōu)榧伲瑮l件式運算值為假時最后邏輯結(jié)果為真。

其中,非運算的優(yōu)先級最高,而且高于算術(shù)運算符;或運算的優(yōu)先級最低,低于關(guān)系運算符,但高于賦值運算符。

以下舉例說明了它們之間的區(qū)別:

假設(shè)x=9,y=6;

2.邏輯表達式

用邏輯運算符將運算對象連接起來的式子稱為邏輯表達式。運算對象可以是表達式或邏輯量,而表達式可以是算術(shù)表達式、關(guān)系表達式或邏輯表達式。邏輯表達式的值也是邏輯量,即真或假。對于算術(shù)表達式,其值若為0,則認為是邏輯假;若不為0,則認為是邏輯真。邏輯表達式并非一定完全被執(zhí)行,僅當必須要執(zhí)行下一個邏輯運算符才能確定表達式的值時,才執(zhí)行該運算符。

3.關(guān)系運算符

對于關(guān)系運算符,同樣我們也并不陌生,C語言中有6種關(guān)系運算符:

>:大于。

<:小于。

>=:大于等于。

<=:小于等于。

==:等于。

!=:不等于。

前四個具有相同的優(yōu)先級,后兩種也具有相同的優(yōu)先級,但是前四種的優(yōu)先級要高于后兩種。

當兩個表達式用關(guān)系運算符連接起來時,這時就是關(guān)系表達式。關(guān)系表達式通常用來判別某個條件是否滿足。要注意的是關(guān)系運算符的運算結(jié)果只有0和1兩種,也就是邏輯的真與假。當指定的條件滿足時結(jié)果為1,不滿足時結(jié)果為0,其格式為

表達式1關(guān)系運算符表達式2

如:i<j,i==j,(i=4)>(j=3),j+i>j。

假如x=2,y=4,表4-5為它們關(guān)系運算符示例。

4.3.3自增運算符、自減運算符和復(fù)合賦值運算符

1.增減量運算符

++為自增運算符,--為自減運算符。

例如:++j、j++、--i、i--。

++和--運算符只能用于變量,不能用于常量和表達式。++j表示先加1,再取變量值;j++表示先取變量值,再加1。自減運算也是如此。

2.復(fù)合賦值運算符

復(fù)合賦值運算符就是在賦值運算符“=”的前面加上其他運算符。以下是C語言中的復(fù)合賦值運算符:

其含義就是變量與表達式先進行運算符所要求的運算,再把運算結(jié)果賦值給參與運算的變量。其實這是C語言中一種簡化程序的方法,凡是二目運算都可以用復(fù)合賦值運算符去簡化表達式,例如:

4.3.4C51的位運算

位運算的操作對象只能是整型和字符型數(shù)據(jù),不能是實型數(shù)據(jù)。C51提供以下六種位運算:

&:按位與運算。

|:按位或運算。

^:按位異或運算。

~:按位取反運算。

<<:左移運算。

>>:右移運算。

4.3.5條件表達式

C語言中有一個三目運算符,它就是“?”條件運算符。條件運算符要求有三個運算對象,它可以把三個表達式連接構(gòu)成一個條件表達式。條件表達式的一般形式如下:

邏輯表達式?表達式1:表達式2

條件運算符的作用簡單來說就是根據(jù)邏輯表達式的值選擇使用表達式的值。當邏輯表達式的值為真時(非0值)時,整個表達式的值為表達式1的值;當邏輯表達式的值為假(值為0)時,整個表達式的值為表達式2的值。要注意的是條件表達式中邏輯表達式的類型可以與表達式1和表達式2的類型不一樣。

下面是一個邏輯表達式的例子:

如a=1,b=2時,要求取a、b兩數(shù)中的較小的值放入min變量中,一般使用判斷語句可以寫成:

4.3.6運算符優(yōu)先級

在一個語句中有多個表達式時,運算符的優(yōu)先級確定了編譯器對表達式進行求值的順序。在出現(xiàn)賦值和表達式的情況下,必須記住這些優(yōu)先級,當有疑問時,可以加上括號來保證處理順序,或者查看運算符的優(yōu)先級加以確認。表4-6列出了執(zhí)行時各運算符的優(yōu)先級和次序。

4.4控制語句

4.4.1if/else語句1.if(條件表達式)語句當條件表達式的結(jié)果為真時,就執(zhí)行語句,否則就跳過。如if(a==b)a++;//當a等于b時,a就加1

2.?if(條件表達式)語句1

?else語句2

當條件表達式成立時,就執(zhí)行語句1,否則就執(zhí)行語句2,如:

3.?if(條件表達式1)語句1

elseif(條件表達式2)語句2

elseif(條件表達式3)語句3

elseif(條件表達式m)語句n

else語句m

這是由if/else語句組成的嵌套,用來實現(xiàn)多方向條件分支,使用時應(yīng)注意if和else的配對使用,要是少了一個就會出現(xiàn)語法錯誤,記住else總是與最臨近的if相配對。一般條件語句只會用作單一條件或少數(shù)量的分支,如果多數(shù)量的分支時則更多地會用到下一篇中的開關(guān)語句。如果使用條件語句來編寫超過3個以上的分支程序的話,會使程序變得不是那么清晰、易讀。

4.4.2while循環(huán)

while在英語中的意思是“當……的時候”,在這里我們可以理解為“當條件為真的時候就執(zhí)行后面的語句”,它的語法如下:

while(條件表達式)語句;

如:

4.4.3do/while循環(huán)

do/while語句可以說是while語句的補充,while是先判斷條件是否成立再執(zhí)行循環(huán)體,而do/while則是先執(zhí)行循環(huán)體,再根據(jù)條件判斷是否要退出循環(huán),這樣就決定了循環(huán)體無論在任何條件下都會至少被執(zhí)行一次,它的語法如下:

do語句while(條件表達式)

4.4.4for循環(huán)

在循環(huán)次數(shù)明確的情況下,使用for語句比使用上述循環(huán)語句都要方便、簡單。它的語法如下:

for([初值設(shè)定表達式];[循環(huán)條件表達式];[條件更新表達式])

4.4.5switch/case語句

在學(xué)習(xí)了條件語句后,用多個條件語句可以實現(xiàn)多方向條件分支,但是使用過多的條件語句實現(xiàn)多方向分支會使條件語句嵌套過多,造成程序冗長,不易讀寫,這時使用switch/case(開關(guān))語句同樣可以達到處理多分支選擇的目的,又可以使程序結(jié)構(gòu)清晰。

switch/case的語法如下:

4.4.6continue和goto語句

1.?continue語句

continue語句是用于中斷的語句,通常使用在循環(huán)中,它的作用是結(jié)束本次循環(huán),跳過循環(huán)體中沒有執(zhí)行的語句,跳轉(zhuǎn)到下一次循環(huán)周期,其語法為

continue;

continue同時也是一個無條件跳轉(zhuǎn)語句,但功能和前面說到的break語句有所不一樣,continue執(zhí)行后不是跳出循環(huán),而是跳到循環(huán)的開始并執(zhí)行下一次的循環(huán)。

2.?goto語句

這個語句在很多高級語言中都會有,它是一個無條件的轉(zhuǎn)向語句,只要執(zhí)行到這個語句,程序指針就會跳轉(zhuǎn)到goto后的標號所在的程序段。它的語法如下:

goto語句標號;

4.5函數(shù)

C語言是由函數(shù)構(gòu)成的。一般功能較多的程序會在編寫程序時把每項單獨的功能分成多個子程序,每個子程序都用函數(shù)來實現(xiàn)。這些函數(shù)還能被反復(fù)地調(diào)用,通常一些常用的函數(shù)可構(gòu)成函數(shù)庫以供在編寫程序時直接調(diào)用,從而更好地實現(xiàn)模塊化的程序設(shè)計,大大提高編程工作的效率。

4.5.1函數(shù)的定義

通常C語言的編譯器都會自帶標準的函數(shù)庫,函數(shù)庫中都是一些常用的函數(shù)。KeiluVision2中也不例外,標準函數(shù)已由編譯器軟件商編寫定義,使用者直接調(diào)用,無需定義,但是標準函數(shù)有時不足以滿足使用者的特殊要求,因此C語言也允許使用者根據(jù)需要編寫特定功能的函數(shù)。

函數(shù)調(diào)用前必須先對其進行定義,定義的格式如下:

說明:用戶函數(shù)的定義通常分為兩部分:一是函數(shù)體(即一對花括號括住的部分);二是函數(shù)頭(即函數(shù)體前面的部分)。

函數(shù)頭包含了函數(shù)類型說明和形式參數(shù)表等幾項:

(1)函數(shù)類型:用來指定本函數(shù)返回值的數(shù)據(jù)類型,可以是前面介紹的各種基本類型,也可以是后面將要介紹的其他類型(如結(jié)構(gòu)體等)。函數(shù)類型說明符也可以省略,若省略,則系統(tǒng)默認函數(shù)返回值的數(shù)據(jù)類型是int。

(2)函數(shù)名稱:是由用戶命名的,命名規(guī)則同用戶標識符。在同一個文件中,函數(shù)是不允許重名的。

(3)無參函數(shù)的函數(shù)名后面的“()”不能省略。在調(diào)用無參函數(shù)時,沒有參數(shù)傳遞。有參函數(shù)的函數(shù)名后面的“()”內(nèi)是用逗號分隔的若干個形式參數(shù),每個參數(shù)也必須指定數(shù)據(jù)類型。

【例4-1】定義一個用戶函數(shù),用于求三個整數(shù)中的最大值,并返回其值。程序如下:

說明:由上面用戶函數(shù)的定義可知,該函數(shù)返回值的類型為int,函數(shù)名為max,它的三個形式參數(shù)x、y、z都是int類型。另外,該函數(shù)體中還定義了int變量max1,其他語句為求三個整數(shù)中最大值的程序段。

注意:該用戶函數(shù)不能單獨運行,只有在主函數(shù)調(diào)用后,才可實際運行。

4.5.2函數(shù)的返回值

每一個函數(shù)都具有一定的功能,如例4-1中的max函數(shù),其功能是求三個整數(shù)中的最大值。若主函數(shù)根據(jù)需要調(diào)用了該函數(shù),自然希望能將求得的結(jié)果反饋回來。在C語言中,可以在被調(diào)函數(shù)內(nèi)采用return語句獲得函數(shù)的返回值。一個函數(shù)利用return語句只能返回一個值。return語句的格式為

return(表達式);

或return表達式;

從前面介紹的有參函數(shù)定義格式可知,函數(shù)名前面的函數(shù)類型說明符是用來指定該函數(shù)返回值的數(shù)據(jù)類型。例如:

4.5.3函數(shù)調(diào)用

函數(shù)調(diào)用的一般方法為:

函數(shù)名(實參列表);

或函數(shù)名();

前者用于有參函數(shù),若實參列表包含了兩個以上實參時,各參數(shù)之間用逗號分隔。實參的個數(shù)應(yīng)與形參的個數(shù)相同,且按順序?qū)?yīng)的參數(shù)類型應(yīng)一致(或兼容);后者用于無參函數(shù)的調(diào)用。注意,括號不能省略。

在程序中,從函數(shù)調(diào)用可能出現(xiàn)的位置這個角度來看,函數(shù)調(diào)用大致可分為以下幾種形式:

(1)以語句的形式進行函數(shù)調(diào)用,例如:

puts(str1);/*上一章介紹的字符串輸出函數(shù),是系統(tǒng)提供的標準函數(shù)之一*/

swap(x1,x2);/*調(diào)用用戶自定義的有參函數(shù)swap*/

printstr();/*調(diào)用用戶自定義的無參函數(shù)printstr*/

以語句的形式進行函數(shù)調(diào)用一般不需要返回值,只是通過函數(shù)調(diào)用完成某些操作。

(2)以表達式的形式進行函數(shù)調(diào)用,例如:

if(strcmp(s1,s2)>0)…/*函數(shù)調(diào)用位于條件式中*/

n_max=max(x,y,z);/*函數(shù)調(diào)用位于賦值語句右側(cè)的表達式中*/

for(j=strlen(str)-1;j>0;j--)/*函數(shù)調(diào)用位于循環(huán)語句的表達式中*/

以表達式的形式進行函數(shù)調(diào)用,被調(diào)用函數(shù)必須返回一個函數(shù)值,以便參加主調(diào)函數(shù)的相關(guān)計算或后續(xù)操作。如上面第一條語句,字符串的比較函數(shù)必須返回一個函數(shù)值以便進行大于0的比較,下面兩條語句中,相應(yīng)的函數(shù)必須返回一個函數(shù)值以便進行賦值操作。

(3)以函數(shù)的參數(shù)形式進行函數(shù)調(diào)用,例如:

printf("%d\n",max(x,y,z));/*max函數(shù)是printf函數(shù)的參數(shù)部分*/

fun1(fun2(t));/*fun2函數(shù)是fun1函數(shù)的實參*/

4.5.4函數(shù)的聲明

用戶函數(shù)(即自定義函數(shù))一般應(yīng)定義在前,調(diào)用在后。如果用戶在編制程序時都按這個規(guī)律來進行,則不需要進行函數(shù)的聲明(或者說,函數(shù)的聲明可以省略)。但從另一個角度來看,由于C語言中的函數(shù)定義是各自獨立的。函數(shù)與函數(shù)之間的排放位置并沒有先后順序關(guān)系,只有調(diào)用與被調(diào)用的關(guān)系,也就是說,在一個含有多個函數(shù)的源程序中,各個函數(shù)的放置(即先后位置)是隨機的。

所謂“函數(shù)聲明”是指向C編譯系統(tǒng)提供有關(guān)信息,如函數(shù)值的類型、函數(shù)名及函數(shù)的參數(shù)個數(shù)等,以便C編譯系統(tǒng)對函數(shù)調(diào)用時進行核查。函數(shù)聲明的一般格式為

函數(shù)類型函數(shù)名(參數(shù)類型1,參數(shù)類型2,…);

或函數(shù)類型函數(shù)名(參數(shù)類型1參數(shù)名1,參數(shù)類型2參數(shù)名2,…);

4.6數(shù)?組?和?指?針

4.6.1數(shù)組1.數(shù)組數(shù)組是一種最簡單實用的數(shù)據(jù)結(jié)構(gòu)。所謂數(shù)據(jù)結(jié)構(gòu),就是將多個變量(數(shù)據(jù))人為地組成一定的結(jié)構(gòu),以便于處理大批量、相對有一定內(nèi)在聯(lián)系的數(shù)據(jù)。

2.數(shù)組單元

在同一數(shù)組中,構(gòu)成該數(shù)組的成員稱為數(shù)組單元(或數(shù)組元素、下標變量)。數(shù)組里面的每一個數(shù)據(jù)用數(shù)組單元名來標識。在C語言中,引用數(shù)組中的某一單元,要指出數(shù)組名和用括號括起來的表示數(shù)組單元在數(shù)組中的位置(順序號)的下標,因此數(shù)組單元又稱帶下標的變量,簡稱下標變量。例如:

3.數(shù)組的維數(shù)

下標變量中下標的個數(shù)稱為數(shù)組的維數(shù)。

如果數(shù)組中的所有元素能按行或列順序排成一行,也就是說,用一個下標便可以確定它們各自所處的位置,這樣的數(shù)組稱為一維數(shù)組,因此具有一個下標的下標變量構(gòu)成一維數(shù)組。

一般來講,數(shù)組元素下標的個數(shù)就是該數(shù)組的維數(shù);反之,一個數(shù)組的維數(shù)一經(jīng)確定,那么它的元素下標的個數(shù)也就隨之確定了。例如:

4.一維數(shù)組的定義、引用和初始化

例如:

對一維數(shù)組的使用有以下幾點說明:

(1)定義一個數(shù)組時,數(shù)組名是標識符,命名規(guī)則同標識符命名規(guī)則相同。

(2)數(shù)組的類型,即數(shù)組元素的類型,可以是基本類型(整型、實型和字符型等),也可以是指針類型、結(jié)構(gòu)體類型或共用體類型。

(3)定義數(shù)組時,必須使用下標常量表達式,可以是常數(shù)或符號常量,但是不能是變量。

(4)如果定義多個相同類型的數(shù)組,則可以使用逗號隔開,例如:

(5)?C編譯器在進行編譯時,為數(shù)組連續(xù)分配地址空間,分配空間的大小為:數(shù)組元素占用的字節(jié)數(shù)×數(shù)組長度。

(6)一定要注意數(shù)組名表示數(shù)組第一個元素a[0]的地址,也就是數(shù)組的首地址。

使用數(shù)組必須先定義,后引用。C語言規(guī)定,不能引用整個數(shù)組,只能逐個引用元素。元素引用的方式為

數(shù)組名[下標]

下標可以是整型常量或整型表達式,例如:

在引用時應(yīng)注意以下幾點:

(1)由于數(shù)組元素本身等價于同一類型的一個變量,因此,對變量的任何操作都適用于數(shù)組元素。

(2)在引用數(shù)組元素時,下標可以是整型常數(shù)或表達式,表達式內(nèi)允許變量存在。在定義數(shù)組時,下標不能使用變量。

(3)引用數(shù)組元素時下標最大值不能出界,也就是說,若數(shù)組長度為n,下標的最大值為n-1;若出界,C編譯時并不給出錯誤提示信息,程序仍能運行,但破壞了數(shù)組以外其他變量的值,可能會造成嚴重的后果,因此必須注意數(shù)組邊界的檢查。

數(shù)組的初始化是指在定義數(shù)組時給全部數(shù)組元素或部分數(shù)組元素賦值。一維數(shù)組的初始化有以下三種形式:

(1)數(shù)組初始化形式一。

(2)數(shù)組初始化形式二。

(3)數(shù)組大小的定義。

5.二維數(shù)組的定義、引用和初始化

定義二維數(shù)組的一般格式為

類型標識符數(shù)組名[常量表達式1][常量表達式2];

例如:

inta[3][4];

定義了一個整型二維數(shù)組a,共有3*4=12個元素,可以稱為3行4列的數(shù)組。

對于以上定義的數(shù)組有以下幾點說明,這些說明同樣適合其他二維數(shù)組。

(1)二維數(shù)組中每個數(shù)組元素必須有兩個下標,常量表達式的值即為下標的值,與一維數(shù)組要求一樣,其下標只能是正整數(shù),并且從0開始。

(2)可以將二維數(shù)組元素排列成一個矩陣,用二維數(shù)組的第1個下標表示數(shù)組元素所在的行,第2個下標表示所在的列,例如:

(3)在C語言中,二維數(shù)組中元素存放的順序是:按行存放,即在內(nèi)存中先順序存放第一行的元素,再存放第二行的元素。例如,數(shù)組a[3][4]的存放順序是:a[0][0]、a[0][1]、a[0][2]、a[0][3]、a[1][0]、a[1][1]、a[1][2]、a[1][3]、a[2][0]、a[2][1]、a[2][2]、a[2][3]。

(4)二維數(shù)組可看成一個一維數(shù)組,其中的每一個元素又是一個一維數(shù)組。例如,數(shù)組a[3][4]可以看成是一個一維數(shù)組,它有3個元素a[0]、a[1]、a[2],每一個元素又是一個包括4個元素的一維數(shù)組,如元素a[0]有4個元素a[0][0]、a[0][1]、a[0][2]、a[0][3]。即

數(shù)組名a表示數(shù)組第一個元素a[0][0]的地址,也就是數(shù)組的首地址。a[0]也表示地址,表示第0行的首地址,即a[0][0]的地址;a[1]表示第1行的首地址,即a[1][0]的地址;a[2]表示第2行的首地址,即a[2][0]的地址。因此可以得到下面的關(guān)系:

其中,&是取地址運算符,&a[0][0]表示取元素a[0][0]的地址

二維數(shù)組中各個元素可看作具有相同數(shù)據(jù)類型的一組變量,因此對變量的引用及一切操作同樣適用于二維數(shù)組元素。二維數(shù)組元素引用的格式為

數(shù)組名[下標][下標]

說明:

(1)下標可以是整型常量或整型表達式。

(2)二維數(shù)組的引用和一維數(shù)組的引用類似,要注意下標取值不要超過數(shù)組的范圍。

例如,下面的語句均是正確的二維數(shù)組引用格式:

在定義二維數(shù)組的同時,可使用以下四種方法對二維數(shù)組進行初始化:

(1)將所有數(shù)據(jù)寫在一個大括號內(nèi),以逗號分隔,按數(shù)組元素在內(nèi)存中的排列順序?qū)ζ滟x值,例如:

inta[2][3]={0,1,2,3,4,5};

(2)分行對數(shù)組元素賦值,例如:

inta[2][3]={{0,1,2},{4,5,6}};

這種賦值方法比較直觀,把第1個大括弧中的數(shù)據(jù)賦給二維數(shù)組的第0行,把第2個大括弧中的數(shù)據(jù)賦給二維數(shù)組的第1行,依次類推。賦值結(jié)果同上。

(3)對部分元素賦值,例如:

inta[2][3]={{1},{4}};

執(zhí)行后對各行的第一個元素賦初值,其余元素均賦值為0,即將1賦值給a[0][0],將4賦值給a[1][0],數(shù)組的其他元素賦值為0,這種賦值方式比較直觀。

(4)如果對全部元素賦初值,則第一維的長度可以不指定,但必須指定第二維的長度,例如:

4.6.2指針

1.指針的基本概念

指針是C語言最靈活的部分,它充分體現(xiàn)了C語言簡潔、緊湊、高效等重要特色,可以說,沒掌握指針就沒掌握C語言的精華。

指針之所以難學(xué)是因為它與內(nèi)存有著密切的聯(lián)系,簡單的說,指針就是內(nèi)存地址。這里首先要區(qū)分三個比較接近的概念:名稱、內(nèi)容(值)和地址。名稱是給內(nèi)存空間取的一個容易記憶的名字;內(nèi)存中每個字節(jié)都有一個編號,就是地址;在地址所對應(yīng)的內(nèi)存單元中存放的數(shù)值即為內(nèi)容或值。

2.指針變量

(1)指針變量的定義。

基類型*變量名

示例:

說明:

①C語言規(guī)定所有變量必須先定義后使用,指針變量也不例外,為了表示指針變量是存放地址的特殊變量,定義變量時在變量名前加指向符號“*”。

②定義指針變量時,不僅要定義指針變量名,還必須指出指針變量所指向的變量的類型即基類型,或者說,一個指針變量只能指向同一數(shù)據(jù)類型的變量。

③示例第一行定義了兩個指向整型數(shù)據(jù)的指針變量pointer1、pointer2,第二行定義了指向?qū)嵭蛿?shù)據(jù)的指針變量f,第三行定義了指定字符型數(shù)據(jù)的指針變量pc。

(2)指針變量的賦值。

指針變量指向某個變量的方法是將被指變量的地址賦值給該指針變量,這里就要用到取址運算符“&”,例如:

上述命令的執(zhí)行將使指針變量p指向變量i。

(3)指針變量的引用。

【例4-2】通過指針變量訪問整型變量。

程序說明:

①int*pi,*pj;語句定義了變量pi、pj是指向整型變量的指針變量,但沒指定它們指向哪個具體變量。

②pi=&i;pj=&j;語句確定了pi、pj的具體指向,pi指向i,pj指向j。不能誤寫成:*pi=&i,*pj=&j;

③printf("%d,%d\n",i,j);語句通過變量名直接訪問變量的方法,這是我們最常用的手段。

④printf("%d,%d",*pi,*pj);語句通過指向變量i、j的指針變量來訪問變量i、j,*pi表示變量pi所指向的單元的內(nèi)容,即i的值;*pj表示變量pj所指向的單元的內(nèi)容,即j的值,因而兩個printf語句輸出的結(jié)果均為變量i、j所對應(yīng)的值。

需要明確的是這里的*是對變量pi、pj所指向單元的值的引用;而int*pi,*pj;語句處pi、pj沒有具體的指向,*定義了pi、pj屬于指針變量,而非間址運算符。

(4)“*”與“&”運算符的進一步說明。

①如果已執(zhí)行了“pointer1=&a;”語句,則&*pointer1的值是&a。因為“*”與“&”運算符的優(yōu)先級相同,并且是自右向左結(jié)合,所以先進行*pointer1的運算,得到變量a,再進行&運算得到的值為變量a的地址。

②如果已執(zhí)行了“a=100;”語句,則*&a的值是100。因為先進行&a運算得到a的地址,再進行*運算,得到a地址的內(nèi)容100。

③指針加1,不是純加1,而是加一個所指變量的字節(jié)個數(shù),例如:

3.數(shù)組與指針

(1)指向數(shù)組的指針。

如果一個變量中存放了數(shù)組的起始地址,那么該變量稱為指向數(shù)組的指針變量,指向數(shù)組的指針變量的定義遵循一般指針變量定義規(guī)則,它的賦值與一般指針變量的賦值相同。如有以下定義:

(2)通過指針引用數(shù)組元素。

若指向數(shù)組的指針后,數(shù)組中各元素的起始地址可以通過起始地址加相對值的方式來獲得,從而增加了訪問數(shù)組元素的渠道。

C語言規(guī)定,如果指針變量p指向數(shù)組中的一個元素,則p+1指向同一數(shù)組中的下一個元素(而不是簡單地將p的值加1),如果數(shù)組元素類型是整型,每個元素占2個字節(jié),則p+1意味著將p的值加2,使它指向下一個元素,因此p+1所代表的地址實際上是p+1*d,d是一個數(shù)組元素所占的字節(jié)數(shù)(對整型數(shù)組,d=2;對實型數(shù)組,d=4;對字符型數(shù)組,d=1)。

①地址表示法

當p定義為指向a數(shù)組的指針變量后,就會產(chǎn)生對同一地址不同的表示方法。例如,數(shù)組元素a[5]的地址有三種不同的表示形式:

②訪問表示法

與地址表示法相對應(yīng),訪問數(shù)組元素也有多種表示法。例如,數(shù)組元素a[5]可通過下列三種形式訪問:

③指針變量帶下標

指向數(shù)組的指針變量可以帶下標,如p[5]與*(p+5)等價。

④指針變量與數(shù)組名的引用區(qū)別

指針變量可以取代數(shù)組名進行操作,數(shù)組名表示數(shù)組的首地址,屬于常量,它不能取代指針變量進行操作。例如,設(shè)p為指向數(shù)組a的指針變量,p++可以,但a++不行。

⑤++與+i不等價

用指針變量對數(shù)組逐個訪問時,一般有兩種方式,*(p++)或*(p+i),表面上這兩種方式?jīng)]多大區(qū)別,但實際上有很大差異,像p++不必每次都重新計算地址,這種自加操作比較快,能大大提高

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論