C語言程式設計教程
第4版

朱鳴華 羅曉芳 董 明 孟 軍 汪德剛 編著
第1章
C語言概述
1.1程式設計的基本概念
計算機的産生是20世紀重大的科技成果之一。計算機的飛速發展大大促進了知識經濟的發展和社會資訊化的程序。人與計算機交流最通用的手段是程式設計語言。當人們想利用計算機解決某個問題時,必須用程式設計語言安排好處理步驟,并存入計算機内供計算機執行,這些用程式設計語言安排好的處理步驟稱為計算機程式,程式是計算機操作指令的集合。
一個計算機程式主要包括兩方面的内容:其一是關于程式實作算法的操作步驟描述,即動作描述;其二是關于算法操作對象的描述,即資料描述。曾經發明Pascal語言的著名計算機科學家沃思(Niklaus Wirth)關于程式設計提出了一個著名的公式:
程式=算法+資料結構
這個公式說明了程式設計的主要任務,也說明了在程式設計過程中“算法”與“資料結構”密不可分的關系。用程式設計語言編制一個能完成某項任務的計算機程式的過程叫作程式設計。用計算機解決一個實際問題,首先應進行程式設計,而程式設計主要包括對資料以及處理問題的方法和步驟的完整而準确的描述。
資料是操作的對象,操作的目的是對資料進行處理,以得到期望的結果。對資料的描述,就是指明在程式中要用到資料的哪些類型群組織形式,即資料結構;對問題的方法和步驟的描述,即計算機進行操作的步驟,也就是所采用的算法。
對于程式設計初學者來說,要學會如何設計一個正确的程式,首先要認真考慮和設計資料結構及操作步驟。一個正确的程式通常包含兩方面的含義:一是書寫正确,二是結果正确。書寫正确是程式在文法上正确,符合程式語言的規則;而結果正确通常是指對應于正确的輸入,程式能夠産生所期望的輸出。程式設計除了以上兩大要素之外,還涉及程式設計的思想和所用的具體語言工具及環境,可以詳細地描述為:
程式設計=算法+資料結構+程式設計方法+語言工具和環境
這4個方面是程式設計人員應具備的基本知識。其中,算法是靈魂,解決“做什麼”和“怎麼做”的問題,不了解算法就談不上程式設計。程式中的操作語句就是對算法的實作。算法是從計算機操作的角度對解題過程的抽象,資料結構是從如何組織被處理對象的角度進行抽象。本書不是以資料結構和算法為主展開讨論的,而是着重介紹利用C語言進行程式設計的基本方法。
程式設計方法是從宏觀的角度處理問題的方法,如結構化程式設計、面向對象的技術等。工具包括使用的程式設計語言及相關的編譯系統和調試工具。
程式設計的另一個關鍵是必須選擇且掌握一種程式設計語言,因為程式設計語言是人和計算機直接交流的工具。
程式設計語言通常分為三類:機器語言、彙編語言和進階語言。
機器語言是指由二進制代碼組成的,不需翻譯就可以被計算機直接執行的指令的集合。這是一種面向機器的語言,執行效率高,但通用性和可讀性都很差。
為了克服這些缺點,産生出一種符号語言,也稱為彙編語言。對于用彙編語言編寫的程式,計算機不能直接識别,需要彙程式設計式把它翻譯成機器代碼。它比機器語言使用起來友善,但通用性仍然很差。
人們把直接表示數學公式和解題方法的語言稱為進階語言。這種語言直覺通俗,非常接近于人們的“自然描述”語言,便于編寫、閱讀、修改和維護,通用性強。用進階語言編寫的源程式,機器也是不能識别的,必須通過編譯程式或解釋程式進行翻譯,最終生成機器語言程式。目前程式設計語言有很多,新的語言不斷湧現。各類語言都有其特點和适用的領域。本書介紹C語言。
最後一項指的是,要選擇一個合适的內建開發環境(Integrated Development Environment,IDE)。IDE是內建了程式員語言開發中需要的一些基本工具、基本環境和其他輔助功能的應用軟體。IDE一般包含四個主要元件:源代碼編輯器(editor)、編譯器(compiler)、解釋器(interpreter)和調試器(debugger)。開發人員可以通過圖形使用者界面(GUI)通路這些元件,并且實作整個代碼編譯、調試和執行的過程。現在的IDE也提供幫助程式員提高開發效率的一些進階輔助功能,比如代碼高亮、代碼補全和提示、文法錯誤提示、函數追蹤、斷點調試等。
1.2C語言發展簡史
C語言是一種通用的程式設計語言,由于它很适合用來編寫編譯器、作業系統,并進行嵌入式系統開發,是以被稱為“系統程式設計語言”,但它同樣适用于編寫不同領域中的應用程式。
1. C語言的産生
C語言是一種被廣泛應用的計算機進階程式設計語言,是在B語言的基礎上發展起來的,它經曆了不同的發展階段。
早期的系統軟體設計均采用彙編語言,例如,大家熟知的UNIX作業系統。盡管彙編語言在可移植性、可維護性和描述問題的效率等方面遠遠不及進階程式設計語言,但是一般的進階語言有時難以實作彙編語言的某些功能。
那麼,能否設計出一種集彙編語言與進階語言的優點于一身的語言呢?這種思路促成了UNIX系統的開發者(美國貝爾實驗室的Ken Thompson)于1970年設計出了既簡單又便于硬體操作的B語言,并用B語言寫了第一個UNIX作業系統,這個作業系統先在PDP-7上實作,1971年又在PDP-11/20上實作。
B語言的前身是BCPL(Basic Combined Programming Language),它是英國劍橋大學的Martin Richards在1967年基于CPL語言設計的,而CPL語言又是在1963年基于ALGOL 60産生的。
1972~1973年,貝爾實驗室的D. M. Ritchie在B語言的基礎上設計出C語言,該語言彌補了B語言過于簡單、功能有限的不足。
1973年,Ken Thompson和D. M. Ritchie合作将90%以上的UNIX代碼用C改寫。随着改寫UNIX作業系統的成功,C語言也逐漸被人們接受。
1987年以後,C語言已先後被移植到大、中、小、微型機上,并獨立于UNIX和PDP,進而得到了廣泛應用。
2. C語言的發展和應用
1978年,B. W. Kernighan 和D. M. Ritchie合寫了一本經典著作——《C程式設計語言》(The C Programming Language,中文版、影印版均已由機械工業出版社引進出版),它奠定了C語言的基礎,被稱為标準C。
1983年,美國國家标準學會(ANSI)根據C語言問世以來的各種版本對C的發展和擴充,制定了新的标準,稱為ANSI C。1987年又公布了新标準,稱為87 ANSI C。目前流行的多種版本的C語言編譯系統都是以此為基礎的。
在ANSI标準化後,C語言的标準在相當一段時間内都保持不變,直到20世紀90年代才進行了改進,這就是ISO 9899:1999(1999年出版)。這個版本就是通常提及的C99。它于2000年3月被ANSI采用。
3. C語言和C++語言交融發展
由于C語言是面向過程的結構化和子產品化的程式設計語言,當處理的問題比較複雜、規模龐大時,就顯現出一些不足,由此面向對象的程式設計語言C++應運而生。C++的基礎是C,它保留了C的所有優點,增加了面向對象機制,并且與C完全相容。絕大多數C語言程式可以不經修改直接在C++環境中運作。
1.3C語言的特點
C語言作為一種古老而常青的經典程式設計語言,具備了現代程式設計的基本結構和元素,其文法是許多語言的基礎。目前C語言在各類語言排行榜中始終名列前茅,它具有以下優點:
1)兼具進階、低級語言的雙重能力。C語言允許直接通路實體位址,能進行位操作,能實作彙編語言的大部分功能,可以直接對硬體進行操作,是以又被稱為中級語言。
2)生成的目标代碼品質好,程式執行效率高。C語言具有彙編語言的許多特性,一般隻比彙程式設計式生成的目标代碼效率低10%~20%,可以開發出執行速度很快的程式。
3)語言簡潔,結構清晰。C程式通常是由若幹函數組成的,強大的函數功能為程式的子產品化和結構化提供了保證,是以程式簡潔清晰,可讀性強。
4)語言表達能力強。C語言運算符豐富,例如,在C語言中,把括号、指派、強制類型轉換等都作為運算符處理。C語言具有現代化語言的各種資料結構,如整型、字元型、數組型、指針型、結構體和共用體等,而且具有結構化的控制語句。
5)程式通用性、可移植性好。C語言沒有依賴于硬體的輸入/輸出語句,而采用系統的庫函數進行輸入/輸出操作,是以C語言不依賴于任何硬體系統,這種特性使得用C語言編寫的程式很容易移植到其他環境中。
當然,C語言也有自身的不足,和其他進階語言相比,其文法限制不太嚴格,例如,對變量的類型限制不嚴格,影響程式的安全性,對數組下标越界不進行檢查等。從應用的角度來看,C語言比其他進階語言較難掌握。
總之,C語言既具有進階語言的特點,又具有彙編語言的特點;既是一個成功的系統設計語言,又是一個實用的程式設計語言;既能用來編寫不依賴計算機硬體的應用程式,又能用來編寫各種系統程式。它是一種深受歡迎、應用廣泛的程式設計語言。
1.4簡單C語言程式舉例
在這一節中,我們通過兩個簡單的C語言程式例子來介紹C語言的程式結構,并對C語言的基本文法成分進行相應的說明,以便使讀者對C語言程式有一個大緻了解。
【例1-1】計算矩形的面積。
#include <stdio.h> //1:編譯預處理
int main( ) //2:主函數
{ //3:函數體開始
float h, w, area; //4:聲明部分, 定義變量
h=10.5; //5:以下4條C語句為執行部分,給變量h和w指派
w=20.5;
area=h*w; //7:計算矩形的面積
printf("area=%6.2f\n", area); //8:輸出area的值
return 0; //9:傳回值為0
} //10:函數體結束
運作結果:
area=215.25
每行中以“//”開始的右邊的文本表示程式注釋的内容。
第1行:是一個編譯預處理,在程式編譯前執行,訓示編譯程式如何對源程式進行處理。它以“#”開頭,結尾不加分号,以示和C語句的差別。
第2行:main表示主函數,每一個C程式都必須有一個主函數,int表示主函數為整型。函數體由第3行和第9行的一對花括号括起來。
第4行:是變量聲明部分,定義變量h、w和area為實型變量。
第5和6行:是兩條指派語句,給變量h指派10.5,w指派20.5。
第7行:将算術表達式h*w的值賦予變量area。
第8行:調用函數printf輸出矩形面積值。
第9行:向作業系統傳回一個零值,如果程式不能正常執行,則會自動向作業系統傳回一個非零值,一般為-1。
上面的主函數構成了一個完整的程式,稱為源程式。它以檔案的方式存在,檔案中包含函數的源程式代碼。C語言規定儲存C源程式檔案的擴充名為“.c”。
【例1-2】計算兩個矩形的面積之和。
/*本程式用來計算兩個矩形的面積之和。包括主函數int main( )、
一個子函數double area(double h, double w )*/
#include <stdio.h> //1:編譯預處理
double area(double h, double w ) //2:定義函數area
{
double s;
s=h*w;
return s; //6:傳回s的值, return是關鍵字
}
int main( ) //8:主函數
{
double h1, h2, w1, w2, s1, s2; //10:聲明部分, 定義變量
h1=10.5; w1=20.5;
h2=1.5*h1; w2=1.5*w1; //12:計算變量h2, w2的值
s1=area(h1, w1); //13:調用area函數, 将得到的傳回值賦給變量s1
s2=area(h2, w2);
printf("area=%6.2f \n ", s1+s2); //15:輸出兩個矩形的面積之和
return 0;
}
area=699.56
本程式包括主函數main、函數area(被主函數調用)和一個編譯預處理指令。
最前面兩行中 /……/内的文本也表示程式注釋的内容,這種方式一般用于表示多行注釋。
第2行:從該行開始到第6行定義函數area,包括函數類型、函數名和函數體等部分。
第13和14行:調用函數area,将兩次調用的傳回值分别賦給變量s1和s2。
第15行:計算并輸出兩個矩形的面積之和。
上面兩個函數構成了一個完整的程式,稱為源程式。可以把這兩個函數放在一個檔案中,當程式語句多的時候也可以分别以函數為機關放在兩個以上的檔案中,儲存C源程式檔案的擴充名為“.c”。
1.5C語言程式的組成與結構
通過以上兩個例子,我們對C語言程式的組成和結構有了初步和直覺的了解,總結如下:
1)一個C語言程式的主體結構是由一個或若幹個函數構成的。這些函數的代碼以一個或若幹個檔案的形式儲存。這些函數中必須有且隻能有一個名為main的主函數。
2)主函數main是程式的入口,它可以出現在程式的任何位置。一個C程式總是從主函數main開始執行,最後結束于主函數。
3)C程式中的函數包括:主函數main,使用者自定義函數(例如,例1-2中的area),系統提供的庫函數(例如,輸出函數 printf)。
4)函數由函數頭和函數體兩部分組成,函數頭由函數類型的定義、函數名和參數表組成,函數體由聲明部分(所使用變量和函數的說明)和若幹執行語句組成。
5)語句由關鍵字和表達式組成,每個語句和聲明部分的結尾都必須加分号。複合語句的開頭和結尾使用左、右花括号{ }。
關鍵字是由C語言系統規定的具有特定功能的固定字母組合。例如,例1-2中的 int、double和return就是關鍵字。
用運算符将操作對象連接配接起來、符合C語言文法的式子稱為表達式。表達式的組成元素有:變量、常量、函數調用、運算符。這些組成元素是以辨別符和關鍵字等形式存在的。例如,例1-2中的h2=1.5*h1和 w1=20.5 都是表達式。
6)程式中“/ /”内的文字是程式的注釋部分,是便于閱讀了解程式的解釋性附加文本,程式編譯器完全忽略注釋部分的内容。此外,在程式調試時,也可以将一部分代碼轉換為注釋保留,而不必删除,以提高程式調試的效率。
另外,一些C語言開發工具還支援用“//”辨別注釋部分,如果某行程式代碼前面插入符号“//”,該符号後面的部分就變為注釋行,并且本行有效,不能跨行。一般情況下,如果注釋内容在程式中占用多行,習慣用“/ /”,而單行注釋内容用“//”辨別即可。
從以上分析可以發現,C程式的組織和構造與日常文章的結構很類似,如表1-1所示。
表1-1文章和C語言對應的層次結構
在一般語言的學習過程中,首先學字、詞組,然後造句,閱讀範文,最後寫作文。現在學習計算機語言,我們也同樣遵循這個規律,即先學習常量、變量的類型和定義方法,然後依次學習表達式、語句和函數等,同時閱讀一些程式範例,最後編寫程式。當然二者也有本質上的差別,一般語言的學習以形象思維為主,而計算機語言的學習是以邏輯思維為主。C語言程式的層次結構如圖1-1所示。
圖1-1C語言程式的層次結構
1.6C語言程式的開發步驟
一個C語言程式從最初編寫到得到最終結果,大緻經過以下幾個步驟:
1)編輯源程式。選擇一種C語言開發工具軟體(IDE),輸入編寫好的程式代碼,稱之為源程式,它以檔案的方式存在,檔案的擴充名為“.c”。
2)編譯源程式。為了使計算機能執行進階語言源程式,必須把源程式轉換為二進制形式的目标程式,這個過程稱為編譯源程式。
編譯是以源程式檔案為機關分别進行的,每一個源程式檔案對應生成一個目标檔案,目标檔案的擴充名為“.obj”。
編譯過程中對源程式的全部内容進行檢查,例如檢查程式中關鍵字的拼寫是否正确,根據程式的上下文檢查文法是否有錯等,編譯結束後,系統顯示所有的編譯出錯資訊。
一般編譯系統的出錯資訊有兩種:一種是錯誤(error)資訊,這類錯誤出現後,系統不生成目标檔案,必須改正後重新編譯;另一種是警告(warning)資訊,是指一些不影響程式運作的不合理現象或輕微錯誤。例如,程式中定義了一個變量,卻一直沒有使用,出現這類警告資訊,系統仍可以生成目标檔案。
3)連接配接目标檔案。編譯結束,得到一個或多個目标檔案,此時要用系統提供的“連接配接程式”(linker)将一個程式的所有目标檔案和系統的庫檔案以及系統提供的其他資訊連接配接起來,最終形成一個可執行的二進制檔案,可執行檔案的擴充名為“.exe”。
4)運作程式。運作最終形成的可執行檔案,得到運作的結果。
5)結果分析。分析程式的運作結果,如果發現結果不對,應檢查程式或算法是否有問題,修改程式後再重複上面的步驟。
C語言程式的開發步驟如圖1-2所示。
圖1-2C語言程式的開發步驟
小結
本章首先叙述了程式設計的基本概念以及C語言産生和發展的曆史過程,然後與其他進階語言進行對比,列舉了C語言的特點,再通過兩個簡單的C程式執行個體,描述了C語言程式的基本組成和結構特點,最後介紹了C語言程式開發各個步驟的内容。
通過本章的學習,讀者應該對程式設計的概念有初步的認識,對C語言總體結構和開發步驟有初步的了解。建議學習本章内容後,盡快在計算機上編譯、運作一個簡單的C語言程式。在今後的學習中,讀者會發現有些問題用文字叙述很難領會,但上機程式設計後,很容易了解,即所謂“在程式設計中學習程式設計”。
習題
一、簡答題
簡要回答下列問題。
- 程式的定義是什麼?程式主要由幾部分組成?
- C語言的主要特點有哪些?
- C語言程式是由哪些部分組成的,各部分的作用是什麼?
二、選擇題
以下各題在給定的四個答案中選擇一個正确答案。
-
以下叙述正确的是( )。
A. C語言允許直接通路實體位址,可以直接對硬體進行操作
B. C語言程式不用編譯,即可被計算機識别運作
C. C語言不允許直接通路實體位址,不可以直接對硬體進行操作
D. C語言程式隻需編譯,不需連接配接即可被計算機運作
-
在一個C程式中( )。
A. main函數出現在所有函數之前,C程式不一定都有main函數
B. main函數可以在任何地方出現,一個C程式必須有且僅有一個main函數
C. main函數必須出現在所有函數之後,一個C程式隻能有一個main函數
D. main函數出現在固定位置,一個C程式可以有多個main函數
三、填空題
- C語言開發工具直接輸入的程式代碼是 A 檔案,經過編譯後生成的是 B 檔案, 經過連接配接後生成的是 C 檔案。
- C語言源檔案的字尾是 A ,經過編譯後生成的檔案的字尾是 B ,經過連接配接後生成的檔案的字尾是 C 。
四、編寫程式題
輸入下面的程式,上機調試并運作。
#include <stdio.h>
int main( )
{
float r, s;
r=15.5;
s=2*3.14*r;
printf("r=%4.2f, s=%4.2f\n", r, s);
return 0;
}