新手上路 C語言教程_第1頁
新手上路 C語言教程_第2頁
新手上路 C語言教程_第3頁
新手上路 C語言教程_第4頁
新手上路 C語言教程_第5頁
已閱讀5頁,還剩73頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、本文包括:1. 1. 引言 2. 2. 什么是C語言? 3. 3. 最簡單的C程序 4. 4. C程序編譯過程解析 5. 5. 變量:程序保存結(jié)果的手段 6. 6. Printf 7. 7. Printf:讀取用戶輸入 8. 8. Scanf 9. 9. if語句和while循環(huán) 10. 10. 示例:編寫能夠打印華氏-攝氏溫度轉(zhuǎn)換表的程序 11. 11. 數(shù)組12. 12. 

2、更多變量知識 13. 13. 函數(shù) 14. 14. 函數(shù)原型 15. 15. 函數(shù)庫 16. 16. 創(chuàng)建一個函數(shù)庫17. 17. makefile 18. 18. 文本文件 19. 19. 打開文本文件 20. 20. 讀取文本文件 21. 21. 指針22. 22. 為什么要用指針? 23. 23. 指針基礎(chǔ) 24. 24. 內(nèi)存地址 25. 25. 指

3、向同一地址 26. 26. 指針常見錯誤 27. 27. 指針作為函數(shù)參數(shù) 28. 28. 動態(tài)數(shù)據(jù)結(jié)構(gòu) 29. 29. 計算機(jī)中的棧和堆30. 30. malloc函數(shù)和free函數(shù) 31. 31. 指針進(jìn)階 32. 32. 指向結(jié)構(gòu)體的指針 33. 33. 指向指針的指針 34. 34. 鏈表?xiàng)?#160;35. 35. 用指針操作數(shù)組 36. 36. 字符串 37. 37.

4、0;字符串須知 38. 38. 運(yùn)算符優(yōu)先級 39. 39. 命令行參數(shù) 40. 40. 二進(jìn)制文件 41. 41. 了解更多信息 42. 42. 閱讀所有軟件類文章C語言是一種廣受歡迎且用途廣泛的程序設(shè)計語言。人們使用它編寫計算機(jī)程序。因?yàn)镃功能強(qiáng)、效率高,所以全世界的程序員都喜歡用它。如果您是一名程序員,或者希望成為一名程序員的話,那么學(xué)習(xí)C語言會使您受益匪淺:C語言入門教程· 您將可以在許多平臺上閱讀和編寫程序。小到微控制器,大到最先進(jìn)的科研系統(tǒng),到處都是C語言的用武之地。許多現(xiàn)

5、代操作系統(tǒng)也是用C語言編寫的。· 學(xué)習(xí)過C語言后,再進(jìn)階的面向?qū)ο驝+語言就容易多了。C+是對C的擴(kuò)展。不先掌握C語言而直接學(xué)習(xí)C+是非常困難的。本文中,我們將會循序漸進(jìn)地完整介紹C語言,并教會您怎樣從零起步成為一名C程序員。一旦您掌握了C語言,您一定會對自己可以做的事情感到吃驚的!C是一種計算機(jī)編程語言。就是說可以用C編寫指令清單交給計算機(jī)去執(zhí)行。C是當(dāng)前正在使用的成千上萬種編程語言之一。它已經(jīng)有幾十年的歷史了。因?yàn)樗δ軓?qiáng)大而且效率很高,所以受到了程序員們廣泛的歡迎。C還是一種容易學(xué)習(xí)的語言。和其他一些語言相比,C的風(fēng)格稍有點(diǎn)古怪,但您會很快適應(yīng)的。HSWC語言編譯器C 是所謂的

6、編譯型語言,意思是說您寫好的源程序必須通過C編譯器來運(yùn)行,使它變成可以在計算機(jī)上運(yùn)行(執(zhí)行)的可執(zhí)行文件。C源程序是供人閱讀的,而編譯器產(chǎn)生的可執(zhí)行程序是供計算機(jī)讀入和執(zhí)行的。也就是說,要編寫并運(yùn)行一個C程序,您必須借助于C編譯器。如果使用UNIX系統(tǒng)(例如,您在UNIX主機(jī)上用C編寫CGI腳本,或者您是學(xué)生,在實(shí)驗(yàn)室的UNIX機(jī)器上工作),C編譯器是免費(fèi)提供的。它的名字是cc或者gcc,可以通過命令行調(diào)用。您如果是學(xué)生,那么學(xué)校很可能會向您提供編譯器。您只要查一下學(xué)校提供什么樣的編譯器并學(xué)習(xí)使用即可。如果您是在家使用Windows操作系統(tǒng)的計算機(jī),則需要下載免費(fèi)的C編譯器或是購買商業(yè)的C編譯

7、器。微軟公司的Visual C+是一套廣泛使用的商業(yè)編譯環(huán)境,可以編譯C和C+程序??上н@套軟件要花費(fèi)幾百美元。如果不想花那么多錢購買商業(yè)編譯器的話,那么您可以在網(wǎng)上挑選一款免費(fèi)的編譯器。如果您想找的話,不妨從我們會從一個極其簡單的C語言程序?yàn)槔_始,循序漸進(jìn)。在這個例子中,我假定您使用的是UNIX命令行,并以gcc作為您的開發(fā)環(huán)境。如果您使用的并不是這些,所有的代碼依然可以正常運(yùn)行您只是需要使用其他可用的編譯器,才能理解這些代碼。讓我們從一個最簡單的C程序開始,了解一下C的基本要素和編譯過程。將下面的程序錄入一個標(biāo)準(zhǔn)的文本編輯器(UNIX上用vi或emacs、Windows上用Notepad

8、、Macintosh上用TeachText),然后以samp.c的文件名保存。文件名如果沒有.c結(jié)尾,編譯的時候就很可能會出現(xiàn)一些錯誤,所以要確保文件名以.c結(jié)尾。另外,請確保您的編輯器不會自動在文件名末尾添加后綴(如.txt)。下面是我們的第一個程序:#include int main()printf(" 這是我第一個程序的輸出!n");return 0;執(zhí)行時,程序使計算機(jī)輸出“這是我第一個程序的輸出!”,之后便退出了。真是簡單到不能再簡單了!書寫位置錄入本程序時,注意將#include中的“#”放在第一列,即最左側(cè)。其他行的間距和縮進(jìn)可隨個人喜好選擇。某些U

