第9章C語言與程序設計補遺_第1頁
第9章C語言與程序設計補遺_第2頁
第9章C語言與程序設計補遺_第3頁
第9章C語言與程序設計補遺_第4頁
第9章C語言與程序設計補遺_第5頁
已閱讀5頁,還剩127頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第第9章章 C語言與程序設計補遺語言與程序設計補遺 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.1 變量的存儲類別與生命期 9.2 指向函數的指針變量 9.3 帶參數的主函數main 9.4 編譯預處理命令 9.5 枚舉類型 9.6 位運算 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.1 變量的存儲類別與生命期變量的存儲類別與生命期 1. 生命期的概念生命期的概念 從變量生命期(即由創(chuàng)建到撤消)來分,可以將變量分為 靜態(tài)存儲變量和動態(tài)存儲變量兩類: (1) 靜態(tài)存儲變量:在程序運行時固定分配存儲空間的 變量。 (2) 動態(tài)存儲變量:在程序運行中根據需要動態(tài)分配存 儲空間

2、的變量。 程序運行時對應的內存分配示意如圖9-1所示。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 圖9-1 程序運行時對應的內存分配示意 第第9章章 C語言與程序設計補遺語言與程序設計補遺 全局變量和靜態(tài)局部變量(static變量)存放在靜態(tài)數據 區(qū),程序開始執(zhí)行時給它們分配內存單元,程序執(zhí)行結束時 再釋放這些內存單元。也即在程序的整個執(zhí)行過程中這些變 量都存在(有自己的內存單元),它們的生命期為程序的整個 執(zhí)行過程。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 動態(tài)數據區(qū)存放自動局部變量、形參變量和用于中斷現 場的保護數據。自動局部變量是指未加staic聲明的局部變量; 形

3、參變量是指函數的形參。在函數調用時為自動局部變量和 形參變量在動態(tài)數據區(qū)分配內存單元,當函數執(zhí)行結束時釋 放這些內存單元。也即在函數的整個執(zhí)行過程中這些變量都 存在,它們的生命期為函數的整個執(zhí)行過程。 在C語言中,每個變量都有兩個屬性:數據類型和數據 的存儲類別。前面各章節(jié)中,我們在定義變量時只涉及它的 數據類型,其實還可以定義變量的存儲類別,它決定這個變 量的存放位置(是靜態(tài)數據區(qū)還是動態(tài)數據區(qū))和生命期。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 變量定義的一般形式如下: 存儲類別 類型標識符 變量名; 其中,方括號“ ”中的內容為可選項。 C語言中的變量可以有4種存儲類別:自動

4、變量、寄存器 變量、靜態(tài)變量和外部變量,分別用存儲類別auto、register、 static和extern。下面僅對自動變量、寄存器變量和靜態(tài)變量 進行介紹。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 2. 自動變量 在函數體內或復合語句內定義變量時,如果沒有指定存 儲類別或使用了“auto”存儲類別,則系統(tǒng)都認為所定義的變 量為自動局部變量,簡稱為自動變量。此外,函數首部中的 形參也是自動變量。例如: auto int a=2,b; int a=2,b; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 上述兩種定義方法是等價的,即都定義了a和b為自動變 量。每當進入函數體或

5、復合語句時,系統(tǒng)在動態(tài)數據區(qū)為自 動變量分配臨時內存單元,退出時自動釋放這些內存單元; 再次進入函數或復合語句時,系統(tǒng)又為它們重新分配臨時內 存單元,退出時又自動釋放這些內存單元。因此,釋放后自 動變量的值不可能保留,這類變量的作用域及生命期只存在 于定義它的函數體內或復合語句內。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 自動變量在動態(tài)數據區(qū)分配內存單元,并隨著程序的運 行可能不斷釋放和重新分配內存單元,也即這個內存單元的 位置是不固定的,因此自動變量中的值也會隨之改變。所以, 自動變量在使用之前必須賦值,否則它的值是不確定的。此 外,在不同函數中使用的同名自動變量也不會相互影響。

6、 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.1 分析下面程序的運行結果。 #include void fun(); void main() fun(); fun(); void fun() int n=2; /*自動變量*/ n+; printf(n=%dn,n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 在程序中,函數fun中定義的n為自動變量,其作 用域只在函數fun內。第一次調用fun時,為n分配臨時內存單 元且n的初值為2,執(zhí)行“n+;”后n值為3,因此輸出結果為3; 第一次調用fun結束,此時分配給n的內存單元被釋放。第二 次調用fun時,又為n重新分

