首頁>技術>

第一部分 "C 語言基礎知識"知識點

1、C 程式的基本結構 C程式是由函式構成的。每個程式由一個或多個函式組成,其中必須有且僅有一個主函式main( )。 main 函式是一個可執行 C 語言程式的入口和正常出口,而不論其在整個程式中書寫的位置如何。 在 C 語言中,大小寫字母是有區別的。(例如習慣使用小寫字母定義變數,用大寫字母定義常量)。 C 程式的註釋有兩種方法,一種是行註釋,使用"//";另外一種是塊註釋,使用"/* */",注意

"/*"與"*/"不能巢狀使用。 C 語言書寫較為靈活,但是提倡採用縮排格式進行程式書寫,以體現語句之間的層次感。 C 程式每條語句以"分號"作為結束標誌。以下幾種情況不得使用分號:

(1) 所定義的函式名稱後不得使用分號; (2) if…else…語句是一個整體,中間不能使用分號將其分隔開; (3) 預編譯命令後不能使用分號。

2、C 程式開發步驟

C 語言在計算機上的開發過程主要由以下四個步驟組成: 第一步:編輯。生成字尾名為".c"的原始檔 第二步:編譯。生成字尾名為".obj"的目標檔案 第三步:連線。生成字尾名為".exe"的可執行檔案 第四步:執行。

3、VC++6.0 開發工具的使用

按下功能鍵 Ctrl+F7 編譯程式;按下功能鍵 F7 連線程式;按下功能鍵 Ctrl+F5 執行程式;若程式在編譯和連線過程中有語法錯誤,則按下功能鍵 F4 定位錯誤所在行並根據錯誤提示資訊改正錯誤(原則是先解決 error,再解決 warning)。

4、C 語言中識別符號的命名規則

識別符號由字母、數字、下劃線組成;規定第一個字元必須為字母或下劃線。 識別符號定義的變數名、函式名、常量名等最好做到"見名知義";大小寫代表不同含義;不能使

用關鍵字;最好不要與 C 語言的庫函式同名。

5、C 語言的資料型別

C 語言的資料型別由基本型別和複雜型別構成。其中基本資料型別包括字元型(char)、整型(int,short,long)、實型(float,double);複雜資料型別包括指標型別、陣列、結構體、聯合體。

char 型佔 1 個位元組、short 型佔 2 個位元組、long 型和 float 型佔 4 個位元組、double 型佔 8 個位元組。

6、常量

(1) 字元型常量(用單引號括起來的一個字元) 兩種形式——普通字元、跳脫字元(掌握'\n'、'\0'、'\t'、'\\'、'\''、'\"'、'\ddd'、'\xhh') 不論普通字元,還是跳脫字元,都等價於 0-127 之間的某個整數,即 ASCII 碼錶。

(2) 整型常量 三種表示形式——十進位制形式、八進位制形式(加前導 0)、十六進位制形式(加前導 0x) 注意:C 語言的整型常量沒有二進位制表示形式。

(3) 實型常量 兩種表現形式——小數表示形式、指數表示形式(由"十進位制小數"+"e 或 E"+"十進位制整數"組成,注意:e 或 E 的兩側必須有數,其後必須為整數)

(4) 字串常量(用雙引號括起來的零個或者若干多個字元) 編譯系統會在字串的最後新增'\0'作為字串的結束符。比較'a'和"a"的不同。

(5) 符號常量:例如 #define PI 3.14159

7、變數

變數必須"先定義、後使用"。變數代表計算機記憶體中一定大小的儲存空間,具體代表多少位元組的存

儲空間示變數的型別而定,該儲存空間中存放的資料就是變數的值。 注意:變數定義後如果未賦初值,則變數的初值是隨機數。因此變數應該先賦值再使用才有意義。為

用"char"定義字元型變數,字元型變數存放 1 個位元組的數值。對於無符號字元型變數,取值範圍是 0~255,對於有符號字元型變數,取值範圍是-128~+127。

(2) 整型變數 用"int"、"short"、"long"定義整型變數,其中 int 型和 long 型佔用 4 個位元組的儲存空間,short型佔用 2 個位元組的儲存空間。

(3) 實型變數 用"float"、"double"定義實型變數,其中 float 型佔用 4 個位元組的儲存空間,double 型佔用 8個位元組的儲存空間。

8、表示式

表示式具有廣泛的含義,根據運算子不同,有賦值表示式、算術表示式、邏輯表示式、關係表示式等,甚至單獨的一個常量或一個變數也是一個表示式。

9、運算子

(1) 算術運算子(+、-、*、/、%) 除號(/)——當除數和被除數都為整數時,相除的結果自動取整。 求餘號(%)——要求"%"號的兩側必須是整數,不能是實數。

(2) 賦值運算子( = ) 格式"變數 = 表示式",表示將表示式的值賦值到變數對應的儲存空間裡。 注意:賦值號"="的左側必須是變數,不能是常量或者表示式。

(3) 複合賦值運算子(+=、-=、*=、/=、%=) 由算術運算子和賦值運算子組成,是兩個運算子功能的組合。例如:a += a + c;

例如:++i; 等價於 i++; 等價於 i=i+1; 自增、自減運算子與其它運算子共同存在於表示式中時,放在變數前和變數後有區別。

例如:若定義 int i = 3, j; 則 j = ++i; 語句執行後 i 的值為 4,j 的值為 4。 則 j = i++; 語句執行後 i 的值為 4,j 的值為 3。

(5) 關係運算符(>、<、>=、<=、==、!=) 注意:不能混淆賦值運算子(=)和關係運算符中的等於號(==)。前者是做賦值操作,

後者是判斷兩個數是否相等。

關係表示式的值只有"邏輯真(用數值 1 表示)"和"邏輯假(用數值 0 表示)"兩種情況。

如果表示式的值為實型,不能使用"=="或者"!="判斷兩個值相等還是不相等。 (6) 邏輯運算子(!、&&、||)

運算邏輯表示式時,當參與運算的數"非 0 表示真"、"0 表示假";表示式的解"1 表示真"、"0 表示假"。

注意:"短路特性"的含義。如果邏輯與"&&"運算子左側表示式的值為 0(假),則該運算子右側的表示式被"短路",即運算過程被計算機省略掉;如果邏輯或"||"運算子左側表示式的值為 1(真),則該運算子右側的表示式被"短路"。

(7) 位運算子(~、^、&、|、<<、>>) 只適用於字元型和整數型變數。是 C 語言具有低階語言能力的體現。 注意:不能混淆邏輯與運算子"&&"和按位與運算子"&";邏輯或運算子"||"和按位

或運算子"|";邏輯非運算子"!"和按位取反運算子"~"。 (8) 逗號運算子(,)

功能為從左至右依次計算由逗號隔開的各表示式的值,最後一個表示式的值即為整個逗號

表示式的值。是優先順序最低的運算子。 (9) 條件運算子(? :)

這是 C 語言中唯一的一個三目運算子,其形式為:<表示式 1> ? <表示式 2> :<表示式 3> (10) 求位元組運算子 sizeof

注意:不能混淆求位元組運算子 sizeof 和字串長度庫函式 strlen( )。前者是運算子,後者是函式。sizeof("Hello")的值為 6,而 strlen("Hello")的返回值為 5。

(11) 各種運算子混合運算時的優先順序排隊口決 二、 二、 二、 與、 或、 二、 逗 ! * / % + - > >= < <= == != && || = ,

(12) 資料型別的強制轉換 格式:(轉換型別名)表示式。 注意:型別名兩側的小括號不能省略,表示式示情況而定可以增加小括號。

第二部分 "C 程式的三種基本結構"知識點

如 if 語句、switch 語句、while 語句、do-while 語句、for 語句;非結構化語句,如 break 語句、continue語句、return 語句、goto 語句)。

2、程式的三種基本結構

順序結構、選擇結構、迴圈結構

3、順序結構

(1) printf()函式的使用 難點

一般形式為:printf("格式控制字串",輸出項列表);

其中"格式控制字串"包含三類字元——普通字元(即原模原樣輸出的字元,主要用於做

提示資訊)、格式說明符(以"%"開頭)、跳脫字元(以"/"開頭) 輸出項列表是可以省略的,當"格式控制字串"中沒有"格式說明符"時,輸出項列表省

略;若是有"格式說明符"時,輸出項列表不能省略,並且有幾個格式說明符,輸出項列表

就必須有幾個對應資料型別的表示式,各表示式之間用逗號隔開。 需要掌握的格式說明符有:%c、%d、%f、%s、%u、%o、%x、%ld、%lf、%e、%%

(2) scanf()函式的使用 難點 一般形式為:scanf("格式控制字串",地址列表); 其中"格式控制字串"包含兩類字元——普通字元(需從鍵盤原模原樣輸入的字元,一般

起分隔和提示作用)、格式說明符(以"%"開頭) 地址列表通常是不省略的,根據"格式控制字串"中包含多少個格式說明符,地址列表中就有幾個地址。對於普通變數,需在變數名前加上取地址符"&",陣列名前不需加"&"。 注意 1:scanf()函式的"格式控制字串"中不能包含"跳脫字元",否則將引起輸入無效。如 scanf ("%d\n", &a);是錯誤的。 注意 2:scanf()的格式控制字串中的普通字元不是用來顯示的, 而是輸入時要求照普通字元原模原樣輸入。 注意 3:scanf()中引數的第二部分一定是地址列表,不能是表示式。 注意 4:字元和數值混合輸入且二者中間沒有分隔符,需注意何時加空格。例如:已定義

char x; int y; scanf("%c%d", &x, &y); 此時從鍵盤輸入時,字元和整數之間需加空格; 而 scanf("%d%c", &y, &x); 此時從鍵盤輸入時,整數和字元之間不能加空格。

(3) getchar()函式的使用 函式原型為:char getchar(void); 例如:char a; a=getchar( ); 該函式使用時關注函式的返回值。

(4) putchar()函式的使用 函式原型為:char putchar(char); 例如:putchar('A'); 該函式使用時關注函式的引數。

(5) printf( )、scanf( )、getchar( )、putchar( )這四個函式都屬於標準輸入輸出庫函式,呼叫時需在程式中包含標頭檔案 stdio.h。

(6) 例如已定義:char a, b='A'; 則以下函式呼叫等價

4、選擇結構

scanf("%c", &a); 等價於 a = getchar( ); printf("%c", b); 等價於 putchar(b);