9、NIX系統(tǒng)上有一個叫cb的C程序美化器,它可以為您美化代碼格式。上例程序代碼的空格和縮進(jìn)風(fēng)格可作為格式的范例。請按下面步驟編譯本程序:· 在 UNIX 系統(tǒng)上,鍵入gcc samp.c -o samp(若gcc不能用就用cc)。此命令行的作用是調(diào)用名為gcc的C編譯器來編譯samp.c,并將生成的可執(zhí)行文件命名為samp。要運(yùn)行編譯好的程序,請鍵入samp(有些 UNIX 系統(tǒng)上要鍵入./samp)。· 在使用在使用DJGPP的DOS和Windows電腦上,請?jiān)贛S-DOS命令中鍵入gcc samp.c -o samp.exe。這條命令會調(diào)用名叫g(shù)cc的C編譯器,使它編譯s

10、amp.c,并生成一個可執(zhí)行文件samp.exe。要運(yùn)行程序,只需鍵入samp。· 如果您使用的是其他編譯器或其他開發(fā)系統(tǒng),閱讀并遵循該編譯器的指南。當(dāng)您運(yùn)行這個程序后,您應(yīng)該會看到“這是我第一個程序的輸出!”的打印了。當(dāng)您編譯這個程序時,到底發(fā)生了什么?下面是示意圖:HSWC語言編譯器如果您鍵入程序時打錯了,它要么不會編譯,要么不會運(yùn)行。如果程序沒有編譯,或者沒有正確地運(yùn)行,請重新編輯,檢查輸入的時候是否有誤。然后修正錯誤,重新編譯。讓我們逐行講解一下這個示例程序,看看每一行都做了什么(點(diǎn)擊這里在新窗口中打開程序):· 程序以#include 開始。這一行將“標(biāo)

11、準(zhǔn)輸入輸出庫(Standard I/O library)”包括進(jìn)程序之中。使用標(biāo)準(zhǔn)輸入輸出庫您可以完成諸如從鍵盤(稱為“標(biāo)準(zhǔn)輸入”)讀入數(shù)據(jù)、向屏幕(稱為“標(biāo)準(zhǔn)輸出”)寫出數(shù)據(jù)、處理磁盤上的文本文件之類的工作。這是一個極有用的函數(shù)庫。C擁有大量像stdio一樣的函數(shù)庫,包括字符串、時間和數(shù)學(xué)函數(shù)庫等。函數(shù)庫就是一個別人寫好供我們調(diào)用的代碼包,它使我們編程變得更加容易(我們在后面討論函數(shù)庫)。· int main()這行聲明了主函數(shù)。所有的C程序都必須包含一個名為main的函數(shù)。我們稍后將學(xué)習(xí)更多關(guān)于函數(shù)的知識。程序從主函數(shù)的第一行開始運(yùn)行。· C語言使用花括號( 

12、和 )標(biāo)識一個代碼塊的開始和結(jié)束。本例中構(gòu)成主函數(shù)的代碼塊包括兩行。· printf語句將輸出的內(nèi)容送往標(biāo)準(zhǔn)輸出設(shè)備(對我們而言就是屏幕)。引號中的部分叫做格式字符串,用于表示數(shù)據(jù)輸出時的格式。格式字符串可以包含文字(“這是我第一個程序的輸出!”)、回車換行符(n)和標(biāo)識變量位置的操作符等。如果您使用的是UNIX系統(tǒng),可以鍵入man 3 printf獲得printf函數(shù)的完整說明文檔。其他系統(tǒng)下您可以通過閱讀編譯器相關(guān)的文檔來了解printf函數(shù)的細(xì)節(jié)。· return 0;這行使主函數(shù)向運(yùn)行它的命令行解釋器返回錯誤代碼0(表示沒有錯誤)。稍后我們還會繼續(xù)介紹這一

13、特性。作為程序員,您的程序常常需要“記住”某個數(shù)值。比如您的程序要求用戶輸入一個數(shù),或者它計算出了一個結(jié)果,您需要把它保存在某處供以后使用。程序是靠使用變量來保存結(jié)果的。例如:int b;上面這行的意思是說:“我想創(chuàng)建一個可以容納一個整數(shù)的存儲空間,名字叫做b?!泵總€變量都有名字(本例中是b)和類型(本例中是int,表示整型)。您可以用如下語句在b中存儲一個值:b=5;您可以用如下語句使用 b 中保存的值:printf("%d", b);C 語言提供了幾種標(biāo)準(zhǔn)的變量類型:· int - 整型,用于保存整數(shù)值· float - 用于保存

