計算機系統是由硬件系統和軟件系統構成,硬件由IBM、HP、DLL、Acer以及聯想這樣的工廠製造出來,叫裸機。軟件由微軟、Oracle以及用友等公司的程序員用計算機語言編寫出來的,叫程序。程序和編寫該程序的文檔一塊兒構成了軟件系統。裸機安裝上了操做系統就構成了第一層虛擬機,計算機軟硬件資源由操做系統來管理。在操做系統之上安裝應用軟件,就構成第二層虛擬機,用戶通常與這層計算機打交道的。應用軟件提供一個輸入數據的界面,用戶經過這個界面將要加工的原始數據(文字、數值 、聲音、圖片、圖形、動畫、電影等)輸入給這個軟件,而後它的加工部分對數據進行交換,最後將計算結果輸出給用戶。程序員
軟件是被記錄下來的思惟的邏輯推理過程,是計算機硬件的「學歷」,是計算機系統的靈魂。沒有安裝軟件的裸機就像是一臺接收不到電視信號的電視同樣,其「本事」不能被挖掘出來。所以,硬件的價值與安裝到其上的軟件功能成正比,人們藉助軟件間接地讓硬件「勞動」。算法
計算機硬件的製造如今能夠實現批量生產了,但軟件的開發還須要人來寫,目前還不能現讓計算機來編寫軟件。用來寫軟件的計算機語言多達2000種,C語言能在衆多計算機語言中脫穎而出,靠的就是既能寫系統軟軟件又能寫應用軟件的特長。系統軟件通常直接與硬件打交道,編寫難度大。應用軟件是用來解決特定領域的數據加工問題的。如今一般的作法是用C開發一個系統軟件,而後用這個系統軟件開發應用軟件例如用C開發出的VFP 系統,用戶使用VFP 系統開發其領域的應用軟件,如考場安排系統,成績管理系統以及售票系統等。框架
1.1 用C 寫程序的思想框架函數
下面給出第一個C程序,命名爲c1.c, C源程序的擴名爲c。動畫
main () // main函數的功能是調用其餘函數,給其傳遞數據,並接收傳來的數據。spa
{void drawsomething (char, int); // 對該函數進行聲明操作系統
drawsomething (' ', 2); 調試
drawsomething('#', 1); printf ("\n"); //括號內參數是實參接口
drawsomething(' ', 1); 圖片
drawspmething('#', 3); printf ("\n") //實參之間用逗號分隔
drawsomething(' ', 0);
drawsomething ('#', 5); printf("\n"); //字符常量用單括撇括起
} // 分號是語句的標誌,少了它就變成了表達式了。
/*下面函數的功能是輸出n個由參數c 指定的字符*/
viod drawsomething(char c, int n) // c 和 n 是形式參數,簡稱爲形參,char 即 character.
{ int i; // 定義變量i 是integer 型, C規定變量必須先定義,後使用。
for (i=0; i<n; i++) printf ("c%", c) //循環n次,每次輸出一個字符。
} // for 循環中的分號是分隔符。第三章會講到,同一符號在不一樣上下文中含義迥然。
由/*&*/ 括起來的部分是C和C++的多行註釋語句,// 是C++的註釋語句。本書全部程序都是在Turbo C++3.0 IDE (Integrated Development Evironment)下調試和編譯。註釋語句也叫內部文檔,通常分兩種:一種是放在源碼的最前面,對該程序進行總體註釋,介紹其功能,I/O接口中參數的含義、權限要求、算法的簡單描述,調用了哪些函數、編者、建立日期、修改日期以及審覈日期;另外一種是行間註釋,對可能引發歧義的語句進行說明。
該程序由main和drawingsomething 兩個函數構成,每一個函數完成一個特定的功能。 一個程序有且只有一個main 函數,mian函數是程序的入口函數,其位置任意。程序老是從main函數開始執行, main 函數執行完了,整個程序也就執行完了。因此,在拿到一個要進行數據變換的問題後,首先要作的就是將要解決的問題分解爲若干功能單一的函數,以使每一個函數都有「一技之長」。接下來main函數按照輸入數據、變換數據、輸出數據的順序調用相應的函數,由其完成具體的任務。固然函數之間能夠相互調用,但不能調用main函數。這就是用C解決數據加工問題的思惟框架。
經過上面的示例能夠看出,一個函數由函數首部和用花括號括起來的函數體兩部分組成。
函數首部由函數返回值類型、函數名(類型 形參、類型 形參,...)構成。 上面的main函數沒有形參,叫無參函數,沒有返回值類型,默認爲int 型,沒有返回值語句,則執行完該函數後系統返回一個隨機數。 drawsomething 函數的返回值類型是viod, 說明不能有返回值。 形參是定義函數時的形式參數,必須是變量,實參是調用函數時的實際參數,必須有明確的值。 調用時,按從右到左(TC++是這樣的,但Fortran等語言按從左向右的順序)的順序將實參的值賦給形參,因此要求實參和形參的類型、個數、順序要對稱,不然是編譯不經過,或者是計算結果不正確。如今讓咱們故意犯個錯誤,將main函數第3行的,2去掉,編譯後給出「too few parameters in call to 'drawsomething' in function main」的提示,將實參2改成2.9 ,運行結果不變,由於形參n是整數,它只要整數的部分。
函數內要先寫局部變量定義,被調函數聲明、判斷、循環、賦值、 return等語句。函數體也能夠是空語句,即只有一個函數首部後跟一對花括號,叫空函數。根據C的思惟框架結構,咱們在處理一個大的任務時,首先要作的是將大任務分解爲小任務,如此分解下去,直到每一個小任務只有一個功能,咱們暫時就用這個空函數表明這個小任務,待分解合理了,任務之間的關係理順了,再把空函數爲真正的函數,而後上機調試、編譯爲EXE文件,就能夠做爲軟件使用了。如,求兩個正整數的最大公約數和最小公倍數,能夠分解爲以下三個函數:
int max(int, int){} // max 函數負責求最大公約數,返回值類型是int型。
min (int, int) {} // min 函數負責最小公倍數,省略了返回值類型。
void main () {} //負責接收待求數,調用max和min,接收其返回值,最後輸出結果。
下面細化後的三個函數:
int max (int bcs, int cs) // bcs是被除數的拼音字母縮寫,cs表明除數。
{ int yushu; // yushu表明餘數,zdgys 表明最大公約數,zxgbs表明最小公倍數。
while(cs != 0) // while 循環結構,讀做當條件爲真時,執行循環體,而後返回到
{yushu=bcs/cs; //條件處繼續判斷,當條件仍爲真時,繼續執行循環體,如此循環,
cs=yushu; //當條件爲假時,跳出循環,繼續執行後繼語句
bcs=cs; //當循環體語句多於一條時用{}括起來,構成複合語句;其功能至關於一條語句。
} // 下面的return語句是上面循環結構的後繼語句
return (bcs): // 將加工結果返回調用處, return後面的圓括號能夠省略。
} //將源代碼寫成鋸齒狀的目的是加強程序的可讀性,程序的結構層次清淅,一目瞭然。
min(int bcs, int cs)// 形參是局部變量,與生活中的臨時工相似。
{int zdgys=max(bcs, cs); // 在定義局部變量的同時調用max函數,其返回值賦之。
return bcs*cs / zdgys; // 先計算,在返回結果。
}
void main () // 無參函數,且不能有返回值,有返回值也不容許使用它。
{ int bcs=26, cs=4; // 定義局部變量的同時,給其賦值。
int zdgys=max (bcs, cs) // 調用max 函數,並將其返回值給zdgys。
int zxgbs=min (bsc, cs) // 調用min函數,並將其返回值給zxgbs。
printf ("\n max=%d, min=%d\n", zdgys,zxgbs); //輸出結果
return 6; // 6可略,寫上此句不算錯,讀者可編寫一個使用此返回值的程序,編譯。
} // 時會給出「not an allowed typ in function function name」的提示。
在TC++系統的IDE中輸入源碼,保存爲c2.c, 也能夠在相似於NotePad這樣的文本文件編緝器中輸入源碼,而後在TC++系統中打開,編譯經過後,生成c2.obj(Object)二進制碼文件,再和庫函數Link成可獨立執行的c2.exe(execute)機器碼文件。 能夠到XP的命令提示符下運行,輸入結果爲Max=2, Min=52。
爲何要把具備某一功能的一段程序稱爲函數呢? 仔細剖析Max這段程序能夠看出,其功能是將傳進來的兩個正整數(自變量、其全部可能的值構成定義域)通過必定的變換規則加工爲最大公約數(因變量,其全部的值構成的值域), 稱這段程序爲函數是比較恰當的。
若被調用函數處於調用函數以前,或函數的返回值類型是int型,聲明語句能夠省略。上面的min函數直接調用了max函數就是這個緣由。函數的聲明,也能夠直接寫在全部函數以前,程序的開始部分。下面的程序c3,c就是這樣。
long power (int, int); // 函數的聲明放在全部函數以前,可沒必要聲明而直接調用。
void main ()
{ int a=2, b=8; // 16位計算機int型變量佔2字節,取值範圍-32768~32767
printf ("result is:%ld\n", power (a,b); // %ld表示此處放一個長整型數,l 即long
} //d 即decimal, \n 表示 換行。
long power (int x, int n) // long int 型中的int 可省略,該函數的功能是求Xn 。
{int i ; // 定義局部變量,也叫自動變量,用auto修飾,能夠省略。
long result=1; // 16 位計算機int型變量佔4個字節,取值範圍-2147483648~2147483647 。
for (i=0; i<n; i ++) // for 循環結構,循環n次。
result*=x // 與result = result*x等價,但前者更簡潔。
return result;
}
爲什麼printf函數沒有聲明,也不見其函數體,用戶也沒有編寫這個函數,卻能夠拿來直接調用呢?緣由是它是庫函數。庫函數是由C系統開發人員事先寫好並編譯成二進制代碼後保存到庫文件中,並隨系統一塊兒提供的。庫函數通常完成和硬件直接打交道的底層功能,或複雜計算。前結如輸出結果的printf函數,將鍵盤輸入的數據送入到內存指定的scanf 函數, 清屏函數clrscr 等, 後者如sqrt、 sin 函數等。因爲printf、 scanf 、 clrscr 函數使用頻繁, TC++編譯系統直接使用它們而沒必要聲明,其餘函數在使用前仍需聲明,但與用戶自定義函數的聲明方法略有不一樣,程序c4.c 說明了這種差別。
#include <math.h> // 包含命令,下面三個庫函數首部信息保存在這個頭文件中。
viod ,main() // 庫函數sin ()、 log10 () , sqrt () 的返回結果做爲printf () 的實參。
{printf ("sin(3)=%lf,"sin(3)) // 求3的正弦, l 便是long, f 即 float。
printf ("log10(10) = %lf," ,log10(10) ) //求 log10(10) , lf 表示雙精度數。
printf ("5's square root is = %lf\n", sqrt (5)); // 求5的平方根
} // 輸出結果爲sin(3)= 0.14120, ,log10(10) =1.000000, 5's square root is:2.236068 。
# include <math.h> 是編譯預處理命令,編譯預處理命令(不能叫語句)不是C 語言的組成部分,但倒是C編譯系統的重要組成部分,使用它主要是爲了提升程序的可讀性。全部編譯預處理命令都以#號開頭且後面緊跟define, undef, pragma 等命令,命令結束處勿寫分號。
在正式編譯這段程序前,編譯預處理程序找到math.h文件(該文件是一個文本文件,保存在安裝文件下include 文件夾中),並將其內容複製一份粘貼到該命令處以取代該命令,而後編譯器對經編譯預處理後的程序進行編譯、鏈接、生成可執行文件。 *. h (h 即head)文件通常稱爲頭文件,這些文件中包含有庫函數的首部信息和系統定義的常量、類型等。程序中用到庫函數時,須將相應的頭文件寫入程序的開始部分,以便在進行編譯預處理時,將這些文件的內容包含進來。
順便提一下,<math.h>也能夠寫做「math.h」。 用雙撇時,編譯處理程序先去當前文件所在的文件夾下尋找,若找不到,再到系統配置文件所指定的文件夾中查找,查找用戶自定義文件通常採用這種方法。用尖括號時,編譯預處理程序直接到系統配置文件所指定的文件夾中查找,查找系統自帶的文件通常採用這種方法。