(1) if 語句 if 語句的三種形式——單分支選擇結構、雙分支選擇結構、多分支選擇結構。 單分支選擇結構: if(表示式)

注意:if 語句的表示式很多時候是關係表示式,不要將"=="號誤用成"="號。 說明 1:表示式兩側的小括號不能省略,此表示式可以是 C 語言中任意合法的表示式,只

要表示式的值為非零(真),就執行其後的語句體;否則,結束 if 語句。 說明 2:由於"if(表示式)"和"語句體"是一個整體,在語法上看作一條語句,因此在"(表

達式)"後面不能加";",如果加了分號,則 if 語句的語句體就成了空語句。 說明 3:"if(表示式)"會自動結合一條語句,如果語句體有多於一條語句時,必須使用復

合語句,即用大括號將多條語句括起來。

語句體;

易錯點

易錯點

說明 4:為了表示語句體從屬於 if,書寫時,應使語句體與關鍵字 if 的位置有縮排。 雙分支選擇結構(二選一):

說明 1:表示式只寫在關鍵字 if 的後面,不能寫在 else 的後面。 說明 2:"if"、"語句 1"、"else"、"語句 2"是一個整體,在語法上看作一條語句,因此在

"(表示式)"後面不能加分號,在關鍵字 else 後面也不能加分號。 說明 3:如果"語句體 1"、"語句體 2"有多於一條語句,則必須使用複合語句。 說明 4:書寫時,應使關鍵字 if 和 else 對齊,"語句體 1"和 if 之間有縮排,"語句體 2"

和 else 之間有縮排。 多分支選擇結構(多選一):

說明:表示式一定是跟在關鍵字"if"的後面,不能跟在關鍵字"else"的後面。

if(表示式) 語句體 1;

else 語句體 2;

if(表示式 1) 語句體 1; else if(表示式 2) 語句體 2; … else if(表示式 n) 語句體 n; else 語句體 n+1;

(2) switch 語句 switch(表示式) { case 常量表達式 1: 語句 1; <break;> case 常量表達式 2: 語句 2; <break;> ……

case 常量表達式 n: 語句 n; <break;> 說明 1:關鍵字 switch 後面表示式的值必須是整型或者字元型,不能是實型。 說明 2:關鍵字 case 後面是"常量表達式",只能是常量或常量表達式,不能是變數或者變數

表示式。且表示式的值必須是整型或者字元型,不能是實型和字串。書寫時注意

"case"與"常量表達式"之間必須有空格;"常量表達式"後面是冒號。 說明 3:每個 case 分支後面的常量表達式必須互不相同。 說明 4:每一個分支後面的"break"可以省略,如果省略,則程式繼續執行下一個 case 分支

的語句,否則執行完該 case 分支的語句就跳出 switch 語句。 說明 5:多個 case 分支可以共用一組語句,當某個 case 分支後面省略了語句,則意味著該分支

與它後面緊鄰的分支共用語句。 說明 6:default 可以省略。 說明 7:書寫時必須注意①switch 後面的表示式必須用小括號括起;②表示式的小括號後面不

5、迴圈結構

迴圈結構程式編寫過程中的三要素——迴圈的初始條件、迴圈的終止條件、控制迴圈結束條件的變化。

<default : 語句 n+1;> }

while(表示式) 迴圈體;

重點

(1) while 語句

while 語句構成的迴圈稱為當型迴圈。當表示式的值為非零,則執行迴圈體,否則結束迴圈。 說明 1:表示式可以是 C 語言中任意合法的表示式,書寫時不能省略其兩側的小括

號。 說明 2:"while(表示式)"會自動結合一條語句,如果迴圈體有多於一條語句時,必須使用複合

語句。 說明 3:"while(表示式)"與"迴圈體"是一個整體,"(表示式)"後面不應加分號,否則迴圈

體就成了一條空語句。 (2) do-while 語句 do

迴圈體;

do-while 語句構成的迴圈稱為直到型迴圈。先執行迴圈體,再判斷表示式的值是否為非零,是則繼續下一次迴圈,否則結束迴圈。 說明 1:do 必須和 while 聯合使用。 說明 2:如果迴圈體有多於一條語句時,必須使用複合語句。 說明 3:表示式可以是 C 語言中任何合法的表示式,書寫時其兩側的小括號不能省略,"while(表

達式)"後面的分號也不能省略。 (3) for 語句

說明 1:小括號裡有三個表示式,每個表示式之間用分號隔開。這三個表示式都可以預設,但是應該在其它相應的位置補齊。

說明 2:"表示式 1"也稱為初始表示式,在整個迴圈開始前執行一次;"表示式 2"也稱終止表示式,每輪迴圈進入前執行一次,如果該表示式的值為非零,則執行迴圈體,否則結

束迴圈;"表示式 3"也稱迴圈表示式,每次迴圈結束時執行一次,常用來控制迴圈的初始條件逐漸轉變到終止條件。

說明 3:"for(…)"會自動結合一條語句,當迴圈體有多於一條語句時,必須使用 複合語句。

(4) break 語句 break 語句出現在迴圈體中的作用是提前結束本層迴圈。 break 語句出現在 switch 語句中的作用是跳出本層 switch 語句。

(5) continue 語句 continue 語句只能出現在迴圈體中,其作用是提前結束本輪迴圈,進入下一輪迴圈。即當

continue 語句被執行時,放置在該語句之後的其它語句將被略過。注意:continue 語句並沒有使整個迴圈結束。

6、常用演算法、常用庫函式

(1) 交換兩個變數中存放的數值——使用首尾相接的三條語句。例如:已定義 int a=3, b=4, t; 若要交換 a 和 b 中的數值,使用如下三條語句 t = a; a = b; b = t;

(2) 數學函式(需包含標頭檔案 math.h)——sqrt( )、fabs( )、pow( )、exp( ) (3) 斐波拉契數列 (4) 素數問題 (5) N 項式求和問題 (6) 迭代法

while(表示式);

for(表示式 1; 表示式 2; 表示式 3)迴圈體;

重點, 難點

難點 重點, 難點

第三部分 "陣列、字串"知識點

1、一維陣列 (1)一維陣列的定義形式:型別說明符 陣列名[常量表達式]; 注意:方括號中的"常量表達式"表示該陣列的元素個數。只能是常量,不能是變數或者變量表達式。 說明 1:陣列一旦定義,就在記憶體空間中分配連續存放的若干儲存單元,每一個儲存單元的大小由數

據型別決定。例如有如下定義:int a[10]; 則計算機為陣列 a 連續分配 10 個儲存單元,每個 儲存單元佔用 4 個位元組,總共是 40 個位元組的儲存空間。

說明 2:陣列一旦定義,陣列名就代表了一段連續儲存空間的首地址,陣列名是常量,永遠指向該數 組第一個元素的記憶體單元地址。

(2)一維陣列元素的引用:陣列名[下標] 與一般變數一樣,陣列必須先定義,後使用。陣列元素的引用是指使用已定義陣列中的某個指定元素,

透過"下標"來指定需要引用的元素。 注意 1:下標的下限一定是"0",上限由陣列定義時的常量表達式值決定,為"常量表達式值-1"。

假設已經有如下定義:int a[10]; 則引用該陣列元素的下標範圍是"0~9",若引用時下標超過此範圍,稱為陣列越界,會導致程式執行出錯。

注意 2:必須區分陣列定義時方括號中的"常量表達式"和陣列元素引用時方括號中的"下標",二者具有不同的含義和功能。前者是指明陣列的大小,後者是指明要引用陣列中的第幾個元素。

(3)一維陣列的初始化 與一般變數一樣,陣列定義後,如果沒有為其賦初值,則陣列元素中的初值是隨機數。為陣列元素賦

組長度。 (4)一維陣列元素的輸入、輸出 由於陣列中的元素是若干個相同型別的數值,不能對其進行整體的輸入或者輸出,必須針對單個元素

進行輸入或者輸出,這時就要使用迴圈結構,對於一維陣列來說,使用單層迴圈。

2、二維陣列

(1)二維陣列的定義形式:型別說明符 陣列名[常量表達式 1][ 常量表達式 2]; 說明 1:"常量表達式 1"指明二維陣列的行數,"常量表達式 2"指明二維陣列的列數。 說明 2:二維陣列可以看作特殊的一維陣列,二維陣列元素在記憶體中是"按行存放"。 (2)二維陣列元素的引用:陣列名[行下標][列下標]

說明:與一維陣列一樣,二維陣列元素引用時的行下標和列下標不能越界。假設已經有如下定義:int a[3][4]; 則引用該陣列元素時,行下標的範圍是"0~2",列下標的範圍是"0~3"。

(3)二維陣列的初始化 二維陣列初始化有以下四種方式:①分行全部元素初始化(使用兩層花括號);②分行部分元素初始

部元素賦初值時,可以省略確定行數的常量值。 (4)二維陣列元素的輸入、輸出 使用雙層迴圈巢狀對二維陣列的所有元素進行輸入、輸出。

3、字元陣列與字串

(1)字元陣列與字串的關係 字元陣列是字元型資料的集合。定義方式為:char 陣列名[常量表達式]; 與其它型別的陣列一樣,將

陣列中的各個字元看作是獨立的個體。當這些字元中有'\0'時,可以將它們視為一個整體,即字串。 字串有常量,但是沒有字串型的變數,字串常量使用字元陣列進行存放,前提是字元陣列的大

小要能容納整個字串,包括字串的結束符'\0'。 (2)字元陣列的初始化 當字元陣列中存放的所有字元作為獨立個體時,其初始化方法與其它型別的陣列一樣。當字元陣列中