14、浮點(diǎn)值· char - 用于保存單個字符值,如“m”或“Z”后面我們會看到整型以外其他類型的例子。 printf語句將要輸出的內(nèi)容送往標(biāo)準(zhǔn)輸出設(shè)備。對我們而言,標(biāo)準(zhǔn)輸出設(shè)備一般就是計算機(jī)屏幕(雖然您也可以將標(biāo)準(zhǔn)輸出重定向到一個文本文件或另一個命令)。下面這個程序?qū)⒂兄谀钊肜斫鈖rintf:#include int main()int a, b, c;a=5;b=7;c=a+b;printf("%d+%d=%dn", a, b, c);return 0;請錄入程序并保存,文件名是add.c。在命令行鍵入gcc add.c -o ad

15、d進(jìn)行編譯,之后再鍵入add(或./add)運(yùn)行程序。您會看到輸出:“5+7=12”。下面是該程序各行的解釋:· int a, b, c; 這行聲明了三個分別名為a、b和c的整型變量。整型變量用于保存整數(shù)。· 下一行將變量a的值初始化為5。· 再下一行將變量b的值初始化為7。· 再下一行將a和b相加,并將結(jié)果“賦值”給c。計算機(jī)將a中的值(5) 和b中的值(7) 相加得到結(jié)果12,并把新值(12) 存入變量c。變量c被賦值12。因此,本行中的“=”稱為“賦值運(yùn)算符”。· 接下來printf語句會打印“5+7=12”。占位符%d的作用是

16、為輸出值占位。本行有三個%d占位符,末尾有三個變量名:a、b和c。C語言將第一個%d和a匹配并替換為5;將第二個%d和b匹配并替換為7;將第三個%d和c匹配并替換為12。然后在屏幕上打印替換結(jié)果:“5+7=12”。+、=及空格作為格式字符串的一部分,按程序員指定的順序自動插入到%d運(yùn)算符之間。前面的程序很好,但要是如果能從用戶那里讀入值5和7而不是使用固定的值的話,那就更好了??梢愿臑橄旅娴某绦颍?include int main() int a, b, c; printf("輸入第一個值:"); scanf("%d", printf("輸入第

17、二個值:"); scanf("%d", c = a + b; printf("%d + %d = %dn", a, b, c); return 0;以下是程序的執(zhí)行過程:HSWC語言執(zhí)行程序示例請按照上例修改原來的程序,然后重新編譯和執(zhí)行并確保它能正常工作。注意scanf和printf都要使用格式字符串(可以鍵入man scanf獲取更多信息)。還要注意a和b前面都有一個“&”。這是C語言中的取地址運(yùn)算符,它會返回變數(shù)的地址(在我們討論指針之前,這個符號沒什么用)。在對單個字符,整數(shù),或者浮點(diǎn)數(shù)形式的任何變量做標(biāo)準(zhǔn)輸入,以及對結(jié)構(gòu)形式(

18、我們很快就會接觸到)的任何變量做標(biāo)準(zhǔn)輸入時,您都必須使用&運(yùn)算符。如果您遺漏了&運(yùn)算符,您在運(yùn)行程序時會報錯。您可以試試,這樣就能看到這種運(yùn)行錯誤是什么樣子。讓我們通過一些變量來完全理解printf。這是最簡單的printf聲明:printf("您好");它的格式字符串告訴printf把“您好”二字發(fā)送到標(biāo)準(zhǔn)輸出。對比:printf("您好n");兩者的區(qū)別是后者在“您好”后跟一個回車換行,一起送到標(biāo)準(zhǔn)輸出。下面這行顯示了如何使用printf輸出一個變量的值。printf("%d", b)%d是占位符,會在printf

19、語句執(zhí)行時替換為變量b的值。通常您需要把輸出值嵌入到一些文字之中。一種方法是這樣:printf("溫度是");printf("%d", b);printf(" 度n");更簡單的方法是這樣寫:printf("溫度是 %d 度n", b);一個printf語句中可以使用多個%d占位符:printf("%d + %d = %dn", a, b, c);在printf語句中,格式字符串包含的操作符數(shù)目和后面的變量的數(shù)目和類型一定要一致,這一點(diǎn)極為重要。例如,如果格式字符串包含有三個%d操作符,那么格式

20、字符串后面必須緊接正好三個參數(shù),且參數(shù)的類型和先后順序必須和操作符指定的是一樣的。使用不同形式的占位符,printf可以打印所有的C標(biāo)準(zhǔn)類型:· int(整數(shù))用%d· float(浮點(diǎn)數(shù))用%f· char(單個字符)用%c· 字符串(字符數(shù)組,見后面討論)用%s在UNIX機(jī)器上要了解printf的更多細(xì)節(jié),可以鍵入man 3 printf。如果使用任何其他C編譯器,則您很可能在其附帶手冊或幫助文件中找到對printf的說明。 使用scanf函數(shù)可以從標(biāo)準(zhǔn)輸入設(shè)備接受輸入。對我們而言,標(biāo)準(zhǔn)輸入設(shè)備一般就是鍵盤。雖然scanf函數(shù)可以做許多事情

21、,但是除了最簡單的工作外,一般而言并不很可靠。原因是它不能很好地處理人為錯誤。不過,對于簡單的程序來說,scanf還是很合適的,而且易于使用。scanf的最簡單用法是像這樣: scanf("%d", &b);該程序?qū)⒆x取用戶從鍵盤輸入的一個整數(shù)(和在printf中一樣,%d代表整型,因此b必須聲明為int),并將其存入b。scanf函數(shù)使用的占位符和printf的相同:· int用%d· float用%f· char用%c· 字符串(后面會討論)用%s在使用scanf時,您必須在其變量前加上&。為什么要這么做的原因,在

