限定修飾符const

const int a = 1;
int const a = 1;

const關鍵字修飾變量a,表示a是一個整型變量,且這個變量的值是不可改變的。這兩個定義的做用同樣,編譯後變量a分配在只讀數據段中,這個數據段在一塊只讀的內存區域中,任何對這塊區域的操做都是非法的。函數

以下面的程序:spa

#include <stdio.h>

int main(void)
{
  int const a = 100;
  a = 200;
  return 0;
}

編譯器會報錯:指針

因此在定義的時候對該變量溫馨化是使得該變量具備值的惟一機會。調試

 

const關鍵字修飾指針--在指針定義以前

const關鍵字在指針變量的定義以前,以下所示:code

int const a = 100;
const int *p;  //指針指向的內容不能改變
//等同於 int const *p;
p = &a;

該定義表示p是一個指針變量,指向一個整型變量的存儲空間,而且這個整型變量是一個不可改變的值的變量。也就是說指針p是能夠改變的,而指針所指向的內容是不可改變的。內存

例如:開發

#include <stdio.h>

int main(void)
{
  int a = 100;
  int b = 200;
  const int *p;
  p = &a;
  printf("a = %d\n", *p);
  *p = 200;   //錯誤,指針所指向的內容(經過*p方式)不能改變
  p = &b;     //正確,指針自己能夠改變
  printf("a = %d\n", *p);
  return 0;
}

運行結果爲:字符串

const關鍵字修飾指針--在指針定義之中

const關鍵字在指針變量的定義之中:編譯器

int a = 100;
int * const p = &a;  //指針自己不能改變

該定義表示p是一個指針變量,指向一個整型變量的存儲空間,而且這個整型變量是一個能夠改變值的變量。而指針p的值不能改變,只能永遠指向這個內存單元,也就是說指針p是不能夠改變的,而指向的內容是能夠改變的。string

例如:

#include <stdio.h>

int main(void)
{
  int a = 100;
  int b = 200;
  int  * const p = &a;
  printf("a = %d\n", *p);
  *p = 200;   //正確,指針所指向的內容(經過*p方式)能夠改變
  //p = &b;     //指針自己不能夠改變
  printf("a = %d\n", *p);
  return 0;
}

運行結果:

const關鍵字修飾指針--在指針定義以前和定義之中

在指針變量定義以前和定義之中均有關鍵字,以下:

const int a = 100;
int const * const p = &a; //指針和指針指向的內容都不能改變

該定義表示a是一個指針變量,指向一個整型變量的存儲空間。這個整型變量是一個不能改變值的變量,並且指針a的值也不能改變:

例如:

#include <stdio.h>

int main(void)
{
  int a = 100;
  int b = 200;
  int const * const p = &a;
  printf("a = %d\n", *p);
  *p = 200;   //錯誤,指針所指向的內容不能改變
  p = &b;     //錯誤,指針自己不能夠改變
  printf("a = %d\n", *p);
  return 0;
}

編譯結果:

指向非const變量的指針或者非const變量的地址能夠傳給指向const變量的指針,C語言能夠作隱式轉換,以下:

int a = 100;
const int *p;
p = &a;  //常量指針指向一個普通變量

可是指向const變量的指針,或者const變量的指針幣能夠傳給非const變量的指針,以避免意外修改了const存儲區的內容,以下:

const int a = 100;
int *p = &a;  //普通指針不能指向一個常量變量

使用const關鍵字的意義

  • 合理的只用cosnt關鍵字,可使編譯器保護那些不但願被改變的參數,防止被意外修改,能夠較少bug的出現。
  • 關鍵字const是爲了告訴用戶這個參數的引用目的。例如一個函數的參數是const char*,這樣用戶就能夠放心的傳給它char*或者const char*指針,而沒必要擔憂指針所指的內存區域被改寫
  • 經過給編譯器一些附加信息,是const關鍵字也許能產生更緊湊的代碼

第一點是最重要的,來看一個程序:

#include <stdio.h>

//將全部空格替換爲"_",失敗返回NULL
char * replace(char *str)
{
  char *p;
  if(str == NULL)
    return NULL;
  p = str;
  while(*p != '\0'){
    if(*p == ' ')
      *p = '_';  //進行字符串的替換
    p++;
  }
  return p;
}

int main(void)
{
  char *p = "hello world and china\n";
  if(replace(p) != NULL)
    printf("the string : %s\n", p);
  return 0;
}

編譯並運行程序:

程序出現了段錯誤,說明內存訪問出錯了,這個錯誤出如今*p = '_';這個語句上。該語句將字符串的值修改,可是做爲replace()函數的參數的源字符串是一個字符串常量,這個常量被分配在只讀數據段中。所以對次字符串的操做形成了非法內存訪問,出現了段錯誤。

若是使用const關鍵字能夠很好的預防這個問題。

修改上面的程序,使用const關鍵字對字符創常量進行聲明,編譯器會發現修改常量的錯誤:

#include <stdio.h>

//將全部空格替換爲"_",失敗返回NULL
const char * replace(const char *str)  //使用const修飾變量
{
  const char *p;
  if(str == NULL)
    return NULL;
  p = str;
  while(*p != '\0'){
    if(*p == ' ')
      *p = '_';  //進行字符串的替換
    p++;
  }
  return p;
}

int main(void)
{
  const char *p = "hello world and china\n"; //將源字符串聲明爲const變量
  if(replace(p) != NULL)
    printf("the string : %s\n", p);
  return 0;
}

編譯結果:

編譯器報錯,提示*p = '_';出錯,程序試圖寫只讀數據段的錯誤被編譯器發現了,這時開發人員能夠很容易就能夠發現這個錯誤。原本在運行時纔出現的錯誤,在編譯階段就由編譯器發現了,這樣就省了大量的調試時間,這對程序開發來講是頗有益的。

相關文章
相關標籤/搜索