今天來講講c中的保留字。
保留字(reserved word)
保留字又稱關鍵字。
指在高階語言中已經定義過的字,使用者不能再將這些字作爲變數名或過程名使用。
每種程式設計語言都規定了自己的一套保留字。
例如:BASIC語言規定不能使用LIST作爲變數名或過程名,因爲LIST是一個BASIC語言專用於顯示記憶體程式的命令。
C有22+10 = 32個關鍵字
C++ 有22+10+11+20 = 63 個關鍵字
JAVA 有22+ 9+ 17 = 48 個關鍵字
ps:以上內容來自百科。其中,C89中,(C語言標準)中,
型別說明保留字:int,long,short,float,double,char,unsigned,signed,const,void,volatile,enum,struct,union
語句定義保留字:if,else,goto,switch,case,do,while,for,continue,break,return,default,typedef
儲存類說明保留字:auto,register,extern,static
長度運算子保留字:sizeof
具體含義如下:
關鍵字 | 含義 |
---|---|
auto | 指定變數的儲存型別,是預設值 |
break | 跳出回圈或switch語句 |
case | 定義switch中的case子句 |
char | 定義字元型變數或指針 |
const | 定義常數或參數 |
continue | 在回圈語句中,回到回圈體的開始處重新執行回圈 |
default | 定義switch中的default子句 |
do | 定義do-while語句 |
double | 定義雙精度浮點數變數 |
else | 條件不滿足的其他情況 |
enum | 定義列舉型別 |
extern | 宣告外部變數或函數 |
float | 定義浮點型變數或指針 |
for | 定義for語句 |
goto | 定義goto語句 |
if | 定義if語句或if-else語句 |
int | 定義整型變數或指針 |
long | 定義長整型變數或指針 |
register | 指定變數的儲存型別是暫存器變數,Turbo c中用自動變數代替 |
return | 從函數返回 |
short | 定義短整型變數或指針 |
signed | 定義有符號的整型變數或指針 |
sizeof | 獲取某種型別的變數或數據所佔記憶體的大小,是運算子 |
static | 指定變數的儲存型別是靜態變數,或指定函數是靜態函數 |
struct | 定義結構體型別 |
switch | 定義switch語句 |
typedef | 爲數據型別定義別名 |
union | 定義無符號的整型或字元型變數或指針 |
unsigned | 定義無符號的整型變數或數據 |
void | 定義空型別變數或空型別指針,或指定函數沒有返回值 |
volatile | 變數的值可能在程式的外部被改變 |
while | 定義while或do-while語句 |
下面 下麪,就幾個我認爲比較容易用錯的保留字進行分析,主要包括 return, void, const, break, continue
至於儲存類說明保留字,也是難點之一,在之前部落格已經描述過了,這裏就不在重複了。
以下內容參閱《c程式設計競賽實訓教學》和一些大牛部落格結合自己看法寫的。
return:結束一個函數並返回其後面表達式中的值。
初學的時候,有些不理解main 函數中return 0;有什麼用,在寫程式的時候老是忘記帶上了。其實,帶上return 0;是很有必要的。
main函數的返回值用於說明程式的退出狀態,如果返回0,表示程式正常退出,否則表示程式異常退出。返回值傳遞給程式的啓用者(操作系統)。
如果沒有寫return語句的話,c99(c語言標準)規定編譯器自動在生成的目標檔案中加入return 0;表示正常退出。
所以,爲了程式碼規範,我們一般都必須帶上return 0;
具體操作----- return (表達式);
其中,括號是可以省略的。 一般不省略,如果返回值爲表示式的時候容易造成混淆。
return返回值的型別,一般是函數定義的型別,如果return後表示式的值型別和函數值的型別不一致,則以函數函數型別爲準,即:函數型別決定返回值型別。
需要注意的一點,也是易錯的一點是:return不能返回指向區域性變數的型別。----因爲在函數結束時區域性變數被自動銷燬(上篇部落格提及的區域性變數的生存週期),則返回的指針爲指向已釋放的空間,再通過此指針進行操作就會產生錯誤。
下面 下麪通過程式具體說明:
- #include<stdio.h>
- int *test()
- {
- int num=3,*ptr; //num爲區域性變數
- ptr = #
- return ptr; //這裏,返回了指向區域性變數的指針
- }
- int main ( )
- {
- int i=4,*p;
- p = test();
-
- printf("%d,%d\n",i,*p);
- return 0;
- }
程式中,函數test的返回值爲指向區域性變數num的指針,當主函數呼叫test函數的時候,返回ptr指針並且賦值給p指針變數,即num變數的地址賦給了p,但是必須明白,在test函數結束的時候,區域性變數num的空間被釋放了,這樣用p來參照這個空間就會出錯。
乍一看,和預期的一樣,但是實際上,這樣的程式是存在隱患的。
下面 下麪改改這個程式,就知道錯在哪了。
- #include<stdio.h>
- int *test()
- {
- int num=3,*ptr; //num爲區域性變數
- ptr = #
- return ptr; //這裏,返回了指向區域性變數的指針
- }
- int test2()
- {
- int x = 9,y=7;
- return (x+y);
- }
- int main ( )
- {
- int i=4,*p;
- p = test();
- i = test2();
- printf("%d,%d\n",i,p);
- return 0;
- }
執行結果: 15,7(也可能是15,9視具體環境而定。)這正印證了我們之前說過了,這樣的返回存在隱患。 在test函數呼叫完後,系統釋放之前給num分配的空間,但是p指針仍然指向那塊區域。
在呼叫test2的時候,系統要爲x,y分配空間。這時候就會把之前釋放的那塊空間給x,y再次分配使用,使用在賦值語句後,該空間的值發現了改變,使得p發生了改變。
所以,切記 return不能返回指向區域性變數的型別。
void :void爲空型別。 void *爲空型別指針。
其中,void a;是不允許的。 每次定義一個變數,系統都會爲其分配空間,而void型別無法確定,系統就不知道該爲它分配多大的空間,顯然是不合理的。
void *p;是允許的, 因爲這是一個指針變數,系統都是預設分配四個位元組的空間,至於具體指向的空間總存放的數據型別,就由使用者自行操作。
並且,在操作的時候,要把該void指針強制轉換爲相應型別的指針後纔可進行操作。
如:
- void p;
- int a=5,b;
- p = &a;
- b = (int )p;//強轉爲int型指針。
const:constant的縮寫,意爲不變。 即用const修飾的變數的不允許改變的。也可稱爲只讀變數。
例如: int const m = 10; const int m = 10; (二者可以認爲等價,const定義一般的變數比較簡單。例如該例中都是限定m爲10)
但是要注意一點,只讀變數雖然值不能改變,但它還是變數,不是常數。
如 int const M = 10; int a[M]; 這樣定義陣列是錯誤的。我們知道,定義陣列時,陣列元素個數必須是常數(這樣系統才知道要分配多大的空間),而M的本質是變數,只是值不改變的變數而已。
所以,一般我們定義陣列採用這樣的操作: #define M 10 int a[M];
下面 下麪討論下const定義指針,這就比較複雜了。
- const int p;//const修飾的是p,表示p可變(地址可變),p所指空間的內容不可變(數據不變)
- int const p;//const修飾的是p,表示p可變(地址可變),p所指空間的內容不可變(數據不變)
- int const p;//const修飾的是p,表示p不可變(地址),p所指空間內容可變(數據可變)
- const int const p; //表示p和p所指的空間內容均不可變
至於地址,數據,拿const int p;舉例。 此時,p=&a;操作是允許的,(修改地址)。而p=10;是允許的(試圖改變數據造成錯誤)。在判讀是修飾p還是p時,我們可以先將定義中的型別識別符號去掉(int),再觀察const後面修飾的內容。
至於break和continue,二者關係比較密切,結合探討。 break退出當前回圈,continue退出當次回圈
continue
1、結束本次回圈(不執行本次回圈中continue後面的語句),繼續下次回圈條件判斷;
2、不可作用於switch語句。當在switch中使用,這個continue實際是作用於其所屬的回圈結構;若它不屬於任何一個回圈,程式將因此報錯!
break
1、結束整個回圈,並停止下次回圈條件判斷;
2、可以作用於switch語句。
具體區別如下:
break和continue的區別如下:
1. break可用於switch語句,表示跳出整個switch塊,而continue則不能用於switch語句
2. 它們都可用於回圈語句的回圈體,所謂的區別也應該是它們對回圈次數的影響不同。break用於立即退出當前回圈,而continue僅跳過當次回圈(本次回圈體內不執行continue語句後的其它語句,但下次回圈還會執行)。舉例說明。
- int i;
- int s = 0;
- for (int i = 1; i <= 10; i++)
- {
- if (i == 6) break;
- s += i;
- }
上面的回圈會因爲break語句而在i=6時提前終止,這樣s的最終值就是1+2+3+4+5
如將break換成continue
- int i;
- int s = 0;
- for (int i = 1; i <= 10; i++)
- {
- if (i == 6) continue;
- s += i;
- }
當i=6時就不會將i累加到s中,s的最終值是1+2+3+4+5+7+8+9+10,唯獨少一個6