22、您學(xué)習(xí)指針后會很清楚。&符號很容易忽略,而一旦您忘記添加&,幾乎每次運(yùn)行程序都會崩潰。通常來說,最好像在這里舉的例子一樣使用scanf函數(shù)讀取鍵盤輸入的單個數(shù)值。讀取多個數(shù)值的時候,請多次調(diào)用scanf函數(shù)。不過,在任何一個實(shí)際的(而不是用來演示的)程序中,您將不會使用scan函數(shù),而是使用gets或者fgets函數(shù)來一次一整行地閱讀文本。然后您會分析這一行,并讀取它的值。這么做的原因是,您可以檢測到輸入的錯誤,并做恰當(dāng)?shù)奶幚?。要完全理解printf和scanf函數(shù),需要一些練習(xí)。一旦掌握了,它們非常有用。試試這個!· 修改這個程序,使它能接受3個數(shù)值,而不是2個,并

23、把3個數(shù)值相加。#include int main() int a, b, c; printf("輸入第一個值:"); scanf("%d", &a); printf("輸入第二個值:"); scanf("%d", &b); c = a + b; printf("%d + %d = %dn", a, b, c); return 0;· 試著在上述程序中隨意刪除或添加字符或者詞語,看編譯器對這些錯誤如何反應(yīng)。比如說,在上述程序的第一行刪除b變量,看看當(dāng)您忘記了聲明變量時,

24、編譯器會怎么辦。刪除一個分號,看會發(fā)生什么?;蛘呗┑粢话氪罄ㄌ?。刪掉主函數(shù)旁邊的一個圓括號。嘗試每一種錯誤,然后通過編譯器運(yùn)行程序,看會發(fā)生什么。通過模擬這些錯誤,您會了解不同種類的編譯器錯誤,并在當(dāng)您真正地犯了這些錯誤的時候,更容易找到這些輸入錯誤。C常見錯誤· 用錯大小寫。C語言區(qū)分大小寫,因此Printf和PRINTF都不對,必須是printf。· 在scanf中忘了使用&。· 在printf或scanf的格式聲明中參數(shù)太多,或者太少。· 在使用變量的時候沒有事先聲明。C語言中,if語句和while循環(huán)都會用到布爾表達(dá)式。下面是一個使用if

25、語句的簡單例子:#include int main()int b;printf("輸入一個值:");scanf("%d", &b);if (b < 0)printf("值為負(fù)數(shù)n");return 0;程序從用戶讀入一個數(shù)字,然后用if語句測試這個數(shù)字是否小于零。如果小于零則打印一條消息,否則什么也不做。程序中的(b<0)稱為布爾表達(dá)式。C需要求出此表達(dá)式的值才能決定是否打印后面的消息。如果布爾表達(dá)式的結(jié)果是真,那么C將執(zhí)行緊接在if語句后面的一行代碼(或花括號中的代碼塊);如果布爾表達(dá)式的結(jié)果是假,那么

26、C將跳過緊接在if語句后面的代碼行或代碼塊。下面是一個稍復(fù)雜一點(diǎn)的例子:#includeint main()int b;printf("輸入一個值:");scanf("%d", &b);if (b < 0)printf("值為負(fù)數(shù)n");else if (b = 0)printf("值為0n");elseprintf("值為正數(shù)n");return 0;這個例子中的else if和else部分處理了值為零或?yàn)檎那闆r。下面是一個更復(fù)雜一些的布爾表達(dá)式:if (x=y) &&

27、amp; (j>k)z=1;elseq=10;上面這個if語句的意思是:“如果變量x和y的值相等,而且變量j的值大于k的值,那么令變量z的值等于1,否則令變量q的值等于10?!痹贑程序中,您經(jīng)常使用類似這樣的if語句進(jìn)行判斷。一般而言,大多數(shù)判斷都很簡單,像第一個例子。但偶爾也會遇到復(fù)雜一些的情況。請注意,C使用=判斷相等,而用=為變量賦值。&&在C中代表布爾操作符與。這是C語言中的所有的布爾操作符:等于 =小于 <大于 >小于等于 <=大于等于 >=不等于 !=與 &&或 |非 !您會發(fā)現(xiàn),while聲明和if聲明使用起來一樣簡單

28、。舉個例子:while (a < b)printf("%dn", a);a = a + 1;這會反復(fù)運(yùn)行大括號中間的兩行語句,直到a大于或等于b。大體來說,while聲明是這樣工作的:C還提供一種do-while結(jié)構(gòu):doprintf("%dn", a);a = a + 1;while (a < b);C中的for循環(huán)只不過是while語句的精簡寫法。例如,您有如下C代碼:x=1;while (x<10)x+; 您可以用for循環(huán)改寫成下面這樣:for(x=1; x<10; x+)請注意,while循環(huán)實(shí)際包括了三個步驟

29、:初始化(x=1)、判斷(x<10)和增量(x+)。使用for循環(huán)可以把三個步驟寫在同一行中,但并不限制三個部分的具體內(nèi)容。例如,您有如下C代碼:a=1;b=6;while (a < b)a+;printf("%dn",a);用for循環(huán)就可以寫為:for (a=1,b=6; a < b; a+,printf("%dn",a);這樣雖然有點(diǎn)不易讀懂,但還是允許的。在for循環(huán)的初始化和增量(不包括測試)部分,我們可以使用多條語句并用逗號操作符加以分隔。許多 C 程序員喜歡用一行代碼“濃縮”進(jìn)很多信息。但也有許多人認(rèn)為這樣會使代碼更加難以

30、理解,所以他們選擇分開來寫。布爾表達(dá)式中=和=的對比=符號是C語言的一個常見的“陷阱”,因?yàn)闀r不時會由于疏忽將其寫成=。這個錯誤很容易犯,但對于編譯器來說兩者的含義截然不同。C的布爾表達(dá)式既接受=也接受=,然而程序的執(zhí)行卻大相徑庭。C的布爾表達(dá)式求值的結(jié)果是整數(shù),所以整數(shù)也可以直接作為布爾表達(dá)式使用。C中整數(shù)零代表假,其他任何非零整數(shù)代表真。下面是的C代碼是合法的:#include int main() int a; printf("輸入一個數(shù)字:"); scanf("%d", &a); if (a) printf("值為真n"