7、配了內存單元,函數fun的執(zhí)行過 程與第一次一樣,因此輸出的結果仍是3。程序執(zhí)行的動態(tài) 圖如圖9-2所示。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 圖9-2 程序執(zhí)行的動態(tài)圖 第第9章章 C語言與程序設計補遺語言與程序設計補遺 程序執(zhí)行后的輸出結果為: n=3 n=3 第第9章章 C語言與程序設計補遺語言與程序設計補遺 3. 寄存器變量 寄存器變量也是自動變量,它與一般自動變量的區(qū)別在 于,寄存器變量的值是存儲于CPU內的寄存器中,而一般的 自動變量則存儲于內存中。由于從寄存器中讀取數據要比從 內存中讀取數據的速度快,所以為了提高運算速度,可以將 一些頻繁使用的局部變量或形參變量定

8、義為寄存器變量。寄 存器變量只要在定義時加上存儲類別register即可。例如: register int a; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 使用寄存器變量時要注意以下幾點: (1) 寄存器變量本身是一個自動變量,因此只有函數內 定義的變量或形參才可以定義為寄存器變量。 (2) CPU中的寄存器個數有限,所以只能將少數的變量 定義為寄存器變量。 (3) 受寄存器長度的限制,寄存器變量只能是char、int和 指針類型的變量。 (4) 由于寄存器變量是保存在CPU的寄存器中而不是保存 在內存中,因此不能進行取地址運算。 (5) 在調用函數時,函數中的寄存器變量才占用寄存器

9、 存放其值,當函數調用結束時就釋放寄存器,也即寄存器變 量消失。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.2 編寫求n!的程序。 解 程序如下: #include long fac(int n); void main() int n; long f; printf(Input n=); scanf(%d, f=fac(n); printf(%d!=%ldn,n,f); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 long fac(int n) register long t=1; register int k; for(k=2;k=n;k+) t=t*k; retur

10、n (t); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 運行結果: Input n=5 5!=120 在程序中,由于函數fac中的變量t和k頻繁使用,故將其定義 為寄存器變量。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 4. 靜態(tài)變量 靜態(tài)變量的存儲空間為內存中的靜態(tài)數據區(qū),該區(qū)域中 的數據在整個程序運行期間一直占用分配給它們的存儲空間, 直到整個程序結束。 特別要注意的是,函數體內如果在定義靜態(tài)變量(稱為局 部靜態(tài)變量)的同時進行了初始化,則以后程序不再對其進行 初始化操作。這是由于第一次遇見局部靜態(tài)變量時,系統(tǒng)即 為局部靜態(tài)變量分配了專用的內存單元并將初始化值送入這 個

11、內存單元,此后該局部靜態(tài)變量就一直使用這個內存單元, 而無論函數的調用或結束;也即,下一次函數調用時,這個 局部靜態(tài)變量仍然使用這個內存單元,而且并不重新初始化。 這樣,局部靜態(tài)變量就可以保存前一次函數調用得到的值而 用于下一次函數調用;這一點是局部靜態(tài)變量與自動變量的 本質區(qū)別。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 局部靜態(tài)變量的初值是在程序編譯時賦予的,在程序執(zhí) 行過程中不再賦值。對沒有賦初值的局部靜態(tài)變量,編譯系 統(tǒng)自動給它賦初值0。 auto型局部變量與static型局部變量的區(qū)別如表9.1所示。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 表表9.1 auto

12、型局部變量與型局部變量與static型局部變量的區(qū)別型局部變量的區(qū)別 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.3 分析下面程序的運行結果。 #include void fun(); void main() fun(); fun(); void fun() static int n=2; /*局部靜態(tài)變量*/ n+; printf(n=%dn,n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 在程序中,函數fun中定義的n為局部靜態(tài)變量;其 作用域只在函數fun內。在程序執(zhí)行開始前,系統(tǒng)已為n分配 了內存單元且n的初值為2,第一次函數fun調用時,執(zhí)行 “n+;”

13、后n值為3,輸出3;第一次調用fun函數結束,但系統(tǒng) 分配給n的內存單元并不釋放。第二次調用fun時,執(zhí)行 “n+;”后n值由3變?yōu)?(注意,不執(zhí)行對靜態(tài)局部變量的初 始化操作static int n=2),故輸出結果為4。所以,程序執(zhí)行后 的輸出結果為: n=3 n=4 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.4 分析下面程序的運行結果。 #include int fun(int x,int y); void main() int j=4,m=1,k; k=fun(j,m); printf(%d,k); k=fun(j,m); printf(%dn,k); 第第9章章 C語