存放的是字串時,其初始化方法有如下幾種: ① char a[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; ② char a[6] = {"Hello"}; ③ char a[6] = "Hello"; ④ char a[] = "Hello"; (3)向字元陣列中存放字串的方法 定義了字元陣列後,如果要向陣列中存放字串,除了以上提到的初始化方法,還有以下方法,注意

不能使用賦值語句的方法。假設已經有定義:char a[50]; 方法 1:scanf("%s", a); 注意:a 已經代表陣列的首地址,前面不再有取地址符&。 方法 2:gets("%s", a); 方法 3: int i=0;

while((a[i] = getchar()) != '\n') i++; a[i] = '\0';

重點 注意:不能用賦值語句的方法向字元陣列中存放字串。以下寫法是錯誤的,原因是陣列名是常量, 永遠指向陣列的首地址,字串常量書寫時,系統給出其在記憶體中佔用的一段無名儲存區的首 地址,不允許將陣列名這個常量重新賦值指向另一個地址空間。

char a[50]; a = "Hello"; (錯誤) (4)'\0'何時系統自動新增、何時需手動新增 字串常量的結束標誌是'\0',缺少了'\0',則不能稱為字串常量。以下列出何時由系統自動新增'\0',

何時需要程式設計者自己手動新增'\0'的幾種情況。 系統自動新增的情況:(假設已有定義: char a[50];) 呼叫 scanf 函式從鍵盤輸入字串時。例如:scanf("%s", a); 呼叫 gets 函式從鍵盤輸入字串時。例如:gets(a); 以字串常量形式對字元陣列進行初始化時。例如:char a[50] = "Hello"; 呼叫 strcpy 函式將字串複製到字元陣列中時。例如:strcpy(a, "Hello");

需手動新增'\0'的情況: 以字元形式對字元陣列進行初始化時。例如:char a[ ] = {'H', 'e', 'l', 'l', 'o', '\0'}; 先定義字元陣列,再將單個字元賦值到各個陣列元素中時。例如:char a[50];

a[0]='H'; a[1]='e'; a[2]='l'; a[3]='l'; a[4]='l'; a[5]='\0'; 對字元陣列中原來存放的字串進行處理,破壞了原字串的'\0',對新處理後的字串需手動新增'\0'

(5)字串輸入、輸出 第一種方法:呼叫 scanf、printf 函式實現,格式說明符使用"%s"。例如:

char a[50]; scanf("%s", a); //當遇到空格或者回車時系統認為字串輸入結束 printf("%s", a); //字串輸出

第二種方法:呼叫 gets、puts 函式實現。例如: char a[50]; gets(a); //當遇到回車時系統認為字串輸入結束

puts(a); 說明:scanf 和 gets 輸入字串時的區別是——scanf 不接收空格,該函式認為空格是字串輸入結束

標誌。而 gets 接收空格作為字串中的有效字元,該函式只認為回車是字串輸入結束標誌。 (6)字串處理函式 求字串長度函式:strlen(s)

例如:char s[50]; int len; len = strlen(s); 說明 1:使用 strlen 求字串長度時,計算的是第一個'\0'之前的有效字元個數,函式返回值不包

括'\0'佔用的位元組數。 說明 2:注意區分 strlen 和 sizeof。首先,strlen 是庫函式,而 sizeof 是運算子;其次,strlen 計

算的是字串有效字元佔用的位元組數,不包括'\0'佔用的空間,而 sizeof 計算的是字元 陣列或者字串佔用記憶體的位元組數,包括'\0'佔用的空間。例如:

char s[20]="Hello"; int x, y, m, n; x = strlen(s); y = sizeof(s); m = strlen("Hello"); n = sizeof("Hello"); 以上舉例中,變數 x 和 m 的值都是 5,因為 strlen 函式僅僅統計字串中有效字元的佔 用的位元組數。變數 y 的值是 20,因為 sizeof(s)計算的是陣列 a 在記憶體中佔用的位元組數。 變數 n 的值是 6,因為 sizeof("Hello")計算的是字串"Hello"在記憶體中佔用的位元組數, 包括'\0'佔用的空間。

字串連線函式:strcat(s1, s2) 例如:char s1[50] = "Hello", s2[50] = " every one";

strcat(s1, s2); //表示把字串" every one"貼上到字串"Hello"的後面 strcpy(s1, "every one");

字串比較函式:strcmp(s1, s2) 說明:該函式是從左至右依次將兩個字串的對應字元取出做比較,比的是對應字元 ASCII 碼

值的大小。當字串 s1 大於字串 s2 時,函式返回 1;當字串 s1 等於 s2 時,函式返 回 0;當字串 s1 小於 s2 時,函式返回-1。

字串複製函式:strcpy(s1, s2) 說明:該函式將 s2 指向的字串複製到 s1 指向的儲存空間裡,要求 s1 指向的儲存空間必須足夠

大,能夠容納即將複製的字串。 例如: char s1[50], s2[50] = "Hello";

strcpy(s1, s2); //表示把字元陣列 s2 中存放的字串複製到字元陣列 s1 中 strcpy(a, "China"); //表示把字串"China"複製到字元陣列 a 中

4、常用演算法

(1)冒泡法排序 (2)選擇法排序

重點

重點

第四部分 "函式"知識點

1、庫函式與自定義函式

(1) 庫函式:目前已學習過的庫函式有標準輸入輸出類庫函式、數學類庫函式,當程式中呼叫庫函式時,必須包含對應的標頭檔案。例如標準輸入輸出類庫函式對應的標頭檔案是<stdio.h>,數學類庫

函式對應的標頭檔案是<math.h>。 (2) 使用者自定義函式:使用者自己編寫的完成特定功能的函式,也稱子函式。 (3) 一個 C 程式由一個 main 函式和若干多個子函式組成。

2、函式定義、函式呼叫、函式宣告的概念

(1) 函式定義——即定義函式的功能。未經定義的函式不能使用。 (2) 函式呼叫——即執行一個函式,呼叫函式時,程式跳轉到被呼叫函式的第一句開始執行,執行

至被呼叫函式的最後一句,然後程式返回呼叫該函式處。 (3) 函式說明——即通知編譯系統該函式已經定義過了。

3、函式定義的格式

<函式型別> 函式名 (<引數表>) {

重點 函式首部

<函式體語句> } 函式由函式首部和函式體構成,其中函式首部由函式型別、函式名、引數表組成。 關於函式型別的說明 說明 1:函式型別分為"空型別(關鍵字是 void)"和"非空型別(需指定具體的返回型別,如 int、

float、double、char、指標型別、結構體型別等)"。 說明 2:當預設"函式型別"時,預設函式返回型別為 int 型。 說明 3:當函式型別是"非空型別"時,函式體內必須有 return 語句,寫成"return(表示式);",

表示式值的型別必須與函式型別一致,否則編譯系統會給出警告提示。 說明 4:當函式型別是"void"時,函式體內不需要 return 語句,或者直接寫"return ;"即可。 說明 5:函式型別是 C 語言中的關鍵字,在 VC++6.0 編譯環境中是藍色字型。 關於函式名的說明 說明 1:函式名命名必須符合 C 語言識別符號的命名規則。命名函式名最好是見名知意。 說明 2:同一段程式中的各自定義函式不允許函式名同名。 關於引數表的說明

說明 1:此時引數表中的引數稱為形式引數,簡稱"形參"。形參必須用一對小括號括起來。 說明 2:如果引數表中沒有引數,稱為無參函式,此時小括號中可以寫關鍵字 void,或者什麼都

不寫。 說明 3:如果引數表中有引數,稱為有參函式,此時小括號中必須明確申明各個引數的資料型別。

注意:每個引數都必須有各自的型別說明符,如 int fun(int a, int b, char c) 關於函式體的說明

說明 1:函式體必須用一對大括號括起來,函式體前面是說明部分,後面是執行語句部分。 說明 2:函式首部與函式體是一個整體,不能被分離開。例如,在括起引數表的小括號與括起函式

體的大括號之間加上分號是錯誤的。

4、函式呼叫

一個已經定義的函式,只有在發生函式呼叫時才能被執行。函式呼叫的過程即是程式跳轉到被呼叫函

數的第一句開始執行,執行至被呼叫函式的最後一句,然後程式返回函式呼叫語句處。 函式呼叫的一般形式: (1)有引數函式的呼叫形式: 函式名(引數) (2)無引數函式的呼叫形式: 函式名( )

函式的傳值呼叫 函式呼叫時的引數稱為實際引數,簡稱"實參"。當發生函式呼叫時,實參將數值傳遞給形參,

實現函式呼叫時的數值傳遞。 為保證函式呼叫時正確的數值傳遞,"實參"與"形參"應有嚴格的對應關係,可以歸納為"3

個一致和 1 個不一致"——規定:實參的個數、型別、順序必須與被呼叫函式形參的個數、型別、順序保持一致。而實參與形參的引數名稱可以不相同。 C 語言中函式呼叫的三種方式

(1)作為獨立的語句。例如:printf("Hello world!"); (2)作為表示式中的一部分。例如:y = sqrt(9); (3)作為其它函式的實參。例如:printf("y = %lf\n", sqrt(9));

5、函式宣告

編輯 C 程式時,如果函式定義寫在函式呼叫之後,則需要進行函式宣告,否則可以省略函式宣告。函式宣告的一般形式為:

型別名 函式名(型別 1,型別 2,… ,型別 n); 說明:函式宣告、函式定義、函式呼叫三者必須有嚴格的對應關係,三者的函式型別需一致,函式名

需相同,引數的個數、型別、順序需一致。

6、函式的巢狀呼叫

C語言中不允許作巢狀的函式定義。因此各函式之

間是平行的,不存在上一級函式和下一級函式的問題。 但是C語言允許在一個函式的定義中出現對另一個函

數的呼叫。這樣就出現了函式的巢狀呼叫。即在被調函

數中又呼叫其它函式。 其關係如圖所示:在執行 main 函式的過程中呼叫

f1 函式,於是轉去執行 f1 函式,在執行 f1 函式過程中又呼叫 f2 函式,於是轉去執行 f2 函式,f2 函式執行完畢後返回 f1 函式的斷點繼續執行,f1 函式執行完畢後返回 main 函式的斷點繼續執行。

7、變數的作用域和儲存類別(教材 12.1~12.3 節)

變數的作用域是指從空間上對變數的作用範圍進行分類,分為全域性變數和區域性變數。其中全域性變數的

作用範圍寬,區域性變數的作用範圍窄。 變數的儲存類別是指從時間上對變數的存在時間長短進行分類,分為動態變數、靜態變數。其中動態

變數的存在時間短,靜態變數的存在時間長。

(1)變數的作用域 變數的作用域是指變數的作用範圍,分為全域性變數和區域性變數,區域性變數又分為函式體的區域性變數以

及複合語句的區域性變數。

全域性變數 函式體內的區域性變數 複合語句內的區域性變數 定義位置 定義在函式體外面 定義在函式體內部 定義在複合語句內部

作用域 從定義位置開始到整個.c 檔案結束有效

本函式體內有效 本複合語句內有效

注意事項 (1)同一個.c 檔案內的全域性變數不能重名