31、;); return 0;如果a是任何非零值,printf語句就會執(zhí)行。在C中,諸如if (a=b)這樣的語句的意義是:“將b賦值給a,然后判斷a的布爾值?!比绻鸻變成0,則if語句判斷為假,否則為真。也就是說a的值在判斷過程中改變了。如果您本該寫=的,那么以上行為顯然不是您的本意(盡管正確使用時還可利用這一特性)。所以在使用=和=的時候請格外小心。假設(shè)您要編寫一個能夠打印華氏-攝氏溫度轉(zhuǎn)換表的程序??梢允褂胒or或者while循環(huán)可以輕松實(shí)現(xiàn):#include int main()int a;a=0;while (a <=100)printf("%4d華氏度=%4d

32、攝氏度n",a,(a -32.0)*5.0/9.0);a =a+10;return 0;該程序運(yùn)行后將打印從華氏0度到華氏100度的轉(zhuǎn)換表。輸出如下:0華氏度=-17攝氏度10華氏度=-12攝氏度20華氏度=-6攝氏度30華氏度=-1攝氏度40華氏度=4攝氏度50華氏度=10攝氏度60華氏度=15攝氏度70華氏度=21攝氏度80華氏度=26攝氏度90華氏度=32攝氏度100華氏度=37攝氏度上表中溫度值以10度為間隔遞增。您會發(fā)現(xiàn)通過程序改變表中溫度的起始值、結(jié)束值和遞增值都很容易。如果想讓溫度值更加精確的話,您可以改用浮點(diǎn)數(shù)值:#include int main()flo

33、at a;a = 0;while (a <= 100)printf("%6.2f 華氏度 = %6.2f 攝氏度n",a, (a - 32.0) * 5.0 / 9.0);a = a + 10;return 0;如上例所示,a的聲明改用float,而且在printf語句中用符號%f代替了符號%d。此外,還在符號%f前規(guī)定了一些格式:打印數(shù)值時使用6位整數(shù)和2位小數(shù)。現(xiàn)在我們要修改程序,使它在適當(dāng)?shù)奈恢貌迦?8.6度。即,我們還是每隔10度打印,但是要增加一行98.6華氏度,因?yàn)樗侨梭w的正常體溫。下面的程序會滿足我們的要求:#include int main

34、()float a;a = 0;while (a <= 100)if (a > 98.6)printf("%6.2f 華氏度 = %6.2f 攝氏度n",98.6, (98.6 - 32.0) * 5.0 / 9.0);printf("%6.2f 華氏度 = %6.2f 攝氏度n",a, (a - 32.0) * 5.0 / 9.0);a = a + 10;return 0;結(jié)束值是100時,上面的程序可以正常工作。但如果將結(jié)束值變成200,您就會發(fā)現(xiàn)程序的一處錯誤:打印了太多次98.6度。我們可以用多種方法改正這個錯誤。下面是其中之一:#i

35、ncludeint main()float a, b;a = 0;b = -1;while (a <= 100)if (a > 98.6) && (b < 98.6)printf("%6.2f 華氏度 = %6.2f 攝氏度n",98.6, (98.6 - 32.0) * 5.0 / 9.0);printf("%6.2f 華氏度 = %6.2f 攝氏度n",a, (a - 32.0) * 5.0 / 9.0);b = a;a = a + 10;return 0;動手一試· 嘗試修改華氏-攝氏度轉(zhuǎn)換程序,以使該程

36、序使用scanf接受用戶輸入,作為結(jié)果輸出表格的起始、結(jié)束和增量值。· 為表格制作表頭。· 試用另一種方法解決上例的程序改正的錯誤。· 制作一個英鎊-千克或英里-公里的轉(zhuǎn)換表。C 常見錯誤· 在if或while語句中錯用=代替=。· 忘記在while循環(huán)中增加計數(shù)器的值這會導(dǎo)致無限循環(huán)(永不結(jié)束的循環(huán))。· 不留神在for循環(huán)或if語句末尾加上了分號,使語句起不了作用。例如:for (x=1; x<10; x+);printf("%dn",x);只打印出一個值,因?yàn)閒or語句循環(huán)執(zhí)行的只是它后面的那個分號。&

37、#160;本節(jié)我們將用C寫一個小程序隨機(jī)生成10個數(shù),并對其進(jìn)行排序。我們將使用一種新的變量結(jié)構(gòu):數(shù)組。借助數(shù)組可以聲明并使用一組同類型的數(shù)據(jù)。比如您現(xiàn)在需要創(chuàng)建五個整數(shù)。一種辦法是直接進(jìn)行聲明:int a, b, c, d, e;這當(dāng)然可以,但如果您需要一千個整數(shù)呢?一種更好的辦法是聲明一個包含五個整數(shù)的數(shù)組:int a5;這個數(shù)組中的五個整數(shù)可以分別使用下標(biāo)進(jìn)行訪問。C中所有數(shù)組的下標(biāo)都是從零到n-1。所以int a5;包含了五個元素。例如:int a5;a0 = 12;a1 = 9;a2 = 14;a3 = 5;a4 = 1;使用下標(biāo)訪問數(shù)組帶來的一個好處是可以用循環(huán)來遍歷下標(biāo)。例如,下

