一、常規用法
關鍵字const用來定義只讀變量,被const定義的變量它的值是不允許改變的,即不允許給它重新賦值,即使是賦相同的值也不可以。所以說它定義的是只讀變量,這也就意味着必須在定義的時候就給它賦初值。
用const修飾變量的格式通常為
1 const type name = value;
代碼示例;(第一種方式)
1 const int Max;
也可以寫成下面這種(第二種方式)
1 int const Max;
通常情況下使用第一種方式(建議將被const修飾的變量的首字母大寫),被 const 修飾的變量一旦被創建后其值就不能再改變,所以常量必須在定義的同時賦值(初始化),后面的任何賦值行為都將引發錯誤。
錯誤代碼示例:

二、const與指針
const與指針配合使用有兩種作用,一是限制指針變量,二是限制指針變量指向的數據
限制指針變量本身
1 int * const p2;//const修飾的是指針變量
限制指針變量本身的意思是,指針變量本身的值不能被修改,所以被 const 修飾的指針變量指針只能在定義時初始化,不能定義之后再賦值,錯誤代碼如下

限制指針變量指向的數據
1 const int *p1; 2 int const *p1;
上面兩種寫法都可以,一般使用第一種,限制指針變量指向的數據的意思就是指針可以指向不同的變量(指針本身的值可以修改),但是不能用指針修改指針指向的數據的值,錯誤代碼如下

區分const是限制的指針變量還是指針變量指向數據的值:const 離變量名近就是用來修飾指針變量的,離變量名遠就是用來修飾指針指向的數據,如果近的和遠的都有,那么就同時修飾指針變量以及它指向的數據。
當然也可以同時限制指針變量和指針變量指向的數據的值,寫法如下
1 const int * const p2;
上面這種寫法使指針變量和指針變量指向數據的值都不能修改
三、const和函數形參
在很多情況下,const修飾的變量完全可以使用 #define命令代替,const 通常用在函數形參中,在C標准庫中有很多函數形參都用const限制了,為了防止在函數內部修改指針指向的數據,例如 fopen_s

四、const和非const類型的轉換
當一個指針變量 str1 被 const 限制時,並且類似const char *str1這種形式,說明指針指向的數據不能被修改;如果將 str1 賦值給另外一個未被 const 修飾的指針變量 str2,就有可能發生危險。
因為通過 str1 不能修改數據,而賦值后通過 str2 能夠修改數據了,意義發生了轉變,所以編譯器不提倡這種行為,會給出錯誤或警告,如下圖

也就是說,const char *和char *是不同的類型,不能將const char *類型的數據賦值給char *類型的變量。但反過來是可以的,編譯器允許將char *類型的數據賦值給const char *類型的變量。這種限制很容易理解,char *指向的數據有讀取和寫入權限,而const char *指向的數據只有讀取權限,降低數據的權限不會帶來任何問題,但提升數據的權限就有可能發生危險。

上面這種情況是編譯器是允許的
五、const與#define
1、define是預編譯指令,而const是普通變量的定義。define定義的宏是在預處理階段展開的,而const定義的只讀變量是在編譯運行階段使用的。
2、const定義的是變量,而define定義的是常量。define定義的宏在編譯后就不存在了,它不占用內存,因為它不是變量,系統只會給變量分配內存。但const定義的常變量本質上仍然是一個變量,
具有變量的基本屬性,有類型、占用存儲單元。可以說,常變量是有名字的不變量,而常量是沒有名字的。有名字就便於在程序中被引用,所以從使用的角度看,除了不能作為數組的長度,
用const定義的常變量具有宏的優點,而且使用更方便。所以編程時在使用const和define都可以的情況下盡量使用常變量來取代宏,但有些情況下const常變量是無法代替define宏的下面會舉例。
3、const定義的是變量,而宏定義的是常量,所以const定義的對象有數據類型,而宏定義的對象沒有數據類型。所以編譯器可以對前者進行類型安全檢查,而對后者只是機械地進行字符替換,
沒有類型安全檢查。這樣就很容易出問題,即“邊際問題”或者說是“括號問題”。
六、補充
如果要定義數組的最大長度,這個時候就不能用const,const定義的常變量,終究是一個變量,不能作為數組的長度,示例代碼如下

這種情況下就只能使用define來定義數組的最大長度(這里有個比較坑的地方是 VS2017遇到這種情況編譯器會報錯,而VC2010的編譯器就不會報錯,估計VC2010是沒有那么嚴格)