(1)必須寫在執行語句之前(2)同一函式體內的區域性變

(1)必須寫在執行語句之前(2)同一個複合語句內的局

重點

(2)全域性變數允許與區域性變數重名,重名時,區域性變數

遮蔽全域性變數

量不能重名 (3)當與全域性變數重名時,區域性變數遮蔽全域性變數

部變數不能重名 (3)與前兩種變數相比,這是作用範圍最小的一種變數

說明 1:從此表格可以看出,作用範圍最寬的是全域性變數,其次為函式體內的區域性變數,範圍最窄的是複合語句內的區域性變數。

說明 2:當全域性變數、區域性變數有重名時,範圍較窄的變數會自動遮蔽範圍較寬的變數。 說明 3:定義在函式體內的變數以及形參都屬於區域性變數。 (2)變數的儲存類別 變數的儲存類別分為 auto(動態型)、static(靜態型)、register(暫存器型)、extern(外部型)。 動態變數—— 只在某一個時間段記憶體在。例如函式的形參、函式體內的區域性動態變數,這類變

量在發生函式呼叫時,系統臨時為它們分配儲存空間,但是隨著函式呼叫結束, 這些變數的儲存空間被釋放掉,變數的值也隨之消失。 動態變數分為全域性動態變數、區域性動態變數。

靜態變數—— 生存期為程式的整個執行過程,直到程式執行結束。這類變數一旦定義,系統就 為之分配儲存空間,靜態變數在整個程式執行過程中固定的佔用這些儲存空間, 因此也稱永久儲存。

靜態變數分為全域性靜態變數、區域性靜態變數。 注意:靜態變數定義後如果沒有賦初值,則初值為零。這一點與動態變數不同, 動態變數定義後如果沒有賦初值,則初值是隨機數。

暫存器變數—— 可以將使用頻率較高的變數定義為 register 型,以提高程式的執行速度。寄存 器變數屬動態變數,儲存空間到特定時候就自動釋放。 注意:暫存器變數只限整型、字元型、指標型。

外部變數—— 如果在某個原始檔(例如 a.c)中定義了一個全域性動態變數 int x,在另外一個源

auto

static

register

extern

重點

重點

檔案(例如 b.c)中需要引用這個全域性變數 x,則在"b.c"中對變數 x 進行如下說 明"extern int a;"後,即可引用"a.c"中定義的變數 x。 注意:全域性變數的定義只能有一次,但是使用 extern 對其進行說明可以有多次。 這一點與函式類似,函式定義也是隻能有一次,而函式說明可以有多次。

8、函式的儲存分類(教材 12.4 節)

(1)用 static 說明函式 一個函式定義後,除了被所在的原始檔呼叫,不允許被其它的原始檔呼叫,則在函式首部的返回值

型別前面加上 static 關鍵字即可達到以上目的。這樣做的好處是避免不同的.c 檔案定義了同名的函式而引起混亂。

(2)用 extern 說明函式 一個函式定義後,如果除了被所在的原始檔呼叫,還能被其它原始檔呼叫,則其它原始檔在呼叫該函

數前,需先使用 extern 關鍵字進行說明,之後便可呼叫。

9、編譯預處理(教材 13.1 節)

在 C 語言中,凡是以"#"開頭的行都稱為編譯預處理命令列,要求掌握"#define"和"#include"。注意:每行的末尾不能加";"號。

(1) 宏替換 —— #define 不帶引數的宏定義

#define 宏名 替換文字 使用說明:替換文字中可以包含已經定義過的宏名 書寫說明:當宏定義分多行書寫時,在行末加一個反斜線"\";宏名習慣用大寫字母;宏定義一般寫在程式的開頭。 帶引數的宏定義

#define 宏名(引數表) 替換文字 使用說明 1:引數表中只有引數名稱,沒有型別說明。 使用說明 2:如果替換文字中有括號,則進行宏替換時必須有括號;反之,如果替換

檔案中本身沒有括號,則宏替換時不能隨便加括號。 書寫說明:宏名和小括號必須緊挨著;小括號不能省略;

重點

(2)檔案包含 —— #include 所謂檔案包含是指在一個檔案中去包含另一個檔案的全部內容,#include 命令列的形式如下: #include "檔名" 或者 #include <檔名> 如果檔名用雙引號括起來,是指系統先在源程式所在的目錄查詢指定的包含檔案,如果找不到,再

按照系統指定的標準方式到有關目錄中去找。 如果檔名用尖括號括起來,系統將直接按照系統指定的標準方式到有關目錄中去尋找。

第五部分 "指標"知識點

1、指標的基本概念(教材 8.1 節) (1)計算機的記憶體空間是由許多儲存單元構成的,每個儲存單元代表一個位元組的容量,每個儲存單

元都有一個唯一的編號,即地址。程式執行過程中使用變數等就存放在這些儲存單元中。對變數的取值有

兩種方法,一種是使用變數名對其內容進行存取,稱為"直接法",另一種是藉助變數的地址對其內容進

行存取,稱為"間接法"。 (2)指標──即地址。一個變數的地址稱為該變數的指標,透過變數的指標能夠找到該變數。 指標變數──專門用於儲存其它變數地址的變數。指標與指標變數的區別,就是變數值與變數名的區

別。注意:指標變數存放的是地址值,而不是通常意義上的數值。

2、指標變數的定義、賦值(教材 8.2 節)

(1)指標變數的定義: 型別識別符號 *指標變數名; 說明 1:此處的型別識別符號稱為指標變數的"基型別",即表示該指標變數應存放何種型別的變數地

址,指標變數的基型別必須與其指向的普通變數同類型,否則會引起程式執行錯誤。 說明 2:與普通變數的定義相比,除變數名前多了一個星號"*"外,其餘一樣。注意:此時的星號

僅僅是一個識別符號,標識其後的變數是指標變數,而非普通變數。 說明 3:例如有定義"int *p;"表示定義了一個 int 型別的指標變數 p,此時該指標變數並未指向某個

具體的變數(稱指標是懸空的)。使用懸空指標很容易破壞系統,導致系統癱瘓。 重點

重點及難點

說明 4:不論是什麼型別的指標變數,在 VC++6.0 編譯環境中已定義的指標變數都佔用 4 個位元組的儲存空間,用來存放地址。這點與普通變數不一樣,普通變數根據不同的資料型別,它所佔用

的儲存空間位元組數是有差別的。 (2)指標變數的賦值 與普通變數相同,指標變數可以在定義時為其賦值,稱為初始化;也可以先定義,再使用賦值語句為

其賦值,賦值方式為:指標變數名=某一地址; 通常有以下幾種方法為指標變數賦值:

方法一:指標變數名 = &普通變數名 方法二:指標變數名 = 另外一個同類型並已賦值的指標變數 方法三:第三種是呼叫庫函式 malloc 或者 calloc,當指標使用完畢後再呼叫 free 將其釋放。例如: int *p; //以下兩種寫法均能實現為指標變數 p 動態分配 40 個位元組儲存空間的功能 p = (int *)malloc(10 * sizeof(int)); 等價於 p = (int *)calloc(10, sizeof(int));

3、指標運算(教材 8.4.2、8.4.3 節)

(1)指標運算中兩個重要的運算子 * (取內容符): 取出其後記憶體單元中的內容。 &(取地址符): 取出其後變數的記憶體單元地址。 說明:此處的取內容符也是星號,外形上與指標變數定義時的識別符號一樣,但是二者的含義完

全不相同,前者是運算子,後者只是一個識別符號。 (2)移動指標

重點

重點

移動指標就是對指標變數加上或減去一個整數,或透過賦值運算,使指標變數指向相鄰的儲存單元。

只有當指標指向一串連續的儲存單元(例如陣列、字串)時,指標的移動才有意義。 指標移動透過算術運算(加、減)來實現,指標移動的位元組數與指標的基礎型別密不可分。例如已定

義:char *p1; int *p2;進行如下運算"p1++; p2++;"後,指標 p1 中存放的地址值自增一個單元,指標 p2 中存放的地址值自增 4 個單元。

(3)比較運算 比較運算是比兩個指標變數中存放的地址值的大小關係。 (4)指標的混合運算 例如有定義:int a, *p; 則以下一些舉例的混合運算需要仔細推敲其含義。

難點

4、函式之間地址值的傳遞(教材 8.5 節)

(1)實參向形參傳送地址值 如果函式的形參為指標變數,對應的實參必須是基型別相同的地址值或者是已指向某個儲存單元的指

針變數。 教材 7.5 節的內容是"函式之間數值的傳遞",這種方式下完成的是實參向形參的數值單向傳遞,即

當發生函式呼叫時,實參將其數值傳遞給形參,函式呼叫完畢後,形參的改變並不能影響對應實參的值,

因此把這種數值傳遞稱為是"單向"的。 而本節的內容是"函式之間地址值的傳遞",其特點是實參為主呼叫函式中某記憶體單元的地址,在被

呼叫函式中可以透過形參對主調函式中該記憶體單元的值進行修改,這也就使得透過形參改變對應的實參值

有了可能,因此透過地址值的傳遞方式,主調函式與被調函式之間資料傳遞可以實現"雙向"的傳遞。 "傳地址"方式的體現的另外一個優越之處在於:可以將多個數據從被調函式返回到主調函式中。這

一點也是"傳值"方式做不到的,傳值方式中被調函式只能利用 return 語句向主調函式返回一個數據。 同學需仔細區分函式之間"傳值"與"傳地址"這兩種方式各自的特點,做題時注意分析何時為傳值

方式,何時為傳地址方式。 (2)透過 return 語句返回地址值 當函式返回值的型別是指標型別,而非普通資料型別時,表明被調函式呼叫完畢後向主調函式返回的

是一個地址值,而不是一個普通的數值。此時應注意 return 語句的表示式值應是指標型別(地址值)。

重點

重點

5、一維陣列和指標(教材 9.2 節)

(1)陣列名是一個地址常量 (2)使用指標對陣列元素進行訪問是基於陣列元素順序存放的特性。

方式一:利用陣列的首地址(陣列名)訪問陣列元素。注意:由於陣列名是常量,因此對數 組名不能使用自增運算,必須藉助一個變數 i 來實現對陣列元素的順序訪問。

例如: int a[10], i = 0; while(i < 10) scanf("%d", &a[i++]); 或者 while(i < 10) scanf("%d", a+ i++); 方式二:利用指標變數訪問陣列元素。 例如: int a[10], i = 0, *p = a; while(i < 10) scanf("%d", p++);