38、面的代碼把數(shù)組的所有元素初始化為零:int a5;int i;for (i=0; i<5; i+)ai = 0;下面的代碼將數(shù)組元素按順序初始化,然后打印輸出:#include int main()int a5;int i;for (i=0; i<5; i+)ai = i;for (i=0; i<5; i+)printf("a%d = %dn", i, ai);在C中到處都會用到數(shù)組。下面的代碼是一種使用數(shù)組的常見情形。請打開編輯器并錄入以下代碼:#include #define MAX 10int aMAX;int rand_seed=10;/

39、* 摘自 K&R - 返回0-32767之間一個隨機(jī)數(shù)字。*/int rand() rand_seed = rand_seed * 1103515245 +12345; return (unsigned int)(rand_seed / 65536) % 32768;int main() int i,t,x,y; /* fill array */ for (i=0; i < MAX; i+) ai=rand(); printf("%dn",ai); /* 這里很快會加入新內(nèi)容 */return 0;這段代碼引入了幾個新概念。#define聲明了一個名為MAX的

40、常量并讓它等于10。為在代碼中醒目起見,常量名習(xí)慣上全用大寫字母。int aMAX;這行告訴我們在C中如何聲明整型數(shù)組。注意,數(shù)組聲明出現(xiàn)的位置決定了它是整個程序的全局變量。下面的一行int rand_seed=10也聲明了一個全局變量,名為rand_seed。它在每次程序開始時被初始化為10,作為下面隨機(jī)數(shù)生成代碼的初始種子。實(shí)際中隨機(jī)數(shù)發(fā)生器的種子應(yīng)該以一個隨機(jī)數(shù)作為初值,如系統(tǒng)時間。本例中的rand函數(shù),在每次程序運(yùn)行時都會給出相同的隨機(jī)數(shù)序列。int rand()這行代碼是一個函數(shù)聲明:rand函數(shù)沒有參數(shù)且返回一個整數(shù)。后面我們會學(xué)習(xí)更多關(guān)于函數(shù)的知識。下面的四行是rand函數(shù)的實(shí)現(xiàn)

41、,我們可以暫時忽略。主函數(shù)沒什么特別的。先聲明了四個整型變量,接下來的for循環(huán)用10個隨機(jī)數(shù)填充數(shù)組。注意數(shù)組a包含了10個獨(dú)立的整數(shù)。您可以用方括號指明具體元素。例如a0代表數(shù)組中的第一個整數(shù),a1代表第二個,以此類推。用/*開始并用*/結(jié)束的行稱為注釋。編譯器完全忽略注釋行。您可以把程序說明(自己看或供其他程序員閱讀)放在注釋中。現(xiàn)在請用下面的代碼替換這里很快會加入新內(nèi)容那行注釋:/* 將數(shù)組用冒泡法排序 */for (x=0; x < MAX-1; x+) for (y=0; y < MAX-x-1; y+) if (ay > ay+1) t=ay; ay=ay+1;

42、 ay+1=t; /* 打印排序后的數(shù)組 */printf("-n");for (i=0; i < MAX; i+)printf("%dn",ai);以上代碼將隨機(jī)數(shù)排序,并按順序打印。每次運(yùn)行程序您都會得到同樣的結(jié)果。要想改變參加排序的值,在每次運(yùn)行程序前請改變rand_seed的值。要真正讀懂這段代碼的簡單辦法只有一個,就是“手動”執(zhí)行一下程序。為簡單起見令MAX等于4。準(zhǔn)備一張紙并假設(shè)您自己就是計算機(jī)。在紙上畫出數(shù)組,然后填入四個隨機(jī)、無序的數(shù)字?,F(xiàn)在按照代碼中的排序部分一邊逐行執(zhí)行,一邊在紙上記錄執(zhí)行過程。您會發(fā)現(xiàn)每次執(zhí)行完內(nèi)層循環(huán)后,較大

43、的那些數(shù)被推向數(shù)組尾部,而較小的那些數(shù)則向數(shù)組首部靠攏。動手一試· 在代碼前一部分,試將填充數(shù)組的for循環(huán)縮減為一行代碼。請確保結(jié)果和原來的程序相同。· 將冒泡排序的代碼提出來建立它自己的函數(shù)。函數(shù)頭是void bubble_sort()。然后將冒泡排序使用的變量也移入函數(shù)變成局部變量。因?yàn)閿?shù)組是全局的,所以不需要傳遞參數(shù)。· 改變隨機(jī)數(shù)種子的初始值。C 常見錯誤· C不提供邊界檢查。所以如果您的數(shù)組指標(biāo)越界了,C不會有任何提示。程序會最后崩潰或輸出無意義的數(shù)據(jù)。· 即使不傳遞參數(shù),函數(shù)調(diào)用也要包含()。例如,C接受x=rand;,但這不能完

44、成函數(shù)調(diào)用,而是把rand函數(shù)的內(nèi)存地址賦值給了x。必須寫成x=rand();才行。變量類型C提供三種標(biāo)準(zhǔn)變量類型:· 整數(shù)類型:int· 浮點(diǎn)數(shù)類型:float· 字符類型:charint表示整數(shù),占4個字節(jié);float表示浮點(diǎn)數(shù),也占4個字節(jié);char表示單個字符(如“a”或“3”),占1個字節(jié);字符串被聲明為字符數(shù)組。C還提供如下派生類型:· double(8字節(jié)浮點(diǎn)數(shù)類型)· short(2字節(jié)整數(shù)類型)· unsigned short或unsigned int(非負(fù)整數(shù),沒有符號位)運(yùn)算符及其優(yōu)先級C中的運(yùn)算符和大多數(shù)語言類

