?
const基本介紹
const是constant的簡寫,用來定義常量,如果一個變量被const修飾,那么它的值就不能再被改變。
const與define的區別
1、define是預編譯指令,定義的宏是在預處理階段展開的,而const是普通變量的定義,是只讀變量,且是在編譯運行階段使用的。
2、define定義的是常量,define定義的宏在編譯后消失了,它不占用內存,而const定義的常變量本質上仍然是一個變量,具有變量的基本屬性,有類型、占用存儲單元,除了不能作為數組的長度,用const定義的常變量具有宏的優點,而且使用更方便。
3、define定義的對象沒有數據類型,編譯器只能機械地進行字符替換,沒有類型安全檢查,即會出現“邊際問題”或者是“括號問題”。而const定義的是變量,有數據類型。
const作用
1、可以用來修飾變量,修飾函數參數,修飾函數返回值,且被const修飾的東西,都受到強制保護,可以預防其它代碼無意識的進行修改,從而提高了程序的健壯性(是指系統對于規范要求以外的輸入能夠判斷這個輸入不符合規范要求,并能有合理的處理方式。ps:即所謂高手寫的程序不容易死);
2、使編譯器保護那些不希望被修改的參數,防止無意代碼的修改,減少bug;
3、增強代碼的可讀性,給讀代碼的人傳遞有用的信息,聲明一個參數,是為了告訴用戶這個參數的應用目的。
const用法介紹
1、修飾局部變量、全局變量及字符串常量
示例代碼:
?
#include?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? #include #include ? const?int?a?=?10;???//const修飾的全局變量放在常量區 //1.const修飾的全局變量,即使語法通過,但是運行的時候會受到常量區的保護,段錯誤,運行失敗 void?test01() { ????//a?=?100;???//直接修改語法不通過 ????int?*p?=?&a; ????*p?=?100;????//間接修改語法通過,運行時產生段錯誤 ????printf("a??%d ",a); } //2.const修飾的局部變量 void?test02() { ????const?int?b?=?10;???//分配到棧上 ????//b?=?100;??//直接修改語法不通過 ???? ????//c語言下稱為偽常量 ????int?*p?=?&b; ????*p?=?100; ????printf("b??%d ",*p);?//間接修改成功 ? ????//int?a[b];??偽常量是不可以初始化數組的 } ?//3.字符串常量 void?test03() { ????char?*p1?=?"hello?world"; ????char?*p2?=?"hello?world"; ????char?*p3?=?"hello?world"; ???? ????printf("%s ",p1); ????printf("%s ",?p2); ????printf("%s ",?p3); ????printf("%s ",&"hello?world");???//四個輸出的結果一樣 ? ????//p1[0]?=?'z';?//不允許修改字符串常量 ????printf("p1[0]???%c ",p1[0]);??//可以輸出 } ???? int?main() { //??test01(); //??test02(); ????test03(); ???? ????return?0; }??
?
const修飾的普通變量:定義的時候就要給它賦初值,之后哪怕是賦相同值都不行。const修飾的局部變量還是變量,直接修改編譯器報錯,可以間接修改,存放在棧區,代碼塊結束時釋放。
const修飾全局變量:直接修改編譯器報錯,間接修改編譯器也許會通過,但運行時會報錯(段錯誤)。const修飾的全局變量存放在全局(靜態)存儲區,編譯期最初將其保存在符號表中,第一次使用時為其分配內存,在程序結束時釋放。
const修飾字符串常量:字符串常量位于文字常量區(也有文章歸類于代碼區),本身就不允許被修改,如果沒有const的修飾,我們可能會在后面有意無意的修改字符串常量,這樣會導致對只讀內存區域的賦值,然后程序會立刻異常終止。有了const,這個錯誤就能在程序被編譯的時候就立即檢查出來,這就是const的好處。讓邏輯錯誤在編譯期被發現。
2、修飾指針
常量指針和指針常量傻傻分不清楚,以下方法幫助你來區分二者:區分常量指針和指針常量的關鍵就在于星號的位置,我們以星號為分界線。
如果const在星號的左邊,則為常量指針
如果const在星號的右邊則為指針常量
如果我們將星號讀作‘指針’,將const讀作‘常量’的話,內容正好符合。
int const * num;是常量指針,就是*num指向的數據不可以改,num指向的地址可以修改,
int const num;是指針常量,就是num指向的地址不可以修改,num指向的數據可以修改。
代碼示例:
?
//第一種,常量指針 const?int?*p1;??????//p本身不是const的,而p指向的變量是const int?const?*p2;??????//p本身不是const的,而p指向的變量是const #include?int?main() { ????int?a?=?5; ????int?b?=?20;? ????const?int?*p?=?&a;? //??*p?=?100;???//編譯器報錯 ????p?=?&b;?????//完全可以 ????printf("%d ",*p);?//間接修改成功?????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????return?0; }
?
需要注意的是以下兩點:
1、常量指針說的是不能通過這個指針改變變量的值,但是還是可以通過其他的方式來改變變量的值的。
2、常量指針指向的值不能改變,但是這并不是意味著指針本身不能改變,常量指針可以指向其他的地址。
?
//第二種,指針常量 int*?const?p3;?????//p本身是const的,而p指向的變量不是const #include?int?main() { ????int?a?=?5; ????int?b?=?20;? ????int?*p?=?&a;? ????int*?const?n?=?&a;? //??n?=?&b;??//error:?assignment?of?read-only?variable?‘n’????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ????*p?=?8; ????printf("%d ",a); ????return?0; }
?
指針常量是指指針本身是個常量,不能在指向其他的地址,需要注意的是,指針常量指向的地址不能改變,但是地址中保存的數值是可以改變的,可以通過其他指向該地址的指針來修改。
?
????//第三種 const?int*?const?p4;????????//p本身是const的,而p指向的變量也是const
?
是以上兩種的結合,指針指向的位置不能改變并且也不能通過這個指針改變變量的值,但是依然可以通過其他的普通指針改變變量的值。
修飾函數的參數
const修飾參數是為了防止函數體內可能會修改參數原始對象。因此,有三種情況可討論:
1、函數參數為值傳遞:
值傳遞(pass-by-value)是傳遞一份參數的拷貝給函數,因此不論函數體代碼如何運行,也只會修改拷貝而無法修改原始對象,這種情況不需要將參數聲明為const。例如:void func(int x)不用寫成void func(const int x)
2、函數參數為指針:
指針傳遞(pass-by-pointer)只會進行淺拷貝,拷貝一份指針給函數,而不會拷貝一份原始對象。根據上面對指針常量、常量指針等討論,同樣分為三種情況:
2.1 防止修改指針指向的內容
典型C庫函數:char *strcpy(char *dest, const char *src);
2.2 防止修改指針指向的地址
void swap ( int * const p1 , int * const p2 );指針p1和指針p2指向的地址都不能修改。
2.3 防止修改指針指向的內容和地址
4.修飾函數的返回值
1、如果函數返回值采用“值傳遞方式”,由于函數會把返回值復制到外部臨時的存儲單元中,加const 修飾沒有任何價值。例如把函數int GetInt(void) 寫成const int GetInt(void)是沒有意義的。
2、如果給以“指針傳遞”方式的函數返回值加 const 修飾,那么函數返回值(即指針)的內容不能被修改,該返回值只能被賦給加const 修飾的同類型指針。
?
const?char?*?GetString(void); char?*str?=?GetString();?//error:?conflicting?types?for?‘str’ const?char?*str?=?GetString();??//這種用法才是正確的
?
審核編輯:湯梓紅
評論