C語言關鍵字const作用及其應用

只要學過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;

需要注意的是一下兩點:

  • 常量指針說的是不能通過這個指針改變變量的值,但是還是可以通過其他的引用來改變變量的值的。
int a=5;
const int* n=&a;
a=6;
  • 常量指針指向的值不能改變,但是這並不是意味着指針本身不能改變,常量指針可以指向其他的地址。
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);
  1. 防止修改指針所指向的地址,如:
void swap(int * const p1, int * const p2);
  1. 修飾函數的返回值

如果給以“指針傳遞”方式的函數返回值加 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;   //合法
  1. 必須初始化
const int i=5;    //合法
const int j;      //非法,導致編譯錯誤
  1. 如何在另一.c源文件中引用const常量
extern const int i;     //合法
extern const int j=10;  //非法,常量不可以被再次賦值
  1. 可以進行類型檢查

用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也會引起後面的編譯錯誤。

  1. 可以避免不必要的內存分配
#define STRING "abcdefghijklmn/n"
const char string[]="abcdefghijklm/n";
...
printf(STRING);   //爲STRING分配了第一次內存
printf(string);   //爲string一次分配了內存,以後不再分配
...
printf(STRING);   //爲STRING分配了第二次內存
printf(string);
...

由於const定義常量從彙編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝。

  1. 可以通過函數對常量進行初始化
int value();
const int i=value();

假定對ROM編寫程序時,由於目標代碼的不可改寫,本語句將會無效,不過可以變通一下:

const int &i=value();

只要令i的地址處於ROM之外,即可實現:i通過函數初始化,而其值有不會被修改。

  1. 是不是const的常量值一定不可以被修改呢?
const int i=0;
int *p=(int*)&i;
*p=100;

通過強制類型轉換,將地址賦給變量,再作修改即可以改變const常量值。

  1. 如何分清數值常量和指針常量:
  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;                 //合法
發佈了15 篇原創文章 · 獲贊 13 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章