第 第 1 章
概述 計算機語言是人與計算機之間交流信息的工具,由計算機能夠識別的語句組成,它使用一整套帶有嚴格規定的符號體系來描述計算機語言的詞法、語法、語義、語用。詞法負責從構成源程序的字符串中識別出一個個具有獨立意義的最小語法單位(單詞);語法涉及語言的構成規律,確定程序的結構形式;語義說明語句代表的含義及該語句的執行過程;語用指出語句的實際用途。
C 語言是一種通用的程序設計語言,它具有豐富的運算符和表達式,以及先進的控制結構和數據結構。C 語言既具有高級語言簡單易學和可移植性好的特點,又具有匯編語言生成代碼質量高的優點。因此,C 語言具有較強的生命力和廣泛的應用前景。
本章從程序設計基礎知識入手,對 C 語言做一概括性介紹,讓讀者了解一個 C 語言程序的基本框架和它的書寫格式,使讀者能夠學會編寫簡單的 C 程序,并能夠進行編輯、編譯、連接、調試運行等上機操作。
1.1
程序設計基礎
在介紹 C 語言程序設計之前,我們先來了解一些有關程序設計的基礎知識。
1.1.1
程序與程序設計語言
1.程序 所謂程序,就是一系列遵循一定規則和思想并能正確完成指定工作的代碼(也稱為指令序列)。簡單地說,程序主要用于描述完成某項功能所涉及的對象和動作規則。通常,一個計算機程序主要描述兩部分的內容,其一是描述問題的每個對象及他們之間的關系,即數據結構的內容;其二是描述對這些對象進行處理的動作、這些動作的先后順序以及它們所作用的對象,要遵守一定的規則,即求解某個問題的算法。
因此,對程序的描述,也可以用經典的公式來表示:
程序 = 數據結構 + 算法 一個設計合理的數據結構往往可以簡化算法,而且一個好的程序應該具有可靠性、易讀性、可維護性等良好特點。
計算機程序有以下共同的性質:
?。?)目的性:程序有明確的目的,運行時能完成賦予它的功能。
?。?)分步性:程序為完成其復雜的功能,由一系列計算機可執行的步驟組成。
?。?)有序性:程序的執行步驟是有序的,不可隨意改變程序步驟的執行順序。
?。?)有限性:程序是有限的指令序列,程序所包含的步驟是有限的。
?。?)操作性:有意義的程序總是對某些對象進行操作,使其改變狀態,完成其功能。
2.程序設計語言 我們平時在使用計算機為我們工作時,計算機所做的工作實際上是由人們事先編好的程序來控制的,編寫程序的工具就是程序設計語言。
程序設計語言(Programming Language)是一組用來定義計算機程序的語法規則。它是一種被標準化的交流技巧,用來向計算機發出指令。一種計算機語言讓程序員能夠準確地定
義計算機所需要使用的數據,并精確地定義在不同情況下所應當采取的行動。
程序設計語言有許多種,按照程序設計語言發展的過程,大概分為三類:機器語言、匯編語言和高級語言。
1)機器語言 機器語言是由 0 和 l 二進制代碼按一定規則組成的、能被機器直接理解和執行的指令集合。它的突出優點是具有最快的運行速度和最少的存儲開銷。它的缺點是機器指令不容易記憶,可讀性差,編程工作量大,容易出錯,通用性差,且隨著不同的計算機系統而改變,現在已經沒有人用機器語言直接編程了。
下面這三行就是某計算機的機器指令,功能是計算 A=15+10 的值:
10110000 00001111 00101100 00001010
11110100
首先,把 15 放入累加器 A 中,然后讓 10 與累加器 A 中的值相加,結果仍放入 A 中,最后結束,停機。
2)匯編語言 為了克服機器語言的缺點,人們用英文助記符描述機器指令,例如用 ADD 表示加、SUB表示減等等,這種采用指令助記符表示的語言就是匯編語言又稱符號語言。例如,上述A=15+10 的計算可用下面的匯編語言程序實現:
MOV A,15
:把 15 放入累加器 A 中 ADD A,10
:10 與累加器 A 中的值相加,結果仍放入 A 中 HLT
:結束,停機 這三條匯編指令與前面三條機器指令的作用是一一對應的。兩者相比,后者的清晰度明顯有了改善??梢?,匯編語言一定程度上克服了機器語言難讀難改的缺點,同時保持了其編程質量高,占存儲空間少,執行速度快的優點。故在程序設計中,對實時性要求較高的地方,如過程控制等,仍經常采用匯編語言。但匯編語言面向機器,使用匯編語言編程需要直接安排存儲,規定寄存器和運算器的動作次序,還必須知道計算機對數據約定的表示(定點、浮點、雙精度)等。這對大多數人員來說,都不是一件簡單的事情。此外,該語言還是依賴于機器,不同的計算機在指令長度、尋址方式、寄存器數目、指令表示等都不一樣,這樣使得匯編程序不僅通用性較差,而且可讀性也差,這促使了高級語言的出現。
用匯編語言編寫的程序,必須翻譯成計算機所能識別的機器語言后,才能被計算機執行。
3)高級語言 高級語言是由表達各種意義的英文單詞和數學公式按照一定的語法規則來編寫程序的語言。例如用“+”表示加法、用“-”表示減法等。
高級語言是更接近于自然語言或數學語言的程序設計語言,便于學習和記憶。例如,上述計算 A=15+10 的 BASIC 語言程序如下:
A=15+10
"15 與 10 相加的結果放入 A 中 PRINT
A
"輸出 A END
"程序結束 可見,高級語言編寫的程序非常直觀明了。
高級語言徹底擺脫了依賴于機器硬件的指令系統,是面向應用的計算機語言。它不再依賴于具體的計算機,用高級語言編寫的程序可以在不同的計算機上使用,程序具有可移植性。編程時用戶不再考慮計算機的內部結構和硬件環境,可以集中精力考慮解題的算法和數據結構,因此編程效率大大提高。
高級語言不能直接在計算機上運行,因為計算機只能識別機器語言程序,高級語言編寫
的源程序必須經過另外的語言處理程序翻譯成機器語言程序后才能被機器接受。因此,高級語言程序的執行速度通常比不上機器語言。
翻譯程序分為兩種,一種是解釋系統,另一種是編譯系統。解釋系統是對高級語言編寫的程序翻譯一句執行一句;而編譯系統是將高級語言編寫的程序文件全部翻譯成機器語言,生成可執行文件以后再執行。高級語言幾乎在每一種機器上都有自己的翻譯程序。C 語言的翻譯程序屬于編譯系統。
高級語言可分為 3 類:面向過程的語言、面向問題的語言和面向對象的語言。
?。?)面向過程的語言致力于用計算機能夠理解的邏輯來描述需要解決的問題和解決問題的具體方法、步驟。在程序中不僅要告訴計算機“做什么”,還要告訴計算機“如何做”,即在程序中要詳細描述用什么動作加工什么數據,即解題的過程和細節。面向過程的語言有FORTRAN、BASIC、PASCAL、C 等。
?。?)面向問題的語言又稱非過程化的語言或稱第四代語言(4GLS)。用面向問題的語言解題時,不必關心問題的求解算法和求解的過程,只需指出問題是要計算機做什么,數據的輸入和輸出形式,就能得到所需結果。面向問題的語言是采用快速原型法開發應用軟件的強大工具,能夠快速地構造應用系統,從而大大地提高了軟件開發效率。它與數據庫的關系非常密切,能夠對大型數據庫進行高效處理。目前應用最廣泛的面向問題的語言有 SQL 等。
?。?)面向對象的語言是將客觀事物看作具有屬性和行為的對象,通過抽象找出同一類對象的共同屬性和行為,形成類。通過類的繼承與多態可以很方便地實現代碼重用,這大大地提高了程序的復用能力和程序開發效率。面向對象語言已是程序語言的主要研究方向之一。面向對象的語言有 C++、Java、Visual Basic 等。
1.1.2
程序設計方法 程序設計簡單地說就是用計算機語言編寫程序的過程。學習計算機語言的目的就是利用該語言工具設計出可供計算機運行的程序。通常,程序設計是很講究方法的,程序設計方法是影響程序設計成敗以及程序設計質量的重要因素之一,C 語言主要采用結構化程序設計方法。
結構化程序設計是荷蘭學者狄克斯特拉(E.W.dijkstra)在 1969 年提出的一種程序設計方法,它規定了一套如何進行程序設計的準則,采用了自頂向下逐步求精的分析設計方法、分而治之的分割技術和模塊化的組織結構,使得設計的程序具有合理的結構、易讀、易調試,容易保證其正確性。
結構化程序設計方法采用:
1.自頂向下 2.逐步細化 3.模塊化設計 4.結構化編碼
結構化程序設計以模塊化設計為中心,將待開發的軟件系統劃分為若干個相互獨立的模塊,這樣使完成每一個模塊的工作變得單純而明確,為設計一些較大的軟件打下了良好的基礎。
由于模塊相互獨立,因此在設計其中一個模塊時,不會受到其它模塊的牽連,因而可將原來較為復雜的問題化簡為一系列簡單模塊的設計。模塊的獨立性還為擴充已有的系統、建立新系統帶來了不少的方便,我們可以充分利用現有的模塊作積木式的擴展。
按照結構化程序設計的觀點,任何模塊都可以通過三種基本程序結構:順序結構、選擇結構和循環結構組合來實現。
三種基本結構應具有如下良好的特性:
1.只有一個入口,即每個模塊與外部聯系只有單一的入口; 2.只有一個出口,即每個模塊與外部聯系只有單一的出口; 3.無死語句,即不存在永遠都執行不到的語句; 4.無死循環,即不存在永遠都執行不完的循環; 每個模塊根據其功能先編寫程序框架,逐步深入,直到精確地編寫出每一個程序結構,精確地編寫每一條語句。
完成編程后,應該檢查每條語句、每個程序結構的邏輯及每個模塊的功能是否正確,直到檢查整個程序是否達到問題的要求,通過編輯、編譯、連接運行、調試檢驗程序是否達到精度要求。
程序設計的首要目標是在程序正確的前提下,提高程序的可讀性、易維護性和可移植性??勺x性是指使用良好的書寫風格和易懂的語句編寫程序;易維護性是指當業務需求發生變化時,不需要太多的開銷就可以擴展和增加程序的功能;可移植性是指編寫的程序在各種計算機和操作系統上都能運行,并且運行結果相同。
1.1.3
程序 設計的基本 過程 程序設計是人們根據要解決的實際問題,提出相應的需求,在此基礎上設計數據結構和算法,然后再編寫相應的源程序代碼并測試該代碼運行的正確性,通過反復調試直到能夠得到正確的運行結果為止,最后整理設計文檔的全過程。較小規模的程序設計由一個程序員完成,大型程序設計是由多個程序員分工,共同協作完成的,因此必須經過多種測試,并詳細整理設計文檔。一般來講,這個過程應當按圖 1-1 所示的步驟進行。
圖 1- 1
程序設計的基本過程 1.提出和分析實際問題 提出和分析實際問題 建立數學模型 設計算法 編寫源程序 編譯調試程序 運行程序 測試程序 編寫程序文檔
提出實際需求的用戶往往不具備太多的計算機知識,而程序設計人員可能又不具備用戶的專業知識,因此,在程序開發初期首先必須由用戶和程序設計人員一起對實際問題進行分析,充分理解用戶的要求,明確哪些要求可以實現,哪些要求不能實現或需經一定的處理才能實現,確定開發的總目標,提出開發的任務和要求,從中獲得必要的輸入數據,明確問題要求做什么,需要什么樣的數據輸出。
分析問題的要求、弄清問題的性質、發現問題的特點、確定解決問題的目標能夠使我們采取有效的方法解決問題。
2.建立數學模型 要用計算機解決實際問題,首先要用理想模型模擬實際問題。理想模型是從實體中抽象出來并能用數學表達式精確定義的實體。建立數學模型的過程就是把錯綜復雜的實際問題進行簡化抽象,用數學公式來描述實際問題的運動和變化過程。例如,用一些數學方程來描述人造衛星的飛行軌跡等。
在建立數學模型的過程中,分析問題的要求、確定解決問題的目標、明確問題的輸入數據和輸出信息、理解問題的約束限制條件,是選擇制定數學模型、建立數學模型的關鍵步驟,是解決問題的關鍵所在。
3.設計算法 一般來說,從實際問題抽象出數學模型通常是有關領域的專業工作者的任務,計算機工作人員只起輔助作用。程序設計人員的工作,最關鍵的一步就是設計算法。算法是指為解決某一特定問題而進行一步一步有窮的操作過程,是一組規則的集合,可以用流程圖來表示算法。編寫程序代碼之前,設計好算法,畫出流程圖,往往會起到事半功倍的效果。
算法可以分為兩大類:數值計算算法和非數值計算算法。數值計算算法的目的是求數值解,其特點是少量的輸入、輸出,復雜的運算,如求高次方程的根、求函數的定積分等。非數值計算算法目的是對數據的處理,其特點是大量的輸入、輸出,簡單的運算,例如,對數據的排序、查找等算法。
一個好的算法應當具有以下特性:
?。?)有窮性:一個算法應包含有限個操作步驟。也就是說,在執行若干個操作步驟之后,算法將結束,并且每一步都在合理的時間內完成。
?。?)確定性:算法中每一條指令必須有確切的含義,不能有二義性,并且對于相同的輸入必然有相同的執行結果。
?。?)可行性:一個算法是可行的,即算法中指定的操作,都可以通過已實現的基本運算執行有限次來實現。
?。?)輸入:一個算法一般有零個或多個輸入。在計算機上實現的算法,通常是用來處理數據對象的,在大多數情況下這些數據是需要通過輸入來得到的。
?。?)輸出:一個算法一般有一個或多個輸出,算法的目的是為了求“解”,這些“解”只有通過輸出才能得到。
描述算法的常用工具是流程圖,也稱程序框圖,流程圖是算法的圖形描述,它用一組圖形符號來表示各種操作,它往往比程序更直觀,能較清晰地表達各種操作之間的邏輯關系,容易閱讀和理解。常用的流程圖符號如圖 1-2 所示。
圖 1- 2
常用流程圖符號 流程線 連接點 處理框 或 判斷框 輸入輸出框 起止框
4.編寫源程序 如果算法正確,將它轉換為任何一種高級語言程序,并不困難,這一步通常稱為編碼。
現在的程序設計語言一般都是一個集成開發環境,自帶編輯器,方便編輯程序。編寫好的程序代碼通過編輯器輸入到計算機內,利用編輯器可對輸入的程序代碼進行復制、刪除、移動等編輯操作,然后以文件(源程序)形式保存。
5.編譯調試程序 源程序必須通過編譯程序將源程序翻譯成目標程序,這期間編譯器對源程序進行語法結構檢查,找出在程序編制過程中存在的語法錯誤,加以修改。這是一個重復進行的過程,需要反復調試程序。
6.運行程序 將編譯源程序生成的目標程序和程序中所需的系統中固有的目標程序模塊(如調用的標準函數、執行的輸入/輸出操作的模塊)連接后生成可執行文件。運行該程序,檢查程序輸出結果是否正確,如發現錯誤,檢查程序的邏輯是否正確,主要解決算法設計錯誤。
7.測試程序 測試程序是對照問題的要求,通過讓程序試運行一組數據,分析輸出的結果,檢查是否達到問題要求的功能和精度要求,輸出信息的格式是否符合要求。這組測試數據應是以任何程序都是有錯誤的前提精心設計出來的,稱為測試用例。
測試有黑盒測試和白盒測試兩種方法。對于不同的測試方法有不同的測試用例。
?。?)黑盒測試也稱為功能測試或數據驅動測試。它把程序看成一個黑盒子,完全不考慮程序的內部結構和處理過程,只對程序的接口進行測試,即檢查程序是否能適當地接受輸入數據并產生正確的輸出信息。實際上目前有些軟件開發商推出的軟件 β 版,即為測試版,免費提供給用戶使用,從使用角度找出軟件的問題,這屬于黑盒測試方法。
?。?)白盒測試是把程序看成一個透明的白盒子,也就是完全了解程序的內部結構和處理過程。這種方法按照程序內部的邏輯來測試,檢驗程序中的每條通路是否正確工作。因此白盒測試又稱為結構測試或邏輯驅動測試。白盒測試一般由計算機專業人員進行。
例如對求解一元兩次方程根:ax 2 +bx+c=0,測試用例可為:
a=0,b=0,c=0,b 2 -4ac≥0,b 2 -4ac<0 等各種特殊情況時對應輸入 a、b、c 的值,觀察程序運行的結果,屬于白盒測試法;若輸入任何 a、b、c 的值包括非法的數據,觀察程序運行的結果,屬黑盒測試法。
8.編寫程序文檔 在程序準確無誤后,要認真編寫程序文檔。包括設計要求、設計思路、設計過程、使用的算法、數據結構、輸出信息及格式等,在源程序中要用注釋語句加上必要的說明。如果沒有程序文檔,編制的程序過一段時間后自己也看不懂,更不要說給別人看,對此要引以為戒,要學會從學習程序設計開始就養成良好的習慣。
1.2
C 語言及其特點
C 語言是一種得到廣泛重視并普遍應用的計算機程序設計語言,也是國際公認的最重要的幾種通用程序設計語言之一,它既可用來編寫系統軟件也可用來編寫應用軟件。
1.2.1
C 語言的發展過程 C 語言的發展是一個充實和完善的過程。
C 語言是由貝爾實驗室的 Dennis Ritchie 和 Brian Kernighan 根據 B 語言開發出來的,而B 語言又是由一種早期的編程語言 BCPL(Basic Combined
Programming Language)發展演變而來的。BCPL 的根源可以追溯到 1960 年的 ALGOL 60 (Algol Programming Language),ALGOL 60 是一種面向問題的高級語言,離硬件較遠。1963 年,英國劍橋大學推出 CPL(Combined Programming Language)語言,CPL 修改了 ALGOL 60,使其能夠直接作較低層次的操作。1967 年英國劍橋大學的 Martin Richards 對 CPL 做了改進,推出了 BCPL 語言。
1970 年美國貝爾實驗室的 Ken Thompson 以 BCPL 語言為基礎,又做了進一步簡化,設計出了很簡單的而且很接近硬件的 B 語言(取 BCPL 的第一個字母),并用 B 語言寫了第一個UNIX 操作系統,在 PDP-7 上實現。1971 年在 PDP-l1/20 上實現了 B 語言,并寫了 UNIX操作系統。但 B 語言過于簡單,功能有限。1972 年至 1973 年間,Dennis Ritchie 在 B 語言的基礎上增加了數據類型(Datatype)和結構(Structure)設計出了 C 語言(取 BCPL 的第二個字母)。C 語言既保持了 BCPL 和 B 語言的優點(精練,接近硬件),又克服了它們的缺點(過于簡單,數據無類型等)。
最初的 C 語言是為描述和實現 UNIX 操作系統提供的一種工具語言。但 C 語言并沒有被束縛在任何特定的硬件或操作系統上,它具有良好的可移植性。1977 年出現了不依賴于具體機器的 C 語言編譯文本——《可移植 C 語言編譯程序》,用該程序編寫的 UNIX 系統迅速在各種機器上實現,UNIX 系統支持的 C 語言也被移植到相應的計算機上。C 語言和 UNIX系統在發展過程中相輔相成,得到了廣泛應用,使它先后被移植到各種大、中、小、微型計算機上。
以 1978 年發表的第七版本 UNIX 系統中的 C 語言編譯程序為基礎,B.W.Kernighan 和D.M.Ritchie 合著了《The C Programming Language》。這本書中介紹的 C 語言成為后來廣泛使用的 C 語言版本的基礎,被稱為標準 C 語言。1983 年,美國國家標準化協會(ANSI)根據 C 語言問世以來的各種版本對 C 語言的發展和擴充制定了新的標準,稱為 ANSI C。1990年,C 語言成為國際標準化組織(ISO)通過的標準語言。
1.2.2
C 語言的特點 一種語言之所以能存在和發展,并具有生命力,總是有不同于其他語言的特點。C 語言也是如此,它的特點是多方面的,人們從不同的角度可總結出眾多的特點,但從全面考慮可歸納為以下幾點。
1.C 語言是比較低級的語言。有人把 C 語言稱為高級語言中的低級語言,也有人稱它是中級語言。它具有許多通常只有像匯編語言才具備的功能,如位操作、直接訪問物理地址等等,這使 C 語言在進行系統程序設計時顯得非常有效,而過去系統軟件通常只能用匯編語言編寫。事實上,C 語言的許多應用場合是匯編語言的傳統領地,現在用 C 語言代替匯編語言,使程序員得以減輕負擔,提高效率,而且寫出的程序具有更好的可移植性。
C 語言簡潔緊湊,靈活方便。C 語言只有 32 個關鍵字,9 種控制語句,程序書寫自由,主要用小寫字母表示。它把高級語言的基本結構和語句與低級語言的實用性相結合。
2.C 語言是結構化的程序設計語言。C 語言主要結構成分是函數,函數允許一個程序中的各任務分別定義和編碼,使程序模塊化。C 語言還提供了多種結構化的控制語句,如用于循環的 for、while、do-while 語句,用于判定的 if-else、switch 語句等,十分便于采用自頂向下、逐步細化的結構化程序設計技術。因此,用 C 語言編制的程序容易理解、便于維護。
3.C 語言具有豐富的運算能力。在 C 語言中除了一般高級語言使用的算術運算及邏輯運算功能外,還具有獨特的以二進制位(bit)為單位的位與、位或、位非以及移位操作等運算。并且 C 語言具有如 a++、b--等單項運算和+=、-=等復合運算功能。
4.C 語言數據類型豐富,具有現代化語言的各種數據類型。C 語言的基本數據類型有整型(int)、浮點型(float)、字符型(char)。在此基礎上按層次可產生各種構造類型,如數組、指針、結構體、共用體等。同時還提供了用戶自定義數據類型。用這些數據類型可以實現復雜的數據結構,如棧、鏈表、樹等。因此,C 語言具有較強的數據處理能力。
5.C 語言具有預處理能力。在 C 語言中提供了#include 和#define 兩個預處理命令實現對外部文件的包含以及對字符串的宏定義。同時還具有#if~#else 等條件編譯預處理語句。這些功能的使用提高了軟件開發的工作效率并為程序的組織和編譯提供了便利。
6.C 語言可移植性好。目前,C 語言在許多機器上實現,大部分是由 C 語言編譯移植得到的。C 編譯程序的可移植性,也就使 C 語言程序便于移植。
C 語言的優點很多,但也有一些不足。如語法限制不太嚴格、類型檢驗太弱、不同類型數據轉換比較隨便,這就要求程序員對程序設計的方法和技巧更熟練,以保證程序的正確性。
總之,C 語言已成為國內外廣泛使用一種編程語言,它不僅是面向過程的程序設計語言中功能最強、效率最高的語言,更是面向對象程序設計語言 C++、Java 和 C#的基礎,并且非常適合用于程序設計語言課程的教學工作中。
1.3
簡單的 C 語言程序 學習 C 語言的關鍵是要把握程序設計的思想,反復實踐,培養自己獨立編寫程序的能力。下面通過幾個簡單的 C 程序實例介紹 C 語言程序的基本結構和編寫方法,使讀者對 C語言程序有一個初步的認識。
例 例 1.1
編寫 C 語言程序,實現在屏幕上顯示字符串“This is a C program.”。
具體程序如下:
/* ex1_1.c 在屏幕上輸出字符串 */ #include "stdio.h"
void main(void) {
printf("This is a C program.\n"); } 運行結果:
This is a C program. 說明:
1.這是一個完整的 C 語言程序。C 語言程序結構一般由注釋、編譯預處理和程序主體組成。
2./* …… */部分為注釋語句。注釋是程序員為讀者作的說明,不影響程序的執行。注釋一般分為兩種:序言注釋和注解性注釋。前者用于程序開頭,說明程序或文件的名稱、用途、編寫時間、編寫人員以及輸入輸出說明等;后者用于程序中難于理解的部分加以解釋說明。
注釋使程序變得清晰,能幫助讀者閱讀和理解程序,提高程序的可讀性。給程序加注釋是一個良好的編程習慣。C 語言注釋部分由“/*”開始,至“*/”結束,應括在/* …… */之間,/和*之間不允許留有空格。注釋部分允許出現在程序中的任何位置上。注釋可占多行,但不允許在/* …… */中間又出現/* …… */注釋,即不允許嵌套。
3.其中以“#”開頭的語句是預處理命令。這些命令是在編譯系統翻譯代碼之前需要由預處理程序處理的語句。本例中的#include 稱為文件包含預處理命令。
#include "stdio.h"的作用是在編譯之前請求預處理程序將文件 stdio.h 的內容增加(包
含)到程序 ex1_1.c 中來,以作為程序的一部分。文件 stdio.h 是系統定義的一個頭文件,它為輸入和輸出提供支持,在本程序中的 printf("This is a C program.\n");語句的執行需要 stdio.h的支持,沒有它,程序將不能通過編譯系統的翻譯。
4.void main(void)表明以下是一個 C 程序的主函數,每一個 C 程序都必須有一個 main()函數,main()是程序的入口。main 前面的 void 表示該 main()函數沒有返回值。用{}括起來的部分是函數體。描述一個函數所執行算法的過程稱為函數定義。例如,此程序中的 main()函數頭和函數體構成了一個完整的函數定義。
5.printf()是 C 語言提供的標準輸出庫函數,它的功能是將一對雙引號中的內容(稱為字符串常量)輸出到標準輸出設備顯示器上。“\n”是換行符,即在輸出字符串“This is a C program.”后回車換行。printf()后的分號是語句的結束符,C 語言程序的每一個語句必須以分號“;”結束。
例 例 1.2
編寫程序,從鍵盤輸入兩個實數,計算并輸出這兩個實數平方之和的平方根。
具體程序如下:
/* ex1_2.c 計算兩個實數平方之和的平方根 */ #include "stdio.h" # include "math.h" void main(void) {
double x,y,s;
/* 定義 x,y 和 s 三個雙精度實型變量 */
printf("Input two real numbers: "); /* 輸出一行提示信息 */
scanf("%lf%lf",&x,&y);
/* 用標準輸入函數輸入兩個實數,賦值給 x 和 y */
s=sqrt(x*x+y*y);
/* 計算2 2y x ? ,并將計算結果賦給變量 s */
printf("s= %lf\n",s);
/* 將 s 變量的值輸出到屏幕上*/ } 運行輸入:
Input two real numbers:
3.0
4.0 <回車> 運行結果:
s=5.000000 說明:
1.當運行該程序時,首先,屏幕上顯示一條提示信息:
Input two real numbers: 此時用戶從鍵盤輸入兩個數。如果此時用戶輸入 3.0 和 4.0,即 Input two real numbers:
3.0
4.0 <回車> 帶下劃線部分是由用戶輸入的,輸入<回車>以示輸入結束。此時屏幕顯示運行結果(s=5.000000)。
2.該程序從 main()開始運行。double x,y,s;是數據類型說明語句,把 x、y 和 s 定義為雙精度實型(double)變量,double 是類型說明符。值得注意的是,所有 C 語言程序中的變量,必須在聲明其數據類型之后才能使用,以便給變量分配相應的內存空間,用來存放變量的值。
3.printf("Input two real numbers: ");輸出語句的作用是在屏幕的當前光標位置處顯示輸入提示,提醒用戶需要從鍵盤輸入兩個實數。
4.scanf("%lf%lf",&x,&y);是輸入語句,其中 scanf()是 C 語言提供的標準輸入庫函數,它的功能是把用戶從鍵盤上輸入的數據傳送給對應的變量;“%lf%lf”是輸入輸出的格式說明字符串,用來指定輸入輸出時的數據類型和格式,%lf 是用于輸入雙精度實型數據的格式
說明符。輸入輸出函數在第 2 章中介紹。
程序執行 scanf("%lf%lf",&x,&y);時,屏幕將等待輸入,直到用戶從鍵盤輸入兩個實數,兩個數之間用空格分隔,最后以輸入回車結束,這樣用戶輸入的兩個實數就分別賦給了變量x 和 y。
5.s=sqrt(x*x+y*y);是賦值語句,用于將表達式 sqrt(x*x+y*y)的計算結果賦值給變量 s。其中*是乘號,sqrt()是求平方根函數,它是在 math.h 頭文件中聲明的標準庫函數,因此要使用該函數就要在程序前面加上# include "math.h"。
6.printf("s= %lf\n",s); 是輸出語句,它先在新的一行上輸出字符串“s=”,然后按實型數據格式(%lf)輸出變量 s 的值,并使光標移到下一行。執行輸出時,%lf 的位置會被后面對應的表達式的值所取代,即輸出 s 的值。
1.4
函數 C 語言是函數型語言,函數是構成 C 語言程序的基本單位。
雖然 main()也是函數,但它是一個特殊的函數。大多數函數是在程序運行時被調用,當程序執行到函數調用語句時,程序暫停主調函數的執行,而去執行被調函數,當被調函數執行完畢時,程序控制立即返回到主調函數中執行調用函數的下一行代碼,繼續程序的執行。此過程可比喻為查字典,當你在看書時遇到一個不認識的字,于是,就停止閱讀,去查字典,字典查完后,又接著看書。
當程序需要服務時,它可以調用函數實現所需要的服務,然后當函數返回時再從它原來的地方繼續執行。
例 例 1.3
設計一個整數加法器,通過調用該加法器,計算兩數之和。
具體程序如下:
/* ex1_3.c 計算兩個整數之和 */ #include "stdio.h" int add(int x,int y);
/* 函數聲明 */
void main()
/* 主函數 */ {
int a,b,sum;
/* 定義 a,b 和 sum 三個整型變量 */
printf("Input two integers: ");
/* 輸出一行提示信息 */
scanf("%d,%d",&a,&b);
/* 輸入兩個整數,賦值給 a 和 b */ sum=add(a,b);
/* 調用函數 add(),將得到的值賦給變量 sum */
printf("sum=a+b=%d\n",sum);
/* 屏幕輸出 sum 變量的值 */
}
int add(int x,int y)
/* 定義 add 函數和形式參數 x,y */
{
int z;
/* 定義 z 變量 */
z=x+y;
/* 變量 x 與 y 相加的和值賦給 z */ return(z);
/* 返回 z 的值,通過 add()帶回到調用處 */
}
運行輸入:
Input two integers: 10,20<回車> 運行結果:
sum=a+b=30
說明:
1.該程序采用了函數調用來計算兩數之和。此程序由兩個函數組成:主函數 main()和用戶自定義函數 add()。main()函數負責數據的輸入和輸出;add()函數負責將 x 與 y 相加的和值賦給變量 z,并將變量 z 的值返回到主函數 main()中,即兩個函數共同合作完成任務。
2.int add(int x,int y);是函數聲明語句。在 C 語言程序中,一個函數必須在函數聲明后才能使用(被調用)。函數聲明告訴編譯器,該函數是存在的,后面編譯器在看到該函數被調用時就不會產生錯誤,同時編譯器還對函數調用進行正確性檢查。
3.sum=add(a,b); 為函數調用語句。add()函數調用使程序執行 add()函數中的語句,并將該函數的返回值賦給變量 sum。
4.關于函數的說明:
add()函數是求兩個整數之和,然后將結果返回給調用它的函數。因此,在函數頭部要寫有 int(整型)返回類型。如果一個函數不需要返回值,則可以像主函數 main()那樣,在頭部聲明為 void(空類型)。
函數定義由函數頭和函數體構成。函數頭又由函數類型、函數名、參數類型和參數名構成。“int add(int x,int y)”就是函數頭。函數體是由緊隨函數頭之后的大括號“{……}”部分構成。
函數頭部的函數參數允許向函數傳遞值。add()函數中的 x、y 就是函數的參數。參數聲明時要指出其類型。add()函數中的參數聲明為“int x,int y”,它指出 x 和 y 的類型都是整型。
函數參數分為形式參數和實際參數。函數定義中的參數稱為形式參數,簡稱形參。add()函數中的 x、y 就是形參。調用函數時實際傳遞的值稱為實際參數,簡稱實參。主函數 main()調用 add()函數使用的 a、b 就是實參。執行函數調用時,將實參值復制給形參,使得形參變量也具有實參的值。實參可以是表達式,它代表賦值一方;形參只能是變量,因為它要接受賦值。此程序在執行調用 add()函數時,將實參 a 和 b 的值分別傳遞給 add()函數中的形參 x和 y,add()函數收到數據后,對它們進行計算,將結果放入變量 z 中,并通過 return(z);語句將結果變量 z 的值返回給主函數。
函數頭部有返回值類型說明時,函數體中一般要用 return 語句返回值,同時,return 語句也使函數退出。如果函數體中沒有 return 語句,函數將在結尾處自動無值返回。如果有返回值,則該返回值應該具有函數頭中聲明的返回類型。add()函數中執行 return(z);語句時,即返回一個 int 型值到主函數 main()中。
函數分為標準庫函數和用戶自定義函數。上例中的 add()函數是用戶自定義函數,scanf()函數和 printf()函數都是標準庫函數(簡稱庫函數)。庫函數是 C 系統提供的,可以為任何程序所使用。庫函數無需用戶聲明和定義,但要將含有其函數聲明的頭文件包含到程序中。
一個 C 語言程序由一個主函數和若干個其他函數組成。由主函數調用其他函數,其他函數也可以相互調用。同一個函數可以被一個或多個函數調用任意多次。
函數定義包含函數聲明,所以可以將函數定義放在函數聲明的位置,即將用戶自定義函數的定義放在主函數 main()之前。主函數 main()可以放在程序中的任意位置。
例 例 1.4
從鍵盤輸入兩個整數,求其中較小數,并輸出結果。
具體程序如下:
/* ex1_4.c 輸出兩個數中較小數 */ #include "stdio.h" int min(int x,int y)
/* 定義 min()函數,x,y 為形參 */
{
/* 函數體開始 */ int z;
/* 定義函數中使用的變量 z */ if(x<y) z=x;
/* 條件語句:如果 x 小于 y 那么把 x 的值賦給 z */
else
z=y;
/* 否則把 y 的值賦給 z */ return(z);
/* 將 z 的值返回,通過 min()帶回調用處 */
}
/* 函數體結束 */ main()
/* 主函數 */
{
/* 函數體開始 */
int a,b,c;
/* 定義三個整型變量 a,b 和 c */ printf("Input two integers: ");
/* 輸出一行提示信息 */
scanf("%d,%d",&a,&b);
/* 用標準輸入函數輸入兩個整數,賦值給 a 和 b */
c=min(a,b);
/* 調用 min()函數,將函數返回值賦給變量 c */
printf("min=%d\n",c);
/* 輸出變量 c 的值 */
}
/* 函數體結束 */ 運行輸入:
Input two integers: 6,9<回車> 運行結果:
min=6
說明:
本程序包括主函數 main()和被調用的函數 min()。min()函數定義放在主函數 main()之前,此時,函數定義的同時也是函數聲明。
程序從主函數 main()開始運行。程序執行 scanf()時,操作員由鍵盤輸入兩個整數值分別存放到變量 a 和 b 中。程序執行 c=min(a,b);時,調用 min()函數,將 a 的值傳送給 x,b 的值傳送給 y,程序轉到 min()函數執行,min()函數中的 if 語句的作用是將 x 變量和 y 變量中的較小值賦給 z 變量。return 語句的作用是將 z 變量的值返回給 min()函數同時程序返回主函數main()執行,min()函數值再送給 c 變量。最后 printf()將 c 變量的值輸出到屏幕。
通過以上幾個實例,可以看到 C 語言程序的結構有如下特點:
1.C 語言程序是由函數組成的
C 語言源程序由若干個函數組成,函數是 C 程序的基本組成單位。組成程序的若干函數中必須有且僅有一個名為 main 的函數。例 1.3 中包含兩個函數:
main()和 add()。因為在main()函數中調用 add()函數,所以 main()為主函數,add()為被調用的函數。被調用函數可以是系統提供的庫函數(例如 printf()函數),也可以是用戶根據需要自己定義的函數(例如例1.3 中的 add()函數)。一個 C 程序可以包含零個或多個用戶自定義函數。
2.C 語言函數由函數頭部和函數體兩部分組成
?。?)
函數的頭部
這部分包括函數類型、函數名、參數類型和參數名。
如例 1.3 中 add()函數的說明部分:
int
add
( int
x ,
int
y )
↓
↓
↓
↓
↓
↓
函數類型
函數名
參數類型
參數名
參數類型
參數名
函數類型是函數返回值的類型,函數名后必須有一對圓括號(),這是函數的標志,參數可有可無,如 main()函數無參數。如果有參數,放在圓括號中,如 int add(int x,int y)。
參數類型的說明也可以放在圓括號外,例如:
add(x,y)
int x,y;
這種參數類型的說明形式是傳統的函數說明形式,和放在圓括號中的參數說明形式 int add(int x,int y)作用一樣。
?。?)
函數體
函數體由緊隨函數頭部之后的大括號括起來的部分組成,其中的語句序列實現函數的預定功能。注意,一個函數內如果有多對大括號,則最外層的一對大括號中的內容為函數體的范圍。
函數體一般包含說明語句和可執行語句兩部分。說明語句部分一般包括變量定義、自定義類型定義、自定義函數說明、外部變量說明等,其中變量定義是主要的;可執行語句部分一般由若干條可執行語句構成。例如,在例 1.3 的 main()函數中的 int a,b,sum;是說明語句(變量定義)部分,其余 4 條語句是可執行語句部分。
函數體中的說明語句必須放在所有可執行語句之前。如果不需要說明語句,也可以缺省說明語句部分,如例 1.1 中,主函數 main()的函數體就缺省了說明語句部分。
3.main()函數
C 程序必須有 main()函數,習慣上稱其為主函數。C 語言程序總是從 main()函數開始執行,并且在 main()函數中結束。
main()函數可以在整個程序的任意位置,通常我們總是把main()函數放在程序中其他函數的前面。
4.C 語言本身沒有輸入輸出語句
輸入和輸出的操作是由庫函數 scanf()和 printf()等函數來完成的。C 語言對輸入輸出實行“函數化”。
1.5
C 語言 程序的 調試 學習程序設計,上機實踐是非常重要的。在計算機上運行程序,從結果中了解程序的運行過程,進而了解程序的結構,比只看書要有效得多。另外,上機可以提高程序設計的興趣,也可以對已有的程序做各種修改,進而學習更多的知識。
1.5.1
調試步驟 C 語言的翻譯程序屬于編譯系統。要完成一個 C 程序的調試,要經過編輯源程序文件(*.c)、編譯源程序生成目標程序文件(*.obj)、連接目標程序與有關的庫函數形成可執行文件(*.exe)和運行可執行程序 4 個步驟。從紙上編寫好的一個 C 語言程序到可以在計算機上執行該程序的調試過程如圖 1-3 所示。
圖 1- 3
C 語言程序上機調試過程示意圖 第 1 步:編輯。啟動 C 語言集成開發系統,進入源程序文件的編輯狀態??梢愿鶕枰斎牖蛐薷脑闯绦?。編輯完成后,保存源程序文件,源程序文件的擴展名為.c。
此外,也可以用任何其他的編輯器來編輯源程序,如 Windows 的寫字板、記事本、Word等等,要注意的是 C 源程序的存儲格式必須是文本文件,在保存時要選擇文件類型為文本文件。
第 2 步:編譯。編譯是將已生成的 C 語言源程序文件和預處理生成的中間文件轉換為機器可識別的目標程序(即二進制代碼),目標程序文件的主文件名與源程序文件的主文件名相同,擴展名為.obj。
在編譯過程中,編譯程序會自動對源程序進行語法和語義分析,并報告出錯行和原因。如有錯誤,用戶必須重新修改源程序文件,所有錯誤修改完后,再進行編譯,如此反復,直到沒有編譯錯誤為止。
第 3 步:連接。編譯成功后,要將生成的目標程序與所指定的庫函數連接為一個整體,從而生成可執行文件??蓤绦形募闹魑募c源程序文件的主文件名相同,擴展名為.exe。
第 4 步:運行。在 CPU 的控制下,逐條執行裝入內存的可執行文件,并將運行結果顯示在顯示器上。如果運行的結果達到預期的目標,則說明程序編寫正確,否則,就需要進一步檢查修改源程序,重復上述步驟,直到得到正確的運行結果為止。
1.5.2
常用的 C 語言 集成開發環境 C 語言程序的開發在特定的集成開發環境下進行,有功能強大的集成開發環境的支持,使 C 語言程序的開發工作變得更輕松。集成開發環境(Integrated Development Environment,開始 編輯 編譯成功 連接 結果正確 運行 是 是 結束 否 否 源程序 目標程序 可執行程序
庫函數
IDE)是一個將編輯器、編譯器、連接器、調試器以及其他建立應用程序的多種工具集成在一起用于開發應用程序的軟件系統。它可以使程序員從源程序的編輯到最后的運行均可在集成環境中完成。
適合 C 語言的集成開發環境有多種,如 Turbo C、Microsoft C、Visual C++、Dev C++、Borland C++、C++ Builder、Gcc 等。這些集成開發工具各有特點,分別適合于 DOS 環境、Windows 環境和 Linux 環境,幾種常用的 C 語言開發工具的基本特點和所適合的系統環境如表 1-1 所示。
表 1-1
常用的 C 語言集成開發工具 開發工具 運行環境 各工具的差異 基本特點 Turbo C DOS 不能開發 C++語言程序 (1)符合 ANSI C (2)各系統具有一些擴充內容 (3)能開發 C 語言程序(集程序編輯、編譯、連接、調試、運行于一體)
Microsoft C DOS Borland C DOS Visual C++ Windows 能開發 C++語言程序 Borland C++ DOS 、Windows Dev C++ Windows C++ Builder Windows Gcc Linux 除表中列出的集成開發工具外,另外還有一些小型的集成開發工具也比較適合于學習者使用,如 Turbo C/C++ for Windows,它支持 C、C++、Windows C 等程序的編輯、編譯、調試和運行。
本書中的 C 語言源程序都是在 Microsoft Visual C++ 6.0 環境下開發的。
1.5.3
Visual C++ 6.0 集成 開發 環境 Visual C++ 6.0 集成開發環境作為一種功能強大的程序編譯器被相當多的程序員所使用,使用 Visual C++也可以完成 C 語言的編譯運行。由于 Visual C++集成開發環境運行于Windows 下,對于習慣于圖形界面的用戶來說是比較易學的,本小節簡要介紹一下如何用Visual C++來完成 C 語言程序設計。
1.啟動 Visual C++ 6.0 單擊“開始”按鈕,選擇“程序”菜單中的“Microsoft Visual C++ 6.0”子菜單,然后單擊“Microsoft Visual C++ 6.0”,就可以啟動 Visual C++ 6.0 集成開發環境。如果已在桌面上建立了該快捷方式,則可以在桌面上雙擊“Microsoft Visual C++ 6.0”快捷圖標以進入系統。
2.Visual C++ 6.0 的工作界面 啟動系統后,即可進入 Visual C++ 6.0 工作界面,如圖 1-4 所示。Visual C++ 6.0 工作界面由標題欄、菜單欄、工具欄、工作區窗口、編輯窗口、輸出窗口和狀態欄組成,分別介紹如下。
?。?)標題欄:主窗口的最上端是標題欄,標題欄用于顯示應用程序名和所打開的文件名。
?。?)菜單欄和工具欄:標題欄的下面是菜單欄和工具欄,用于提供用戶操作的命令接口。菜單以文字和層次化的方式提供命令接口;工具欄由一系列命令按鈕組成,使用方便,默認情況下,標準工具欄自動打開,包含文件操作、編輯操作等常用的 15 個按鈕。
?。?)工作區窗口:主窗口的左側是項目工作區窗口,工作區窗口用來顯示所設定的工作區的信息。Visual C++ 6.0 以項目管理程序,每一個程序都應該屬于一個項目,如果一個程序由多個文件組成,則這些文件都在同一個項目中,因此項目名與文件名可以不同。當打開一個項目時,工作區窗口將會顯示關于當前項目的文件、類以及資源的信息。
?。?)編輯區窗口:主窗口的右側是編輯區窗口,用來輸入和編輯源程序。Visual C++ 6.0允許同時打開多個文件,用戶可以選擇其中一個作為當前編輯的文件。
?。?)輸出窗口:主窗口的下面是輸出窗口,輸出窗口主要用于顯示項目建立過程中生成的錯誤信息,還可以通過選擇不同的標簽顯示其他信息。
?。?)狀態欄:主窗口的最底端是狀態欄,給出當前操作或所選擇命令的提示信息。
圖 1-4
Visual C++ 6.0 工作界面 3.Visual C++ 6.0 的編輯器 Visual C++ 6.0 的編輯器能夠使程序員快速高效地編制程序,其特點如下。
?。?)自動語法:用高亮度和不同顏色的文字顯示不同的語法成分。
?。?)自動縮進:幫助排列源代碼,增強程序的可讀性。
?。?)參數幫助:在輸入系統提供的標準庫函數時,將自動顯示該函數的參數信息。
?。?)集成的關鍵字幫助:能夠快速得到任何關鍵字、MFC 類或 Windows 函數的幫助信息。
?。?)拖放編輯:能夠用鼠標選擇文本并自由拖動到任意位置。
?。?)自動錯誤定位:能夠自動將光標移動到有編譯錯誤的源代碼處。
編輯 C 語言程序文件時,要注意保存時必須給出源文件的擴展名.c,否則,系統會自動給出擴展名為.cpp。
4.Visual C++ 6.0 的調試器 標題欄 菜單欄 工具欄 欄 工作區窗口 編輯區窗口 輸出窗口 狀態欄
調試器是 Visual C++ 6.0 集成環境中最出色的組件之一,它幾乎可以幫助找到程序開發中可能產生的所有錯誤,正確熟練地使用調試器,是每一個程序開發人員的必備技能。
調試器的主要調試方法有設置斷點(Breakpoints)、跟蹤(Trace)和觀察(View)。所謂斷點是指在源程序的某代碼行前加一個標記,設置斷點的目的是告訴調試器運行到此行代碼時暫停執行,以使程序員能夠觀察程序中的變量、表達式、調試輸出信息以及內存、寄存器和堆棧的值,進而了解程序的運行情況,...