14、言與程序設計補遺語言與程序設計補遺 int fun(int x,int y) static int m=0,i=2; i=i+m+1; m=i+x+y; return m; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 程序執(zhí)行的動態(tài)圖如圖9-3所示。 圖9-3 程序執(zhí)行的動態(tài)圖 第第9章章 C語言與程序設計補遺語言與程序設計補遺 由于靜態(tài)局部變量在每次函數調用結束時并不消失,所 以在動態(tài)圖中,我們將靜態(tài)局部變量m和i放置于函數fun空間 的開始處,并且當函數fun結束時,它們仍然存在(在動態(tài)圖 上是用一條橫線將它們與局部自動變量分開,且這條線一直 持續(xù)到程序結束)。在下一次調用函數

15、fun時,仍可使用它們 的值。由動態(tài)圖可知,程序的運行結果為:8,17。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.2 指向函數的指針變量指向函數的指針變量 在C語言中,一個函數所對應的程序代碼總是存放在一 段連續(xù)的內存區(qū)域內,并且像數組名代表數組的首地址一樣, 函數名就代表該函數代碼所占內存區(qū)域的首地址。不同的函 數有不同的首地址。因此,函數名可以看做為是一個廣義的 變量,我們可以把這個“變量”函數名(函數的首地址) 賦給一個指針變量,使該指針變量指向這個函數,然后通過 指針變量就可以找到并且調用執(zhí)行這個函數。這種指向函數 的指針變量就稱為“函數指針變量”。 第第9章章 C語言

16、與程序設計補遺語言與程序設計補遺 1. 函數指針變量的定義與初始化 函數指針變量定義的一般形式為 類型說明符 (*指針變量名)(); 其中,類型說明符表示被指向的那個函數的返回值類型, “(*指針變量名)”表示“*”后面的變量名是一個指針變量, 最后的空括號“()”表示這個指針變量的指向是一個函數。 例如: int(*p)(); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 定義了p是一個指向函數的指針變量,該函數的返回值 為整型。p是用來存放函數的入口地址的,在沒有賦值前它 不指向任何一個具體函數,并具有一個空指針值。 想要通過函數指針變量來實現對某個函數的調用,還必 須對函數指針變量

17、進行初始化,即將需要調用的某個函數入 口地址賦給它;由于函數名代表該函數的入口地址,因此是 將某個函數名賦給函數指針變量。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 函數指針變量初始化的方式有兩種:一種是直接賦值; 一種是加地址運算符“ 或者 函數指針變量名= 也可以在函數指針變量定義時進行初始化: 類型說明符 (*指針變量名)(形式參數表)=函數名; 或者 類型說明符 (*指針變量名)(形式參數表)= 第第9章章 C語言與程序設計補遺語言與程序設計補遺 函數的指針變量與普通指針變量都能實現間接訪問, 其唯一的區(qū)別是:普通指針變量指向的是內存的數據存儲區(qū), 而函數的指針變量指向的是內

18、存的程序代碼區(qū)。因此,普通 指針變量的“*”運算是訪問內存中的數據,而函數的指針 變量執(zhí)行“*”運算時,其結果是使程序控制轉移到由函數 指針變量所指向的函數入口地址,并開始執(zhí)行該函數。此外, 形式參數表也與第5章函數中的形式參數表不同,只能給出 形參的類型。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 2. 用函數指針變量調用函數 定義了函數指針變量并初始化后,就可以在程序中通過 函數指針變量來調用所需要的函數了。調用函數的一般形式 為 (*指針變量名)(實參表) 由于優(yōu)先級不同,所以“*指針變量名”必須用圓括號 “( )”括起來,表示間接調用指針變量所指向的函數,而后面 的圓括號“(

19、 )”中的內容為傳遞給被調函數的實參。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.5 用函數指針調用函數的方式實現在兩數中找出最 大數的程序。 #include int max(int a,int b); void main() int (*p)(int,int); int x,y,z; p=max; printf(Input two numbers:n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 scanf(%d,%d, z=(*p)(x,y); printf(max=%dn,z); int max(int a,int b) if(ab) return (a);

20、else return (b); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 運行結果: Input two numbers: 88,66 max=88 第第9章章 C語言與程序設計補遺語言與程序設計補遺 從程序中可以看出,用函數指針變量形式調用函數的步 驟如下: (1) 先定義函數指針變量;如程序中的“int (*p)(int,int); 語句”。 (2) 將被調函數的入口地址(即函數名)賦給函數指針變量; 如程序中的“p=max;”語句。 (3) 用函數指針變量形式來調用函數;如程序中的 “z=(*p)(x,y);”語句。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.

21、6 分析下面程序運行的結果。 #include float f1(float n); float f2(float n); void main() float (*p1)(float),(*p2)(float),(*t)(float),y1,y2; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 p1=f1; p2=f2; y1=p2(p1(2.0); t=p1;p1=p2;p2=t; y2=p2(p1(2.0); printf(%3.0f,%3.0fn,y1,y2); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 float f1(float n) return n*n; floa