45、似:+ 加- 減/ 除* 乘% 取模/ 運(yùn)算符在操作數(shù)都是整數(shù)的情況下執(zhí)行整數(shù)除法運(yùn)算,否則執(zhí)行浮點(diǎn)數(shù)除法運(yùn)算。例如:void main()float a;a=10/3;printf("%fn",a);上面這段代碼將會打印出一個浮點(diǎn)數(shù),因?yàn)閍被聲明為float。但由于執(zhí)行的是整數(shù)除法運(yùn)算,所以a的值是3.0。C的運(yùn)算符優(yōu)先級和大多數(shù)語言的也很類似,即先乘除,后加減。5+3*4 的結(jié)果是17,不是32,因?yàn)?比+有更高的優(yōu)先級。使用括號可以改變正常的優(yōu)先級順序:(5+3)*4的結(jié)果是32。因?yàn)樵诶ㄌ栔?+3優(yōu)先計算。我們后面還將遇到運(yùn)算符優(yōu)先級引入指針后C的運(yùn)算符優(yōu)

46、先級會變得復(fù)雜一些。類型轉(zhuǎn)換C可以自動類型轉(zhuǎn)換。特別是使用指針時需要經(jīng)常這樣做。某些類型間的賦值操作時也會發(fā)生類型轉(zhuǎn)換。例如,上面的程序中整型數(shù)值被自動轉(zhuǎn)換為浮點(diǎn)型。顯式類型轉(zhuǎn)換時,將目的類型放在括號中,并放在要轉(zhuǎn)換的數(shù)據(jù)之前。例如,在上面的程序中,將a=10/3;替換為a=(float)10/3;后會得到結(jié)果3.33333,因?yàn)?0在做除法之前已被轉(zhuǎn)換為浮點(diǎn)數(shù)了。Typedef使用C的typedef語句,用戶可以聲明自定義的類型。例如,下面代碼定義了一個C程序中經(jīng)常用到的類型:#define TRUE 1#define FALSE 0typedef int boolean;void main

47、()boolean b;b=FALSE;這段代碼在C程序中聲明布爾型的變量。如果您不喜歡把實(shí)數(shù)的類型稱為“float”,您可以這樣寫: typedef float real;然后就可以使用實(shí)數(shù)類型了: real r1,r2,r3;只要在使用之前定義,typedef 語句可以出現(xiàn)在C程序的任何地方。結(jié)構(gòu)體在 C 語言中可以使用結(jié)構(gòu)體把變量組織到一起。例如:struct recint a,b,c;float d,e,f;struct rec r;如上例所示,每當(dāng)要聲明rec型的結(jié)構(gòu)體時,都要寫struct rec。這條規(guī)定很容易被忘記。一旦您由于疏忽忘了寫上struct,就會遇

48、到很多編譯錯誤。上面的代碼可以縮減為下面的形式:struct recint a,b,c;float d,e,f; r;即用一個語句同時聲明了rec類型和一個rec類型的變量r。您也可以使用typedef 語句定義結(jié)構(gòu)體類型的名字。例如,如果您不喜歡每次聲明一個結(jié)構(gòu)體變量時都去寫struct rec r,則您可以用:typedef struct rec rec_type;定義一個新類型,然后就可以聲明rec_type類型的變量了:rec_type r;使用句點(diǎn)(.)訪問結(jié)構(gòu)體的成員。如r.a=5;。數(shù)組在一般變量聲明的變量名后加上數(shù)組的大小即可聲明一個數(shù)組,如下所示:int a10; /* 整數(shù)

49、數(shù)組 */char s100; /* 字符數(shù)組(C 的字符串) */float f20; /* 實(shí)數(shù)數(shù)組 */struct rec r50; /* 結(jié)構(gòu)體數(shù)組 */增量長記法 短記法i=i+1; i+;i=i-1; i-;i=i+3; i += 3;i=i*j; i *= j;動手一試· 試寫幾段代碼研究一下類型轉(zhuǎn)換和運(yùn)算符優(yōu)先級。考查對象包括int、char、float等。· 創(chuàng)建一個結(jié)構(gòu)體數(shù)組,然后編寫一段代碼,使其基于結(jié)構(gòu)體的一個整型成員對結(jié)構(gòu)體數(shù)組排序。C 常見錯誤· 如前所述,當(dāng)使用/運(yùn)算符計算兩個整數(shù)時常常會得出意想不到的結(jié)果。用前請三思。大多數(shù)編程語

50、言都支持定義某種形式的函數(shù)。使用函數(shù)可以將一個大程序分解為小的代碼塊并分別命名,然后這些命名的代碼塊就可以在整個程序中重復(fù)使用了。函數(shù)輸入?yún)?shù)并返回一個結(jié)果。C函數(shù)可以輸入的參數(shù)個數(shù)沒有限制。一般來說,對于編譯器而言,只要在調(diào)用函數(shù)以前事先聲明函數(shù)名稱,則各函數(shù)在程序中的順序并不重要。我們已經(jīng)討論過一些有關(guān)函數(shù)的內(nèi)容了。前面遇到的rand函數(shù)幾乎是最簡單的函數(shù)了。它不接受參數(shù)并返回一個整數(shù):int rand()/* 摘自 K&R - 生成一個0-32767之間的隨機(jī)數(shù)字。*/ rand_seed = rand_seed * 1103515245 +12345; return (unsi

51、gned int)(rand_seed / 65536) % 32768;int rand()這些程序定義了rand函數(shù),還指明rand沒有輸入?yún)?shù)并返回一個整數(shù)。此函數(shù)沒有局部變量,但如果需要的話,局部變量會緊接著打開的開始。(C 允許您在任何  后面聲明變量,這些變量一直存在,直到程序執(zhí)行至那個匹配的 為止,此后即不復(fù)存在。因此函數(shù)的局部變量在遇到函數(shù)中匹配的 時就消失了。在其生存周期內(nèi),局部變量被保存在系統(tǒng)棧上。)請注意第一行的()后面沒有;。您若不小心加上了分號,編譯器會給出一大堆莫名其妙的錯誤信息。另外還要注意即使當(dāng)函數(shù)沒有參數(shù)時也要使用()。括號告訴編譯器您在聲

