只要學過C語言的,都有知道const這個關鍵字,知道是用來定義常量的,如果一個變量被const修飾,那么它的值就不能再被改變,那么還有什么其他作用呢?
一、const常用作用
1.修飾局部變量
const int n=5;
int const n=5;/*二者是等價的,均表示變量n的值不能被改變了*/
注意:在使用const修飾變量時,一定要給變量初始化,否則之后就不能賦值了!
接下來看看const用於修飾常量靜態字符串,例如:
const char* str="fdsafdsa";
如果沒有const的修飾,我們可能會在后面有意無意的寫str[4]=’x’這樣的語句,這樣會導致對只讀內存區域的賦值,然后程序會立刻異常終止。有了const,這個錯誤就能在程序被編譯的時候就立即檢查出來,這就是const的好處。讓邏輯錯誤在編譯期被發現。
2. 常量指針與指針常量
常量指針是指針指向的內容是常量,可以有一下兩種定義方式。
const int * n;
int const * n;
需要注意的是一下兩點:
1、常量指針說的是不能通過這個指針改變變量的值,但是還是可以通過其他的引用來改變變量的值的。
int a=5;
const int* n=&a;
a=6;
2、常量指針指向的值不能改變,但是這並不是意味着指針本身不能改變,常量指針可以指向其他的地址。
int a=5;
int b=6;
const int* n=&a;
n=&b;
指針常量是指指針本身是個常量,不能在指向其他的地址,寫法如下:
int *const n;/*指針常量*/
需要注意的是,指針常量指向的地址不能改變,但是地址中保存的數值是可以改變的,可以通過其他指向改地址的指針來修改。
int a=5;
int *p=&a;
int* const n=&a;
*p=8;
區分 常量指針和指針常量的關鍵就在於星號的位置,以星號為分界線
如果const在星號的左邊,則為常量指針
如果const在星號的右邊,則為指針常量
將星號讀作‘指針’,將const讀作‘常量’的話,內容正好符合。int const * n;是常量指針,int *const n;是指針常量。
int const *n; /*是常量指針*/
int * const n; /*是指針常量*/
指向常量的常指針
指針指向的位置不能改變且也不能通過這個指針改變變量的值。(但是仍然可以用其他的普通指針改變變量的值)
const int* const p;
3. const修飾函數的參數
1> 防止修改指針指向的內容,如:
void StringCopy(char *dst, const char *src);
2> 防止修改指針所指向的地址,如:
void swap(int * const p1, int * const p2);
4. 修飾函數的返回值
如果給以“指針傳遞”方式的函數返回值加 const 修飾,那么函數返回值(即指針)的內容不能被修改,該返回值只能被賦給加const 修飾的同類型指針。
例如,若有如下函數:
const char* GetString(void);
當用以下語句來接收函數返回值時將出錯:
char *str = GetString(); /*錯誤*/
應當改寫為:
const char *str = GetString(); /*正確*/
二、const和#define區別
關鍵字const用來定義常量,如果一個變量被const修飾,那么它的值就不能再被改變,我想一定有人有這樣的疑問,C語言中不是有#define嗎,干嘛還要用const呢,我想事物的存在一定有它自己的道理,所以說const的存在一定有它的合理性,與預編譯指令相比,const修飾符有以下的優點:
1、預編譯指令只是對值進行簡單的替換,不能進行類型檢查
2、可以保護被修飾的東西,防止意外修改,增強程序的健壯性
3、編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。
三、const面試題
1. const聲明的變量只能被讀
const int i=5;
int j=0;
...
i=j; //非法,導致編譯錯誤
j=i; //合法
2.必須初始化
const int i=5; //合法
const int j; //非法,導致編譯錯誤
3.如何在另一.c源文件中引用const常量
extern const int i; //合法
extern const int j=10; //非法,常量不可以被再次賦值
4. 可以進行類型檢查
用const方法可以使編譯器對處理內容有更多了解。
#define I=10
const long &i=10;
...
char h=I; //沒有錯
char h=i; //編譯警告,可能由於數的截短帶來錯誤賦值。
說明:由於編譯器的優化,使得在const long i=10時,i不被分配內存,而是已10直接代入以后的引用中,以致在以后的代碼中沒有錯誤,為達到說教效果,特別地用&i明確地給出了i的內存分配。不過一旦你關閉所有優化措施,即使const long i=10也會引起后面的編譯錯誤。
5.可以避免不必要的內存分配
#define STRING "abcdefghijklmn/n"
const char string[]="abcdefghijklm/n";
...
printf(STRING); //為STRING分配了第一次內存
printf(string); //為string一次分配了內存,以后不再分配
...
printf(STRING); //為STRING分配了第二次內存
printf(string);
...
由於const定義常量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝。
6.可以通過函數對常量進行初始化
int value();
const int i=value();
假定對ROM編寫程序時,由於目標代碼的不可改寫,本語句將會無效,不過可以變通一下:
const int &i=value();
只要令i的地址處於ROM之外,即可實現:i通過函數初始化,而其值有不會被修改。
7.是不是const的常量值一定不可以被修改呢?
const int i=0;
int *p=(int*)&i;
*p=100;
通過強制類型轉換,將地址賦給變量,再作修改即可以改變const常量值。
8.如何分清數值常量和指針常量:
int ii=0;
const int i=0; //i是常量,i的值不會被修改
const int *p1i=&i; //指針p1i所指內容是常量,可以不初始化
int * const p2i=ⅈ //指針p2i是常量,所指內容可修改
const int * const p3i=&i; //指針p3i是常量,所指內容也是常量
p1i=ⅈ //合法
*p2i=100; //合法