22、t f2(float n) return 2*n; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 程序中,函數f1實現的是返回參數值的平方值, 函數f2實現的是返回參數值的2倍。在主函數main中定義了三 個函數指針變量p1、p2和t,語句“p1=f1;p2=f2;”讓函數指針 變量p1指向函數f1,函數指針變量p2指向函數f2,然后調用 “p2(p1(2.0)”,即先讓2.0平方后再乘以2,即結果為8并賦給 變量y1。接下來,語句“t=p1;p1=p2;p2=t;”交換了p1和p2的 指向,即此時p1指向f2,p2指向f1。再次調用“p2(p1(2.0)”, 則是先讓2.0乘以2然

23、后再平方,即結果為16并賦給y2。因此, 最后輸出的y1和y2值為:8,16。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 使用函數指針變量還應注意以下幾點: (1) 函數指針變量不能進行算術運算,這與數組指針變 量不同;數組指針變量加減一個整數可以使指針移向后面或 前面的數組元素,而函數指針的移動則毫無意義。 (2) 函數指針變量定義時“(*指針變量名)”的圓括號“( )” 不能缺省,有了括號指針變量名先和“*”結合,表示定義的 變量名是一個指針變量。如果缺省了圓括號“( )”,即如下面 所示: int *p(int,int); 則表示定義的p是一個函數;p為函數名,其前面的“*”

24、表示函數p是返回指針值的函數,也即意思和功能完全不同 了。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (3) 要注意函數指針變量與指向二維數組的指針變量 之間的區(qū)別。如:“int (*p)(int);”和“int (*p)4;”,前者是函 數指針變量,后者是指向二維數組的指針變量。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 3. 函數的指針變量作為函數的參數 函數的形參可以是各種類型的變量,也可以是指向函數 的指針變量。形參是指向函數的指針變量時可以接受實參傳 來的不同函數,這種參數傳遞不是傳遞任何數據或普通變量 的地址,而是傳遞函數的入口地址。當函數參數在兩個函數 之間傳

25、遞時,調用函數的實參應該是被調函數的函數名,而 被調函數的形參應該是接受函數地址的函數指針變量。 例9.7 任意輸入兩個整數,求它們的和、差、積、商。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 程序設計如下: #include int add(int x,int y); int sub(int x,int y); int mul(int x,int y); int div(int x,int y); int fun(int(*p)(int ,int),int x,int y); void main() 第第9章章 C語言與程序設計補遺語言與程序設計補遺 int a,b; prin

26、tf(Input a,b=); scanf(%d,%d, printf(%d+%d=%dn,a,b,fun(add,a,b); printf(%d-%d=%dn,a,b,fun(sub,a,b); printf(%d*%d=%dn,a,b,fun(mul,a,b); printf(%d/%d=%dn,a,b,fun(div,a,b); int add(int x,int y) return x+y; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 int sub(int x,int y) return x-y; int mul(int x,int y) return x*y; int di

27、v(int x,int y) return x/y; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 int fun(int(*p)(int ,int),int x,int y) int z; z=(*p)(x,y); return z; 運行結果: Input a,b=12,4 12+4=16 12-4=8 12*4=48 12/4=3 第第9章章 C語言與程序設計補遺語言與程序設計補遺 程序中的add、sub、mul和div是已經定義過的函數,函 數fun中的形參p是函數指針變量,主函數main調用fun函數: fun(add,a,b) 則將函數add的入口地址傳給了函數指針變量p,而

28、a、b 值分別傳給了形參x、y;即函數fun中的語句“z=(*p)(x,y);” 此時相當于語句“z=add(x,y);”,從而實現了對a與b的求和; 其他函數調用也是如此。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.3 帶參數的主函數帶參數的主函數main 前面各章介紹的主函數main都是不帶參數的,因此main 后的括號是空括號“()”。實際上主函數main是可以帶參數的, 這個參數可以認為是主函數main的形參。C語言規(guī)定主函數 main的參數只能有兩個:argc和argv,并且第一個形參argc必 須是整型變量,第二個形參argv必須是指向字符串的指針數 組。也即,主函數

29、main的一般形式為: 第第9章章 C語言與程序設計補遺語言與程序設計補遺 void main (int argc,char *argv) 函數體 其中,argc稱做參數計數器,它的值是包括命令名在內的參 數個數,因此其值至少為1;argv指針數組的作用是存放命令 行中命令名及每個參數字符串的首地址。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 由于主函數main是最先執(zhí)行的,因此不可能在程序內 部獲得實參值。所以,主函數main的實參值是從操作系統(tǒng)的 命令行上獲得的。當需要運行一個可執(zhí)行文件時,在DOS提 示符下鍵入文件名及實參值,即可把這些實參傳給main的形 參。 帶參數的主函數

30、main的調用形式如下: 可執(zhí)行文件名 參數1 參數2 參數n 第第9章章 C語言與程序設計補遺語言與程序設計補遺 上面這一行字符稱為命令行,是在DOS系統(tǒng)提示符下鍵 入的。其中,可執(zhí)行文件名稱為命令名,其后的參數稱為命 令行參數,命令名與各參數之間用空格分隔。例如: c:file1 China Beijing 由于命令名file1本身也算是一個參數,所以共有三個參 數,因此argc的值取3,argv指針數組中元素的值為命令行中 各字符串(參數均按字符串處理)的首地址。指針數組的大小 即為參數個數;數組元素的初值由系統(tǒng)自動賦予。上述命令 行參數在賦給帶參主函數main中的argv指針數組后示意

31、見圖 9-4。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 圖9-4 帶參主函數main中的argv示意 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例如,在c盤根目錄下的文件file1.c的內容如下: #include void main(int argc,char *argv ) while(argc1) +argv; printf(%sn,*argv); argc-; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 用VC+ 6.0中的工具欄Build中的Build命令先將file1.c生 成可執(zhí)行文件file1.exe(保存于Debug子目錄中),其后再將 file

32、1.exe由Debug目錄移至c盤根目錄下,然后點擊桌面上 “開始”按鈕中的運行框并輸入。 c:file1 China Beijing 則輸出為: China Beijing 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.8 有以下程序: #include #include void main(int argc,char *argv ) int i,len=0; for(i=1;iargc;i=i+2) len=len+strlen(argvi); printf(%dn,len); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 經編譯鏈接后生成的可執(zhí)行文件是ex.exe,若運

33、行時輸 入以下帶參數的命令行: ex abcd efg h3 k44 則執(zhí)行后輸出的結果是 。 A) 14 B) 12 C) 8 D) 6 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 本題的argv示意如圖9-5所示,argc的值為5。在主 函數main中,for循環(huán)執(zhí)行了兩次;當i=1時, len=0+strlen(argv1),argv1=abcd;故此時len值為4。當 i=3時,len=4+strlen(argv3),其中argv3=h3,故此時len 值為6。當i=5時,退出循環(huán)。所以最后輸出的len值為6,即 應選D項。 第第9章章 C語言與程序設計補遺語言與程序設計補

34、遺 圖9-5 argv示意 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.4 編譯預處理命令編譯預處理命令 預處理是C語言所具有的一種對源程序處理的功能。所 謂預處理,就是指在正常編譯之前對源程序進行預先處理。 也即,源程序在正常編譯之前先執(zhí)行源程序中的預處理命令 進行預處理,然后再編譯源程序。通常把預處理看做編譯的 一部分,是編譯中最先執(zhí)行的部分。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 預處理功能包含了一組預處理命令,不同的預處理命令 實現不同的功能;最常使用的是文件包含命令和宏定義,在 調試程序時也可使用條件編譯命令。 預處理命令都是以“#”開頭,每個預處理命令必須

35、單獨 占一行,并且未尾不加分號(這就是命令與語句的區(qū)別)。預 處理命令可以出現在程序的任何地方,但一般都將預處理命 令放在源程序的首部,其作用域從預處理命令在程序中該命 令說明的位置開始到程序的結束。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 預處理命令參數是一種替換功能,這種替換功能只是簡 單的替代,不做語法檢查;例如,宏定義就是用定義的字符 串來替代宏名;又如,文件包含命令就是一個用文件內容替 代被包含的文件名;這樣的替代目的是為了使程序的書寫更 加簡潔。 C語言提供的預處理命令有宏定義、文件包含和條件編 譯。下面只對宏定義和文件包含這兩個命令進行介紹。 第第9章章 C語言與程序

36、設計補遺語言與程序設計補遺 9.4.1 宏定義命令宏定義命令 C語言中,允許用一個標識符來表示一個字符串,稱之 為宏。宏是一種編譯預處理命令,被定義為宏的標識符稱為 宏名。在編譯預處理時,程序中所有出現的宏名都用宏定義 中的字符串去替換,稱為宏代換或宏展開。 注意,宏定義是由程序中的宏定義命令完成的,而進行 宏代換的操作則是由預處理程序在編譯之前自動完成的,根 據是否帶參數將宏定義分為不帶參的宏定義和帶參宏定義。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 1. 不帶參數的宏定義 不帶參數的宏定義一般形式如下: #define 標識符 字符串 其中,define是關鍵字,它表示宏定義命

37、令;標識符為所定 義的宏名,它的寫法應符合C語言標識符的規(guī)則;字符串可 以是常數、表達式及格式串等。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例如: #define PI 3.14159 #define SUM 10+20 #define NL printf(n) #define TRUE 1 這里,PI、SUM、NL、TRUE都是宏名,而3.14159、10+20、 printf(n)和1都是被定義的字符串。宏定義是將PI、SUM、 NL、TRUE分別定義為3.14159、10+20、printf(n)和1;替 換時,將程序中出現的PI、SUM、NL和TRUE分別用對應的 字符串

38、替換。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.9 利用如下公式計算圓周率的近似值,直到最后一項的 絕對值小于(=10-7)。 解 程序如下: #include #include #define Epsilon 1e-7 void main() 第第9章章 C語言與程序設計補遺語言與程序設計補遺 int i,m=1,sign=1; double pi=4,t=4; for(i=1;fabs(t)Epsilon;i+) sign=-sign; m+=2; t=sign*4.0/m; pi+=t; printf(pi=%fn,pi); 第第9章章 C語言與程序設計補遺語言與程序設

39、計補遺 運行結果: pi=3.141593 2. 帶參數的宏定義 帶參數的宏定義的一般形式如下: #define 標識符(形參表) 字符串 其中,括號“()”中的形參表由一個或多個形參組成,當形參 多于一個時,形參之間用逗號隔開,對帶參數的宏展開也是 用字符串替換宏名,而形參則被對應的實參替換,其他的字 符仍然保留在字符串內。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 帶參宏調用的一般形式如下: 宏名(實參表) 例如: #define s(a,b) a*b c=s(x+y,x-y); 宏調用時,用x+y替換形參a,用x-y替換形參b,其余字 符不變,即“*”仍保留在字符串內。經預處理

40、宏展開后的 語句為: c=x+y*x-y; 注意,定義帶參數的宏時,宏名與括號“( )”之間不得有 空格。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 帶參的宏和函數有相似之處,但它們在本質上是不同的: (1) 函數調用時先求實參表達式的值,然后將該值傳遞 給對應的形參;而帶參數的宏展開時,只是用實參字符串替 換對應的形參。 (2) 函數調用是在程序運行中進行的,當調用到這個函 數時才為函數的形參分配臨時內存單元并接受實參的值;而 宏展開是在編譯之前進行的,不分配內存單元也不進行值傳 遞,更沒有返回值。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (3) 函數中要求實參和形參都

41、要定義數據類型,且二者 的類型應一致,否則應進行類型轉換;而宏名沒有類型,并 且所帶參數也沒有類型,展開時用指定的字符串替換宏名即 可,并且宏定義時的字符串可以是任何類型的數據。 (4) 函數調用不會使源程序的長度發(fā)生變化,而宏展開 可以使源程序的長度發(fā)生改變。 (5) 函數調用要占用運行時間,而宏展開是在編譯之前 處理的,不占用運行時間。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.10 分析下面程序的運行結果。 #include #define HDY(A,B) A/B #define PRINT(Y) printf(y=%dn,Y) void main() int a=1,

42、b=2,c=3,d=4,k; k=HDY(a+c,b+d); PRINT(k); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 在主函數main中,“K=HDY(a+c,b+d);”語句在宏 展開后為“K=a+c/b+d;”,運行后K被賦值為1+3/2+4=6,而 “PRINT(K);”展開后為“printf(y=%dn,k);”故輸出結果為: y=6。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.11 有以下程序 #include #define N 5 #define M N+1 #define f(x) (x*M) void main() 第第9章章 C語言與程序

43、設計補遺語言與程序設計補遺 int i1,i2; i1=f(2); i2=f(1+1); printf(%d,%dn,i1,i2); 程序運行后的輸出結果是 。 A) 12,12 B) 11,7 C) 11,11 D) 12,7 第第9章章 C語言與程序設計補遺語言與程序設計補遺 解 宏替換只是字面上的替換,在編譯之前完成。程 序中第1條要替換的語句“i1=f(2);”展開后是“i1=(2*M);”, 再展開為“i1=(2*N+1);”,最后展開為“i1=(2*5+1);”,結果 是i1的值為11。而第2條要替換的語句“i2=f(1+1);”,展開后 是“i2=(1+1*M);”,再展開為“i