(3)引用一維陣列元素的二種等價方法——下標法、指標法 假設有如下定義:int a[3], *p = a; 從上表可總結出,下標法取陣列元素數值的表示式為"a[i]"或"p[i]",指標法取陣列元素數值

的方法為"*(a+i)"或"*(p+i)"。下標法取陣列元素地址的表示式為"&a[i]"或"&p[i]",指標法取陣列元素地址的方法為"a+i"或"p+i"。

(4)假設有以下定義:int a[10], *p = a; 則 p 和 a 的相同點是:都是指標,存放陣列的首地址。 不同點是:a 是地址常量,p 是指標變數。a 永遠指向該陣列的首地址,直到該陣列

的儲存空間被系統收回;p 是變數,可以重新賦值指向其它的儲存空間。

6、一維陣列與函式引數(教材 9.3 節)

(1)陣列元素作為函式實參 由於陣列元素相當於一個個獨立的普通變數,當陣列元素作為函式實參時,實現的是"傳值"方式,即單向傳遞。在被調函式中只能使用陣列元素的數值,不能改變陣列元素的初值。 (2)陣列元素的地址作為函式實參

當某陣列元素的地址作為函式實參時,實現的是"傳地址"方式,能夠達到雙向資料傳遞的功能。即在被呼叫函式中,不但可以利用形參使用該陣列元素的初值,還可以達到修改該陣列元素初值

的目的。 (3)陣列名作為函式實參

當陣列名作為函式實參時,由於陣列名本身就是一個地址值,因此實現的是"傳地址"方式,能夠達到雙向資料傳遞的功能,對應的形參必須是一個與陣列型別一樣的指標變數。在被呼叫函式中,

可以透過形參(指標變數)使用陣列中的所有元素,還能夠修改這些元素的初值。 說明 1:陣列名作為函式實參時,對應的形參有如下幾種寫法,都代表一個與陣列型別一致的指

針變數。 void fun(int a[10]) 或者 void fun(int a[ ]) 或者 void fun(int *a) { … } { … } { … }

說明 2:陣列名作為實參時,對應的形參是一個與陣列同類型的指標變數,發生函式呼叫時,系 統只是為該指標變數(形參)分配 4 個位元組的儲存空間,並不是分配等同於整個陣列需要 佔用的儲存容量。 例如:

a[0] a[1] a[2] 下標法

p[0] p[1] p[2] *a *(a+1) *(a+2)

取數

組元

素的

數值 指標法

*p *(p+1) *(p+2)

&a[0] &a[1] &a[2]

下標法 &p[0] &p[1] &p[2]

a a+1 a+2

取數

組元

素的

地址指標法

p p+1 p+2

重點

重點

void main(void) void fun(int a[10]){ { int a[10]; … … printf("%d", sizeof(a)); printf("%d", sizeof(a)); …

fun(a); } …

注:fun 函式中的列印結果是"4",因為形參是一個指標變數,不論何種型別的指標變數,系統都為它分配 4 個位元組的儲存空間。

}

注:主函式中的列印結果是"40",因為 a 陣列定義後,系統為它分配 40 個位元組的儲存空間。

7、二維陣列和指標(教材 9.6 節) 難點

(1)二維陣列"基型別"的理解 假設有定義:int a[3][4], *p;

與一維陣列一樣,二維陣列名也是一個地址常量。 二維陣列可以看作由多個一維陣列組成,由以上定義可知,二維陣列 a 由三個一維陣列組成,每

一個一維陣列中有四個元素,a[0]、a[1]、a[2]分別是這三個一維陣列的陣列名,它們各自代表了這三個一維陣列的首地址,同樣也是不可改變的常量地址。

基於以上分析,可以這樣理解:①二維陣列名 a 的基型別是 4 個 int 型;②一維陣列名 a[0]、a[1]、a[2]的基型別是 1 個 int 型(即陣列元素的型別)。 假設有定義:int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12};以下示意圖表示了二維陣列名、一維陣列名、二維陣列中各元素之間的對應關係。

以上示意圖的右側是二維陣列的 12 個元素,每個元素佔用一個 int 型的儲存空間(4 個位元組),

假設第一行第一個元素 a[0][0]的地址為 0x1000,分析可知第二行第一個元素 a[1][0]的地址為 0x1010,第三行第一個元素 a[2][0]的地址為 0x1020,這三行元素的首地址分別由 a[0]、a[1]、a[2]來存放。示意圖的中部就是 a[0]、a[1]、a[2]構成的一個一維陣列,這三個元素是一級指標,存放的是地址值(分別是 0x1000、0x1010、0x1020)。示意圖的左側是二維陣列名 a,它是一個二級指標,存放由 a[0]、a[1]、a[2]三個元素構成的一維陣列的首地址(假設是 0x1030)。

透過以上分析可知,"a[i]"是一級指標,基型別為 1 個 int 型。"a"是二級指標,基型別是 4 個int 型。例如:"a[0]"指向元素 a[0][0],則"a[0]+1"表示地址向後移動,指向元素 a[0][1],即一級指標加 1 表示地址向後移動 1 個 int 型。"a"指向元素 a[0],則"a+1"表示地址向後移動,指向元素a[1],即二級指標加 1 表示地址向後移動 4 個 int 型。

(2)二維陣列每行元素的首地址 a(或者 a[0])代表二維陣列中第一行元素的首地址;a+1(或者 a[1])代表第二行元素的首地址;

a+2(或者 a[2])代表第三行元素的首地址。

1030 a

1000

1010

1020

a[0]

a[1]

a[2]

該行首地址為 1000 1 2 3 4

5 6 7 8

9 10 11 12

a[0][0] a[0][1] a[0][2] a[0][3]

a[2][0] a[2][1] a[2][2] a[2][3]

該行首地址為 1010

該行首地址為 1020

該一維陣列首地址為 1030

二維陣列名 a (二級指標)

一維陣列名 a[i](一級指標)

二維陣列元素 a[i][j] (內容)

(5)透過建立一個指標陣列引用二維陣列元素 假設有定義:int *p[3]; 則將 p 稱為指標陣列。 由於"[ ]"的優先順序高於"*"的優先順序,因此 p 首先與"[ ]"結合,構成 p[3],說明是一個數 組,"p[3]"再與"int *"結合,表示該陣列中每個元素的資料型別是"整型指標"型別,於是我們將 "int *p[3]"稱為指標陣列——即它首先是一個數組,陣列中的每個元素是指標型別。 下面我們來分析"指標陣列"與"二維陣列"的對應關係,假設有定義:int *p[3], a[3][2]; (注 意以上定義中,必須保證指標陣列的元素個數與二維陣列的行號常量一致,即 p[3]中的"3"與 a[3][2] 中的"3"要保持一致)。則以下寫法表示將 p 陣列中的每個元素(指標變數)指向 a 陣列中的每一 行。(參看教材 P128 圖 9.6) 第一種方法:p = a; 第二種方法:for(i = 0; i < 3; i++) p[i] = a[i]; 這時,可以透過指標陣列 p 來引用二維陣列 a 中的元素。

(6)透過建立一個行指標引用二維陣列元素 假設有定義:int (*q)[2]; 則將 q 稱為行指標。同學需仔細區分行指標與指標陣列的區別。 由於定義時加了小括號,因此 q 首先與"*"結合,說明 q 是一個指標變數,然後再與"[3]"結 合,說明指標變數 q 的基型別是一個包含兩個整型元素的陣列。 下面我們來分析"行"與"二維陣列"的對應關係,假設有定義:int (*q)[2], a[3][2]; (注意以 上定義中,必須保證行指標的元素個數與二維陣列的列號常量一致,即(*q)[2]中的"2"與 a[3][2] 中的"2"要保持一致)。則指標變數 q 的基型別與 a 的基型別相同,q = a; 是合法的賦值語句,表示 指標 q 指向了二維陣列 a 的首地址,這時可以透過行指標 q 來引用二維陣列 a 中的元素。

(7)二維陣列、指標陣列、行指標之間的對應關係 假設有定義:int a[3][2], *p1[3], (*p2)[2]; 則 a 是二維陣列名、p1 是指標陣列名,p2 是行指標名,由於二維陣列的行數與指標陣列的維數相同,二維陣列的列數與行指標的維數相同,因此它們三

者可以產生對應關係。以下語句合法 p1 = a; p2 = a; 可以將 a、p1、p2 都視為二級指標。

難點 8、二維陣列名和指標陣列名作為函式實參(教材 9.7 節)

(1)二維陣列名作為函式實參 首先回憶一維陣列名作為函式實參的時候,對應的形參是與陣列元素同類型的指標變數,形參有如下幾種寫法:

main() { int a[3]; … fun(a); //一維陣列名作為函式實參 … }

則 fun 函式首部可以有如下幾種寫法:(1)void fun(int

p[3])

p[ ]) *p)