52、明一個函數(shù)而不是簡單地聲明一個int類型。對于任何要返回結(jié)果的函數(shù)來說,return語句是不可或缺的。它指明函數(shù)要返回的值并使函數(shù)立即退出。因此您可以在函數(shù)中放置多個return語句作為函數(shù)的多個退出點(diǎn)。若函數(shù)中沒有return語句,則函數(shù)在執(zhí)行到 時退出并返回一個隨機(jī)值(這時很多編譯器會發(fā)出警告)。C中的函數(shù)可以返回任何類型的值:包括int、float、char、結(jié)構(gòu)體等等。調(diào)用rand函數(shù)的方式有許多種。例如:x=rand();。此語句中x被賦值為rand的返回值。注意,在函數(shù)調(diào)用中即使沒有參數(shù)也必須使用(),否則x將被賦值為rand函數(shù)的內(nèi)存地址,而這通常并非您的本意。也可以用這種方式調(diào)

53、用rand:if (rand() > 100)或:rand();后一種方式中,rand函數(shù)被調(diào)用了,可是其返回值隨即被丟棄。您可能不會以這種方式使用rand,但很多函數(shù)會返回某種錯誤代碼作為調(diào)用結(jié)果,而您又不關(guān)心這些錯誤代碼的話(如您知道不可能發(fā)生錯誤),就可以用這種調(diào)用方式將其丟棄。如果您不想返回任何值的話,函數(shù)可以使用void作為返回類型。例如:void print_header() printf("第一個程序n"); printf("作者 Marshall Brainn"); printf("版本 1.0, 發(fā)布于1991年12月2

54、6日n");此函數(shù)沒有返回值??梢韵裣旅孢@樣調(diào)用:print_header();調(diào)用時必須加上(),否則函數(shù)不會被調(diào)用,即使此語句在很多系統(tǒng)上能通過編譯。C函數(shù)可以接受任何類型的參數(shù)。例如: fact(int i) int j,k; j=1; for (k=2; k<=i; k+) j=j*k; return j;返回傳入的整型參數(shù)i的階乘。用逗號分隔多個參數(shù): int add (int i, int j) return i+j;C語言經(jīng)歷了許多年的演變。有時您會看到用“舊式風(fēng)格”編寫的函數(shù)。以add為例:int add(i,j)int i;int j;return

55、i+j;您應(yīng)該能夠讀懂舊式代碼。它們在執(zhí)行上并無不同,只不過是另一種書寫格式罷了。編寫程序時應(yīng)該使用“新式風(fēng)格”(稱為ANSI C),把類型聲明寫在參數(shù)列表中;除非您要把代碼交付給只有“舊式”(非ANSI C)編譯器的人?,F(xiàn)在,把程序中的所有函數(shù)聲明函數(shù)原型已成為公認(rèn)的良好編程風(fēng)格。函數(shù)原型在真正定義函數(shù)之前,向后面的代碼聲明了函數(shù)的名稱、參數(shù)和返回值的類型。為了理解函數(shù)原型的用處,請錄入下面的程序并運(yùn)行:#include void main() printf("%dn",add(3);int add(int i, int j) return i+j;盡管add要求傳入兩個

56、參數(shù)而實(shí)際只傳入了一個,這段代碼還是能在很多編譯器上通過編譯而不會產(chǎn)成警告。這是因?yàn)楹芏郈編譯器既不對參數(shù)類型也不對參數(shù)個數(shù)做匹配性檢查。于是您可能僅是因?yàn)椴恍⌒亩鄠骰蛏賯髁艘粋€參數(shù)而要浪費(fèi)大量時間調(diào)試代碼。上面的代碼能順利通過編譯,卻給出錯誤的結(jié)果。針對此問題,C語言允許您在程序開始處(實(shí)際是任何地方)聲明函數(shù)原型。這樣一來,C就會檢查所有參數(shù)列表的類型和數(shù)目。試試編譯下面的程序:#include int add (int,int); /* add 的函數(shù)原型 */void main() printf("%dn",add(3);int add(int i, int j)

57、return i+j;函數(shù)原型使編譯器對printf語句報錯。請?jiān)诔绦蜷_始處為每個函數(shù)聲明原型。這樣可以為您節(jié)省大量的調(diào)試時間,還順便解決了不能在定義前使用函數(shù)的問題。例如,下面的代碼不能通過編譯:#include void main() printf("%dn",add(3);float add(int i, int j) return i+j;您也許會問:為什么add返回int時可以編譯,返回float時就不行了?因?yàn)槔弦恍┑腃編譯器默認(rèn)函數(shù)返回一個int值。使用函數(shù)原型可以解決這個問題?!芭f式”(非ANSI)編譯器也支持函數(shù)原型,但原型中的參數(shù)列表必須為空。舊式編譯器不對參數(shù)列表進(jìn)行錯誤檢查。動手一試· 請返回到前面介紹的那個冒泡法排序的例子,為冒泡排序創(chuàng)建一個函數(shù)

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論