44、2=(1+1*N+1);”,最后展開為 “i2=(1+1*5+1);”,結果是i2的值為7。故應選B。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.4.2 文件包含命令文件包含命令 文件包含是指將指定文件中的內容嵌入到當前源程序 文件中,文件包含命令的一般形式為: #include 或 #include 文件名 其功能是:在編譯預處理時把“文件名”所指的文件內容嵌 入到當前的源程序文件中,然后再對嵌入后的源程序文件進 行編譯。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 對于第1種由尖括號“”括住文件名的文件包含命令, 這種方式告訴編譯預處理程序,被包含的文件存放在C編譯

45、系統(tǒng)所在的目錄下。該方式適用于嵌入C系統(tǒng)提供的頭文件, 因為C系統(tǒng)提供的頭文件都存放在編譯系統(tǒng)所在的目錄下。 對于第2種用雙引號“ ”括住文件名的文件包含命令, 編譯預處理程序首先到當前文件所在的文件目錄下查找被包 含的文件,如果找不到再到編譯系統(tǒng)所在的目錄下查找。當 然,也可以在文件名前給出路徑名,直接告訴編譯預處理程 序被包含文件所在的確切位置。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 在使用文件包含命令時應注意以下幾點: (1) 一個#inlude命令只能包含一個文件,如果要包含多 個文件,就得用多個文件包含命令。 (2) 文件包含可以嵌套,即在一個被包含的文件中又可 以包含