(2)void fun(int (3)void fun(int

當二維陣列名作為函式實參時,對應的形參必須是一個行指標變數,形參的寫法有以下幾種形式:

main() 則 fun 函式首部可以有如下幾種寫法: { int a[2][3]; (1)void fun(int p[2][3])

(2)void fun(int p[ ][3])

… fun(a); //一維陣列名作為函式實參

… (3)void fun(int (*p)[3]) } 注意以上寫法,列下標不可預設。無論是哪種方式,系統都把 p 處理成一個行指標。

(2)指標陣列名作為函式實參 當指標陣列作為函式實參時,對應的形參應當是一個指向指標的指標。形參的寫法有以下幾種形式:

main() 則 fun 函式首部可以有如下幾種寫法:{

(1)void fun(int *p[3]) (2)void fun(int *p[ ])

int a[2][3], *p[3] = a; … fun( p ); //指標陣列名作為函式實參 … }

與一維陣列名作實參時形參的寫法相似(一維陣列名作實參時對應的形參有三種寫法),當指標陣列

作為函式實參時,傳送的仍然是一個一維陣列名,對應的形參也有三種寫法,只不過形參的型別是指標類

型而已。

9、字串與指標(教材 10.2 節)

(3)void fun(int **p)

重點

(1)使指標指向一個字串 由於字串中的每一個字元在記憶體空間裡是順序存放的,因此使用指標操作字串是比較便利的。以

下是幾種將字元型指標變數指向字串的正確方法: 方法一:在定義字元型指標變數時為其賦初值一個字串(初始化)。例如: char *p = "Hello"; 方法二:先定義字元型指標變數,然後透過賦值語句讓指標變數指向字串。例如: char *p; p = "Hello"; 示例中的字串常量"Hello"在程式中給出的是它在記憶體空間的首地址,因此可以透過賦值

語句將這段無名儲存區的首地址賦值給指標變數,使得指標指向該字串。 方法三:先定義字元型指標變數,然後將指標變數賦一個有效的地址值(可以將指標賦值為一個字元

陣列的首地址,或者呼叫 malloc 函式為指標變數動態分配一段儲存空間),最後呼叫 strcpy 函式將字串複製到指標所指向的這段儲存空間裡。例如:

char *p; p = (char *)malloc(6 * sizeof(char));

strcpy(p, "Hello");

char a[6], *p; p = a; strcpy(p, "Hello");

或者

注意:在呼叫 strcpy 函式之前,指標 p 必須已經指向一個有效的儲存空間,然後才能向這個

儲存空間裡存放字串常量。如果指標只是定義,沒有為其賦有效的地址值,這樣的 指標是不能拿來用的。

(2)一些容易範錯誤的用法 錯誤一:使用賦值語句企圖為字元陣列賦一個字串。例如: char a[6]; a = "Hello"; (錯誤原因是陣列名是常量,不能指向另外的儲存空間) 錯誤二:指標變數定義後就呼叫 strcpy 函式企圖將一個字串複製到指標所指的儲存空間裡。例如: char *p; strcpy(p, "Hello");

(錯誤原因是指標 p 中此時存放的是一個隨機的地址值,即它還未指向一段有效的儲存空 間,向一個隨機的儲存空間裡賦值字串常量是毫無意義的。)

(3)"字元陣列存放字串"與"指向字串的指標"的比較 對於字串的操作,既可以使用字元陣列,還可以使用字元型指標變數,二者使用上有一些異同: 相同點:都可以利用初始化的方法為其賦一個字串常量。例如: char a[6] = "Hello"; (正確) char *p = "Hello"; (正確) 不同點 1:字元陣列不能使用賦值語句為其賦字串常量;而字元型指標變數可以透過賦值語句使之

指向字串常量;例如: char a[6]; a = "Hello"; (錯誤) char *p; p = "Hello"; (正確) 不同點 2:字元陣列定義之後可以呼叫 strcpy 函式為其賦字串常量;而字元型指標變數定義之後不

能立即呼叫 strcpy 函式為其賦字串常量。例如: char a[6]; strcpy(a, "Hello"); (正確) char *p; strcpy(p, "Hello"); (錯誤) 不同點 3:字元陣列裝載字串後,系統為陣列開闢的是一段連續的儲存空間(大於或等於字串長

度),陣列名代表了這段儲存空間的首地址。字元型指標變數指向字串後,系統為字元型 指標變數開闢的僅僅是 4 個位元組,用來存放字串無名儲存區的首地址。例如:÷ char a[ ] = "Hello"; (系統為陣列開闢了 6 個位元組的儲存空間用來存放字串) char *p = "Hello"; (系統為指標變數 p 開闢了 4 個位元組用來存放字串常量的首地址) 因此 sizeof(a) 的運算結果是 6;而 sizef(p) 的運算結果是 4。

(4)字串陣列 難點

多個字串放在一起就構成了字串陣列。可以使用一個二維陣列(字元型的)來構造字串陣列,

也可以定義一個指標陣列(字元型的)來構造一個類似的字串陣列。以下分別敘述: 方法一:使用二維陣列來構造字串陣列。例如: char name[ ][10] = {"China", "America", "English", "France"}; 定義二維陣列時,可以預設第一維的長度,該例中,系統為二維陣列 name 總共開闢了 40

個位元組的儲存空間,用來存放四個字串,雖然有一些單元被浪費,示意圖如下所示:

name name[0]

name[1]

name[2]

name[3]

C h i n a \0

A m e r i c a \0

E n g l i s h \0

F r a n c e \0

方法二:定義一個指標陣列來構造字串陣列。例如: char *pname[4] = {"China", "America", "English", "France"};

pname pname[0]

pname[1]

pname[2]

pname[3]

C h i n a \0

A m e r i c a \0

E n g l i s h \0

F r a n c e \0

由以上示意圖可以看出,指標陣列 pname 中有四個元素,都是字元型的指標變數,每個指標指 向的儲存空間不等長。因此用指標陣列構造的字串陣列能夠有效利用儲存空間,根據不同的字串 長度系統為之分配不同的儲存容量,因此不會造成儲存空間的浪費,這一點與二維陣列構造的字串 陣列不一樣。

1、main 函式的引數(教材 11.1 節) main 函式的引數通常有兩個,函式首部可以寫成以下形式: 第一個引數:型別必須是 int 型,引數名通常是 argc,也可以由使用者自己來命名。該引數記錄使用者從命令列輸入的字串的個數。 第二個引數:型別必須是字元型的指標陣列,引數名通常是 argv,也可以由使用者自己來命名。該引數記錄使用者從命令列輸入的各個字串,由於多個字串構成字串陣列,此時的形參為一個指標陣列,數

組中的每一個指標指向各個字串的首地址。 說明:從命令列輸入的多個字串中,第一個字串必須是可執行檔案的檔名。

參看教材"P158 例 11.1"對引數 argc 和 argv 的使用。

2、指向函式的指標(函式指標)(教材 11.2 節)

(1)指向函式的指標變數的定義、賦值

指向函式的指標也稱"函式指標",由於 C 語言中函式名代表該函式的入口地址,因此可以定義一種指向函式的指標來存放該入口地址,將這種指標稱為指向函式的指標。

void main(int argc, char **argv){ … }

難點

重點

double fun(int a, char *p){ … }

該 fun 函式定義為返回型別是 double 型,有兩引數,第一個是 int 型,第二個是 char *型。

{ … } void main(int argc, char *argv[ ])

或者

void main(void){ double (*pfun)(int, char *); //定義指向函式的指標變數

char x=2, double y; pfun = fun; //將 fun 函式的入口地址賦值給指標變數 pfun …

y = (*pfun)(10, &x); //等價於 y = fun(10, &x); }

以上示意圖中,在主函式內部首先定義了一個指向函式的指標變數 pfun,明確指出該指標所指向的函式返回值是 double 型,函式有兩個引數,第一個引數是 int 型,第二個引數是 char *型。然後為指標變

量 pfun 賦值,透過語句"pfun = fun;"將 fun 函式的入口地址賦值給指標變數 pfun,於是對函式的呼叫即可透過該指標來完成。最後利用 pfun 實現對 fun 函式的呼叫,透過語句"y = (*pfun)(10, &x);"來完成,該語句等價於傳統用法"y = fun(10, &x)"。

注意 1:定義指向函式的指標變數 pfun 時,"* pfun"的兩側必須加小括號,寫成 (* pfun)。 注意 2:為指向函式的指標變數賦值時,賦值號的左側只寫指向函式的指標變數名,賦值號的右側只

寫函式名。 注意 3:利用指向函式的指標變數呼叫函式時,等價於使用函式名呼叫函式。

(2)指向函式的指標變數作為實參 函式名作實參時,對應的形參應該是函式指標。 函式指標也可以作函式實參,對應的形參應當是型別相同的指標變數。參看教材"P159 例 11.2"。

3、函式的遞迴呼叫(教材 11.3 節) 重點

一個函式如果自己呼叫自己,則稱為直接遞迴呼叫;如果是兩個函式相互呼叫對方,則稱為間接遞迴

呼叫。 一個函式在它的函式體內呼叫它自身稱為遞迴呼叫。這種函式稱為遞迴函式。在

遞迴呼叫中,主調函式又是被調函式。執行遞迴函式將反覆呼叫其自身。例如有函式

fun 如下圖所示:

int fun (int x) {

int y; z=fun(y);return z;

}

這個函式是一個遞迴函式。但是執行該函式將無休止地呼叫其自身,這當然是不正確

的。為了防止遞迴呼叫無終止地進行,必須在函式內有終止遞迴呼叫的手段。常用的

辦法是加條件判斷,滿足某種條件後就不再作遞迴呼叫,然後逐層返回。

第七部分 "結構體、共用體" 知識點 重點

1、結構體型別的說明

"結構體"是一種構造型別,是由數目固定,型別相同或不同的若干有序變數組成的集合。組成結構體的每個資料都稱為結構體的"成員",或稱"分量"。 結構體型別說明的形式如下: struct 結構體標識名

例如:以下定義了一個日期型的結構體型別 { struct data { int year; int month; int day; };

型別名 1 結構體成員名列表 1; 型別名 2 結構體成員名列表 2; … 型別名 n 結構體成員名列表 n;

} ; 說明 1:結構體型別的說明可以巢狀。 說明 2:struct 是關鍵字。"結構體標識名"可以省略。 說明 3:右側花括號後面的分號 ; 不能省略。 說明 4:結構體型別的說明只是列出了該結構的組成情況,標誌這種型別的結構模式已存在,編譯程

序並沒有因此而分配任何儲存空間。就類似於列出"int",標誌系統認可這種資料型別,但 "int"本身並不佔用記憶體空間,只有定義了 int 型的變數後,系統才為變數分配記憶體空間。

2、用 typedef 定義型別

typedef 是一個關鍵字,利用它可以將已存在的資料型別命一個新的名稱,可以理解為給已有的資料型別取一個別名。

例如:typedef int INT; INT x, y; //等價於 int x, y; 以上寫法表示使用 typedef 給已有的資料型別"int"取了一個新名字"INT",於是"INT"等價於"int",

可以使用這個新型別名定義變數 x 和 y。 注意:typedef 的使用並不是定義了一種新的型別,而僅僅是將已有的資料型別取了一個新名稱。 使用者自己定義的結構體型別一般都比較複雜,使用 typedef 可以為結構體型別取一個較為簡單的名稱。 以下三種方式是使用 typedef 為結構體型別取一個別名的方法。別名為"DATE"。

方法一:先定義結構體型別,再使用 typedef 為之取一個別名。 struct date { int year; int month; int day; }; typedef struct data

方法二:定義結構體型別 方法三:定義結構體型別的同時使用 typedef 的同時使用 typedef為之 為之取一個別名,並且不省略 取一個別名,並且省略了結構體標識名。 typedef struct date { int year; int month; int day; }DATE; DATE;

結構體標識名。 typedef struct { int year; int month; int day; }

圖 1 圖 2 圖 3

DATE;

3、定義結構體變數

以上提到結構體型別定義後,系統只是認可有這樣一種使用者自己構造的複雜資料型別,但並沒有為之 分配儲存空間,只有定義了該結構體型別的變數之後,系統才為變數分配相應的儲存空間,結構體變數佔

用的儲存容量由結構體型別決定。以下幾種是定義結構體變數的方法: 方法四:先定義結構體類

方法一:先定義結構體型別,再定義該結構體型別的變數。 struct date { int year; int month; int day; }; struct data

方法三:先使用 typedef 型,然後使用 typedef方法二:在定義結 為之構體型別的同時, 定義結構體型別的別名, 取一個別名,最後使用別

名定義結構體變數。 struct date { int year; int month; int day; }; typedef stuct date DATE;DATE x, y;

圖 7

定義結構體變數。 再使用結構體型別的別struct date { int year; int month; int day; }

圖 5

名定義變數。 typedef struct date { int year; int month; int day; }DATE; DATE

圖 6

x, y;

x, y; x, y;

圖 4 同學仔細比較"圖 1"和"圖 4",如果結構體型別名"struct date"前面有關鍵字 typedef,則 struct date

後面的是結構體型別的別名,反之如果沒有關鍵字 typedef,則 struct date 後面的是結構體變數。 同學再仔細比較"圖 2"和"圖 5",同樣道理,如果"struct date"前面有關鍵字 typedef,則右側花

括號後面的是結構體型別的別名,反之如果沒有關鍵字 typedef,則右側花括號後面的是結構體變數。 以上圖 4~圖 7 三種方法都定義了兩個結構體型別的變數 x 和 y,這兩個變數各自佔用 12 個位元組的存

儲容量,該儲存容量的大小由結構體型別決定。

4、定義結構體型別的指標變數

結構體型別的指標變數定義方法與結構體型別普通變數的定義方法相同,均可使用圖 4~圖 7 所示的

三種方法,例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU x, *p = &x;

右圖所示定義了一個 STU 結構體型別的普通變數 x,以及指標變數 p。由於該結構體型別各成員一共佔用 20+30+1+4+8=63 位元組的儲存容量,因此係統為變數 x 分配 63 位元組的儲存空間,指標 p 的基型別為STU 結構體型別,即指標 p 所指向的一則段儲存空間是 63 位元組。

定義結構體指標變數 p的同時對它進行初始化,為之賦值為"&x",這一賦值過程很有必要,因為這使得指標變數 p 指向了一個有效的儲存空間,沒有指向有效儲存空間的指標不能隨便使用。

5、透過結構體變數或結構體指標引用成員

例如上圖中定義的 STU 型別的結構體變數 x 或者結構體指標 p,它們有五個成員,如果要把某一個成員取出進行操作,不能直接使用,例如"age = 20;"這樣的語句是錯誤的,原因是 age 現在不是一個獨立的變數,它是變數 x 的一個成員,或者稱之為一個屬性,要取出 age 並將它賦值為 20,必須透過變數 x或者指標 p 才能將它取出。有以下三種方法,用到"."運算子或者"->"運算子。

(1)結構體變數名. 成員名 (2)結構體指標變數名->成員名

重點

(3)(*結構體指標變數名). 成員名 例如: strcpy(x.name, "LiWei"); 或者 strcpy(p->name, "LiWei"); 或者 strcpy((*p)->name, "LiWei"); x.age = 20; 或者 p->age = 20; 或者 (*p).age = 20;

6、給結構體變數賦值

方法一:初始化 定義結構體變數的同時為它的各個成員賦初值,稱為初始化,例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU

右圖所示在定義結構體變數 x 的同時為它的五個成員賦初值。所有初值必須要

用一對花括號括起來,各數值之間用逗號

隔開,數值的型別以及書寫順序與各成員

的型別和書寫順序保持一致。

x={"20070102001", "ZhangHua", 'M', 18, 80.0};

方法二:結構體變數的整體賦值。如果兩個結構體變數型別相同,則可以對兩個結構體變數進行整體

賦值。例如:

typedef struct student { char num[20]; char name[30]; char sex; int age; double score; }STU; STU x, y={"20070102001", "ZhangHua", 'M', 18, 80.0};x = y; //結構體變數的整體賦值

右圖所示定義了兩個結構體變數 x 和y。其中變數 y 使用初始化的方法已經為它的五個成員賦了初值,而變數 x 定義的時候各成員還沒有初值。由於 x 和 y 是同類型的變數,因此可以透過賦值語句"x = y;"將變數 y 的值整體賦值給變數 x。這樣做相當於將變數 y 各個成員的初值對應地賦值給變數 x 的各個成員。

方法三:結構體變數的各成員分開賦值。兩個結構體變數對應成員之間可以相互賦值,例如: strcpy(x.num, y.num); strcpy(x.name, y.name); x.sex = y.sex; x.age = y.age; x.score = y.score; 注意:以上各成員分開賦值時,對於字串型別,不能寫成"x.num = y.num;"、"x.name = y.name;",

雖然此時賦值號的兩側型別相同,都是陣列名(是地址),但由於陣列名本身是地址常量,不能將其賦值

為另一個儲存空間的首地址,因此對於字元陣列型別的成員之間進行賦值,應選用 strcpy 庫函式。其它基本資料型別的成員之間可以直接使用賦值語句進行賦值。

方法四:從鍵盤為各成員輸入數值。例如: scanf("%s", x.num); //注意:成員"x.num"本身是陣列名,代表地址,因此前面不加取地址符 scanf("%s", x.name); //成員"x.name"本身是陣列名,代表地址,因此前面不加取地址符 scanf("%c", &x.sex); //成員"x.sex"、"x.age"、"x.score"是基本資料型別的變數,前面要加取地址符 scanf("%d", &x.age); scanf("%lf", &x.score);

7、結構體變數或成員做實參

"傳值"方式——與基本資料型別一樣,當結構體變數或者結構體變數的成員做實參時,實現的是"傳

值"方式,只能單向傳遞資料。對應的形參必須與實參保持同類型。 "傳地址"方式——當結構體變數的地址或者結構體變數成員的地址做實參時,實現的是"傳地址"

方式。對應的形參必須是同類型的指標變數。 難點 8、利用結構體變數構成連結串列

當結構體型別定義時有一個自身結構體型別的指標變數作為成員,則可以利用該結構體型別的變數構

成連結串列。構成連結串列有靜態方式和動態方式兩種,動態方式是難點,也是考查的重點。 構成單向連結串列時,通常有一個頭結點,若干個資料結點,以及一個末尾結點。一般來說,頭結點的數

據域為空,頭結點的指標域指向第一個資料結點,依次類推,每一個數據結點的指標域指向後一個數據結

點,最後一個數據結點稱為末尾結點,末尾結點的指標域為空(NULL)。 有關單向連結串列的基本演算法(參考教材 P198~P201)有:連結串列的建立、順序訪問連結串列中各結點的資料

9、共用體

共用體型別的說明以及共用體變數的定義方式與結構體相似。共用體與結構體不同的是,結構體變數

的各個成員各自佔用自己的儲存空間,而共用體變數的各個成員佔用同一個儲存空間。 說明 1:共用體變數的儲存空間大小由佔用位元組數最多的那個成員決定。 說明 2:共用體變數初始化時只能對它的第一個成員進行初始化。 說明 3:由於共用體變數所有成員佔用同一個儲存空間,因此它們的首地址相同,並且與該變數的地

址相同。 共用體變數中每個成員的引用方式與結構體完全相同,可以使用如下三種方式: (1)共用體變數名.成員名 (2)共用體指標變數名->成員名 (3)(*共用體指標變數名).成員名

第八部分 "檔案"知識點

1、基本概念

(1)記錄在外部介質上的資料的集合稱為"檔案"。資料可以按文字形式或二進位制形式存放在介質上,因此檔案可以按資料的存放形式分為文字檔案和二進位制檔案。二進位制檔案的輸入輸出速度較快一些。

(2)對檔案的輸入輸出方式稱為存取方式,在 C 語言中,有兩種存取方式——順序存取、直接存取。 順序存取的特點是:每當開啟這類檔案進行讀或寫操作時,總是從檔案的開頭開始進行讀或寫。 直接存取的特點是:可以透過呼叫庫函式指定讀或寫的起始位置,然後直接從此位置開始進行讀或寫。 (3)檔案指標:是一個指向結構體型別名為 FILE 的指標。對檔案的開啟、關閉、讀、寫等操作都

必須藉助於檔案指標來完成。例如:FILE *fp; 即表示定義了一個 FILE 結構體型別的檔案指標。 (4)檔案位置指標:只是一個形象化的概念,用來表示當前讀或寫的資料在檔案中的位置。讀或寫

操作總是從檔案位置指標所指的位置開始。

2、檔案操作類庫函式

檔案操作類庫函式都定義在 stdio.h 標頭檔案裡。 (1) fopen 和 fclose 函式——開啟、關閉檔案

函式呼叫形式:檔案指標 = fopen(檔名, 檔案使用方式); fclose(檔案指標); 說明 1:fopen 函式的引數檔名和檔案使用方式都是字串。該函式呼叫成功後即返回一個

FILE 型別的指標。常用的檔案使用方式及其含義如下表所示: 檔案使用方式 含義

"r"、"w" 為只讀、只寫而開啟文字檔案。總是從檔案開頭進行讀寫操作。 "r+"、"w+" 為讀和寫而開啟文字檔案。 "a" 為在檔案後面新增內容而開啟文字檔案。檔案中原有內容保持不變。

文字 檔案

"a+" 在檔案末尾新增內容後,可以從頭開始讀。

"rb"、"wb" 以只讀、只寫而開啟二進位制檔案。總是從檔案開頭進行讀寫操作。 "rb+"、"wb+" 為讀和寫而開啟二進位制檔案。 "ab" 為在檔案後面新增內容而開啟二進位制檔案。檔案中原有內容保持不變。

二進位制 檔案

"ab+" 同"a+", 在檔案末尾新增內容後,可以從指定位置讀。 說明 2:當對檔案的讀、寫操作完成之後,必須呼叫 fclose 函式關閉檔案。 (2) fscanf 和 fprintf 函式——格式化輸入輸出。

函式呼叫形式:fscanf(檔案指標, 格式控制字串, 輸入項列表); fprintf(檔案指標, 格式控制字串, 輸出項列表); 功能:fscanf 函式是從檔案讀入格式化資料,fprintf 函式是將格式化資料寫到檔案中。 說明:這兩個函式與 scanf、printf 函式的功能相似,表一比較這四個函式的區別。 函式名 功能及資料流向 函式名 功能及資料流向 scanf 鍵盤 記憶體 printf 記憶體 顯示屏 fscanf 檔案 記憶體

輸入 格式化資料 fprintf 記憶體 檔案

輸出 格式化資料

表一

(3) fgetc 和 fputc 函式——也可寫成 getc、putc。功能是輸入、輸出一個字元。 函式呼叫形式:ch = fgetc(檔案指標); //ch 是一個字元型變數 fputc(ch, 檔案指標); 功能:fgetc(或 getc)函式是從檔案讀入一個字元,fputc(或 putc)函式是將一個字元輸出

到檔案。

說明:這兩個函式與 getchar、putchar 函式的功能相似,表二比較這四個函式的區別。 函式名 功能及資料流向 函式名 功能及資料流向 getchar 鍵盤 記憶體 putchar 記憶體 顯示屏

fgetc 檔案 記憶體 輸入

一個字元 fputc 記憶體 檔案 輸出

一個字元 表二

(4) fgets 和 fputs 函式——輸入、輸出一個字串。 函式呼叫形式:fgets(str, n, 檔案指標); //str 是字串的起始地址,n 表示讀入字串的長度 fputs(str, 檔案指標); 功能:fgets 函式是從檔案讀入字串,fputs 函式是將字串輸出到檔案。 說明 1:fgets 函式最多隻能從檔案中讀 n-1 個字元,讀入結束後,系統將自動新增'\0'。 說明 2:這兩個函式與 gets、puts 函式的功能相似,表三比較這四個函式的區別。 函式名 功能及資料流向 函式名 功能及資料流向

gets 鍵盤 記憶體 puts 記憶體 顯示屏 fgets 檔案 記憶體

輸入 字串 fputs 記憶體 檔案

輸出 字串

表三

(5) fread 和 fwrite 函式——讀、寫二進位制檔案。 函式呼叫形式:fread(buffer, size, count, 檔案指標); fwrite(buffer, size, count, 檔案指標); 引數說明:以上函式中的引數 buffer 是資料塊的指標,輸入或者準備輸出的資料存放在此內

存塊中;size 表示每個資料塊的位元組數;count 用來指定每次讀、寫的資料塊個數。 說明:fread 和 fwrite 這兩個函式只能針對二進位制檔案進行讀寫,不能操作文字檔案。

(6) feof 函式——用來判斷二進位制檔案是否結束,如果是則返回 1,否則返回 0。 函式呼叫形式:foef(檔案指標); 說明:文字檔案是以 EOF(相當於-1)作為檔案的結束標誌。二進位制檔案沒有明顯的結束

標誌,判斷二進位制檔案是否結束必須呼叫 feof 函式。 (7) fseek 函式——用來移動檔案位置指標到指定的位置上,接著的讀或寫操作就從此位置開始。

函式呼叫形式:fseek(檔案指標, offset, origin); 引數說明:以上函式中的引數 offset 是以位元組為單位的位移量,為長整型;origin 是起始點,

用以指定位移量是以哪個位置為基準,起始點既可以用識別符號(表四)來表示, 也可以用數字來表示。

位置指標起始點的識別符號 代表的起始點 數字 SEEK_SET 檔案開始 0 SEEK_END 檔案末尾 2 SEEK_CUR 檔案當前位置 1

表四

說明 1:對於文字檔案來說,位移量 offset 必須是 0。例如:fseek(pf, 0L, SEEK_SET); 表示 將檔案位置指標移到檔案開頭;fseek(pf, 0L, SEEK_END); 表示將檔案位置指標移 到檔案末尾;

說明 2:對於二進位制檔案來說,如果位移量是正整數,表示位置指標從指定的起始點處向後移 動;如果位移量是負整數,表示位置指標從指定的起始點處向前移動。

(8) ftell 函式——用來獲得當前檔案位置指標的位置,該函式返回值是一個長整型的數,表示當前位置指標相對於檔案開頭的位元組數。 函式呼叫形式:t = ftell(檔案指標); //t 是一個長整型的變數

(9) rewind 函式——又稱"反繞"函式,功能是使檔案的位置指標回到檔案開頭處。 函式呼叫形式:rewind(檔案指標);

常用庫函式

1、標準輸入輸出函式(標頭檔案 stdio.h) 函式名 函式原型 功能

scanf scanf(格式控制, 地址項列表) 從鍵盤輸入格式化資料 printf scanf(格式控制, 輸出項列表) 將格式化資料輸出到顯示屏 getchar char getchar(void) 讀取鍵盤輸入的一個字元 putchar putchar(char ch) 將一個字元輸出到顯示屏 gets gets(char *s) 讀取鍵盤輸入的一個字串,可以包含空格 puts puts(char *s) 將一個字串輸出到顯示屏

2、數學函式(標頭檔案 math.h) 函式名 函式原型 功能

sqrt double sqrt(double x) 計算並返回引數 x 的平方根值 pow double pow(double x, double y) 計算並返回引數 x 的 y 次方的值 fabs double fabs(double x) 計算並返回引數 x 的絕對值 log double log(double x) 計算並返回引數 x 的對數值,即求 ln(x)的值

3、字串處理函式(標頭檔案 string.h) 函式名 函式原型 功能

strlen int strlen(char *str) 計算 str 所指字串的長度,不包括'\0' strcpy strcpy(char *dest, char *sour) 將 sour 所指字串複製到 dest 所指的儲存空間裡 strcat strcat(char *dest, char *sour) 將 sour 所指字串貼上到 dest 所指字串的末尾

strcmp int strcmp(char *str1, char *str2) 比較 str1 和 str2 所指的兩個字串,並返回比較的結果。如果前者>後者,返回 1;如果前者<後者,返回-1;如果前者==後者,返回 0。

4、動態儲存分配函式(標頭檔案 stdlib.h) 函式名 函式原型 功能

malloc void *malloc(unsigned n) 按照形參給定的大小動態分配記憶體空間,並返回指向該記憶體塊的指標。(形參 n 即代表 n 個位元組)

calloc void *calloc(unsigned n, unsigned size) 按照形參給定的大小動態分配記憶體空間,並返回指向該記憶體塊的指標。(形參 n 即代表有 n 個數據塊,形參 size 代表每個資料塊的位元組數)

free void free(void *p) 釋放之前呼叫 malloc 或 calloc 分配的記憶體空間。形參指標 p 指向即將被釋放的記憶體空間的首地址。

5、檔案函式(標頭檔案 stdio.h) 函式名 函式原型 功能

fopen FILE *fopen(檔名, 檔案使用方式) 按照使用方式開啟檔案,返回檔案指標 fclose fclose(FILE *fp) 關閉由 fp 指向的已開啟的檔案 fscanf fscanf(FILE *fp, 格式控制, 地址列表) 從 fp 指向檔案讀入格式化資料 fprintf fprintf(FILE *fp, 格式控制,輸出項列表) 將格式化資料寫到 fp 指向檔案中 fgetc/getc char fgetc(FILE *fp) 從 fp 指向檔案讀入一個字元 fputc/putc fputc(char ch, FILE *fp) 將一個字元寫到 fp 指向檔案中 fgets fgets(char *s, int n, FILE *fp) 從 fp所指檔案的指定位置讀入一個字串(含 n-1

個字元),將此字串存放到 s 所指的記憶體空間裡。fputs fputs(char *s, FILE *fp) 將 s 所指字串寫到 fp 指向的檔案中。

fread fread(void *p, int s, int n, FILE *fp) 從 fp 指向的二進位制檔案讀出 n 個數據塊,每個資料塊有 s 個位元組大小,將讀出的資料塊存放到 p所指的記憶體空間裡。

fwrite fwrite(void *p, int s, int n, FILE *fp)從 p 所指的記憶體空間裡讀取資訊寫到 fp 指向的二進位制檔案裡,讀取的資訊由 n 個數據塊組成,每個資料塊有 s 個位元組大小。

feof int feof(FILE *fp) 判斷 fp 指向的二進位制檔案是否結束,如果是返回1,否則返回 0。

fseek fseek(FILE *fp, long n, int origin) 移動 fp 指向的檔案的位置指標,使之移動到距離origin 起始點 n 個位元組的位置。

ftell long ftell(FILE *fp) 獲得並返回 fp 指向的檔案當前位置指標相當於檔案開頭的位元組數。

rewind rewind(FILE *fp) 反繞函式,使檔案位置指標回到檔案開頭。

其 它

1、C 語言中的常用關鍵字

(1) 與資料型別有關的:char、int、float、double、short、long、signed、unsigned、void、struct、union、typedef、enum、sizeof

(2) 與儲存類別有關的:auto、static、register、extern (3) 與程式控制結構有關的:if、else、switch、case、default、while、do、for、break、continue、return、

goto

2、容易用錯的運算子

(1)= 是賦值號,功能是將其右側表示式的值賦值給左側的變數,注意它的左側只能是變數名。 == 是關係運算符中的等於號,功能是比較其左右兩側表示式的值是否相等。 (2)* 當把它放在兩個表示式中間時作乘號使用(雙目運算子);當變數定義時把它放在變數名前時它

是一個標誌,標誌此時定義的變數時指標變數;當把它放在變數名前作為表示式中的一部分,則

它是取內容符(單目運算子)。 (3)&& 是邏輯與運算子 對比 & 是按位與運算子(雙目) 對比 & 是取地址符(單目)

|| 是邏輯或運算子 對比 | 是按位或運算子 ! 是邏輯非運算子 對比 ~ 是按位取反運算子

(4)^ 是按位異或運算子,注意它不是計算次方的運算子,計算次方需呼叫 pow 庫函式完成。 (5)sizeof 是求位元組數運算子,注意它不是庫函式,而是運算子。注意它與 strlen 庫函式的區別。 (6)! 邏輯非運算子(單目) != 是關係運算符中的不等於號(雙目) (7), 是逗號運算子,是逗號 C 語言中比較特殊的一個運算子,其優先順序最低。 (8)? : 是條件運算子,是指 C 語言中唯一的三目運算子。

13
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • TensorFlow 2從零開始構建YOLOv3目標檢測網路