46、另一個文件。如文件1包含文件2,而文件2又要用到 文件3的內容,可在文件1中用兩個#indule命令分別包含文件 3和文件2,并且文件3的包含命令應在文件2的包含命令之前, 這樣文件1和文件2都能使用文件3的內容。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (3) 被包含的文件2與其所在的文件1,經過預處理后成 為一個文件即文件1,而不是兩個文件。因此,在文件2中定 義的全局變量此時在文件1中有效,即無需使用extern聲明。 (4) #include命令用于包含擴展名為.c的源程序文件或擴 展名為.h的“頭文件”。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.12 計

47、算xy。 解 文件filel.c中的內容 #include #include d:cfile2.h /*指明要包含文件file2.c的 完整路徑*/ int main() int x,y; double power(int,int); /*函數聲明*/ printf(Input x,y:); scanf(%d,%d, printf(%d*%d=%fn,x,y,power(x,y); return 0; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 d盤C目錄下file2.h文件中的內容為; double power(int m,int n) int i; double y=1.0; fo

48、r(i=1;i=n;i+) y*=m; return y; 運行結果為: Input x,y:2,10 2*10=1024.000000 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.13 用包含排序文件的方法實現從高分到低分輸出學 生成績。 解 文件px.c如下: void sort(int x,int n) /*選擇排序文件*/ int i,j,k,t; for(i=0;in-1;i+) k=i; for(j=i+1;jn;j+) 第第9章章 C語言與程序設計補遺語言與程序設計補遺 if(xkxj) k=j; if(k!=i) t=xi;xi=xk;xk=t; 第第9章章 C語

49、言與程序設計補遺語言與程序設計補遺 文件cj.c如下: #include #include px.c void main() int num,score50,k; printf(Input num=); /*輸入班級人數*/ scanf(%d, printf(Input score of student:n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 for(k=0;knum;k+) scanf(%d, /*輸入學生 成績*/ sort(score,num); for(k=0;knum;k+) printf(%4d,scorek); /*從高到低輸出學 生的成績*/ if(k+1)

50、%10=0) printf(n); printf(n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.14 現有兩個C程序文件T1.c和myfun.c同在TC系統(tǒng)目錄 (文件夾)下,其中T1.c文件如下: #include #include myfun.c void main() fun(); printf(n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 myfun.c文件如下: void fun() char s20,c; int n=0; while(c=getchar()!=n) sn+=c; n-; while(n=0) printf(%c,sn-); 第第9

51、章章 C語言與程序設計補遺語言與程序設計補遺 當編譯鏈接通過后,運行程序T1時,輸入Thank! 求輸 出的結果。 解 本題源程序相當于: #include void fun(); void main() fun(); printf(n); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 void fun() char s20,c; int n=0; while(c=getchar()!=n) sn+=c; n-; while(n=0) printf(%c,sn-); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 從程序來看,主函數main只調用了一次函數fun,然后輸 出一個回車換

52、行符n。所以,程序的重點在函數fun。函數 fun中有兩個while循環(huán),第1個while語句 “while(c=getchar()!= n) sn+=c;”的作用是: 第第9章章 C語言與程序設計補遺語言與程序設計補遺 從鍵盤上讀入字符到變量c,若讀入的不是回車換行符 n,就將它存入數組s。n為數組s的下標,用來控制字符順 序放入數組s中。所以當第1個while語句結束時,s數組放入 了“Thank!”,而n則是下一個將要放入字符的數組元素下標。 接下來的“n-;”語句,使n退回到字符為“!”的下標值。第2 個while語句“while(n=0) printf(%c,sn-);”,則由數組s

53、中 的字符“!”開始由后向前(由語句“n-;”控制)直至第1個字符 “T”為止,逐個字符進行輸出,所以輸出的結果即為輸入字 符串的逆序:!KnahT。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 9.5 枚舉類型枚舉類型 枚舉表示一類數據的個數有限,即可窮舉。枚舉類型是 一類有限離散的符號數據量的集合。例如:真假、性別、星 期、時辰、職稱、年級等。而實型則不是這樣,實型數據是 連續(xù)的、無法窮舉的。C語言引入了枚舉類型,即在枚舉類 型定義中列舉出所有可能的取值,被說明為該枚舉類型的變 量只能取定義中列舉出來的值。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 由于C語言沒有像PAS

54、CAL語言那樣提供集合的并、交、 差運算和判斷某元素是否屬于某個集合的屬于運算等,所以 C語言中的枚舉類型的功能有限,在程序中很少使用。 1. 枚舉類型和枚舉變量的定義 定義枚舉類型的一般形式為: enum 枚舉類型名 枚舉常量名表 ; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 其中,enum是關鍵字,稱為枚舉類型定義標識符;枚舉常量 名表形式如下: 標識符1,標識符2,標識符n 這些標識符不得重名,它們表示的是枚舉類型定義中所有可 能出現的枚舉值,因此是枚舉常量。例如: enum weekday sun,mon,tue,wed,thu,fri,sat ; 定義了一個枚舉類型enum

55、 weekday,它有7個枚舉常量。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 枚舉變量如同結構體變量和共用體變量一樣,也可以有 三種定義形式: (1) 先定義枚舉類型再定義枚舉變量。例如: enum weekday sun,mon,tue,wed,thu,fri,sat ; enum weekday a,b,c; (2) 在定義枚舉類型的同時定義枚舉變量。例如: enum weekday sun,mon,tue,wed,thu,fri,sat a,b,c; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (3) 直接定義枚舉變量。例如: enum sun,mon,tue,wed

56、,thu,fri,sat a,b,c; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 使用枚舉類型時應注意以下幾點: (1) 枚舉變量的取值范圍限定在枚舉類型定義時的枚舉 常量名表內,即不得出現枚舉常量名表以外的標識符。 (2) 枚舉常量只是一個標識符,不能與變量混淆,即不 得用賦值語句給枚舉常量標識符賦值。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (3) 枚舉常量(標識符)本身是有值的。枚舉類型定義時, 每個枚舉常量(標識符)的值就確定了,即按定義時出現的順 序依次為0、1、2、;如上面枚舉類型enum weekday 中, sun的值為0、mon的值為1、。枚舉常量(標識

57、符)的值可以 輸出,但枚舉常量即標識符不能直接輸出。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (4) 也可以在定義時強制改變枚舉常量的值。例如: enum weekday sun,mon=3,tue,wed,thu,fri,sat a,b,c; 則sun的值為0,而mon的值為3,其后的枚舉常量值順序加1, 即tue的值為4、wed值為5、。 第第9章章 C語言與程序設計補遺語言與程序設計補遺 (5) 若要將整數值賦給枚舉變量必須作強制類型轉換。例如: a=(enum weekday)0; 這相當于: a=sun; (6) 枚舉常量由于本身有值,所以可以比較大小,也可以作 為循環(huán)控

58、制變量。例如: if(amon) 或者: for(a=mon;a=sat;a+) printf(%2d,a); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 2. 枚舉變量的使用 枚舉變量的值只能用賦值語句獲得,不能用scanf函數直 接讀入枚舉常量(即標識符)。通常是先輸入一個整數,然后 再通過switch語句給枚舉變量賦值。例如: enum weekday sun,mon,tue,wed,thu,fri,sat workday; scanf(%d, switch(n) 第第9章章 C語言與程序設計補遺語言與程序設計補遺 case 0: workday=sun; case 1: wor

59、kday=mon; case 2: workday=tue; case 3: workday=wed; case 4: workday=thu; case 5: workday=fri; case 6: workday=sat; 第第9章章 C語言與程序設計補遺語言與程序設計補遺 此外,也不能通過printf函數直接輸出枚舉變量的值 標識符形式的枚舉常量,枚舉變量的值通常也是通過switch 語句以字符串形式輸出對應的信息。例如: swith(workday) case sun: printf(Sundayn); case mon: printf(Mondayn); case tue: pri

60、ntf(Tuesdayn); case wed: printf(Wednesdayn); case thu: printf(Thursdayn); case fri: printf(Fridayn); case sat: printf(Saturdayn); 第第9章章 C語言與程序設計補遺語言與程序設計補遺 例9.15 已知一個不透明的布袋中裝有紅、藍、黃、綠、 紫色圓球各一個,現從中一次抓出兩個,問可能抓到的兩個 球都有哪些顏色組合。 解 分析見例6.11。本題采用枚舉變量求解。程序如下: #include enum color red,blue,yellow,green,purple ;

溫馨提示

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

評論

0/150

提交評論