初識(shí)C++的const關(guān)鍵字,常量與常變量
C語(yǔ)言的const
注:c語(yǔ)言部分cosnt引用自《c語(yǔ)言深度剖析》一書(shū)。
1. const關(guān)鍵字
const 是 constant 的縮寫(xiě),是恒定不變的意思,也翻譯為常量、常數(shù)等。很不幸,正是因?yàn)檫@一點(diǎn),很多人都認(rèn)為被 const 修飾的值是常量。這是不精確的,精確的說(shuō)應(yīng)該是只讀的變量,其值在編譯時(shí)不能被使用,因?yàn)榫幾g器在編譯時(shí)不知道其存儲(chǔ)的內(nèi)容。或許當(dāng)初這個(gè)關(guān)鍵字應(yīng)該被替換為 readonly。那么這個(gè)關(guān)鍵字有什么用處和意義呢?
const 推出的初始目的,正是為了取代預(yù)編譯指令,消除它的缺點(diǎn),同時(shí)繼承它的優(yōu)點(diǎn)。我們看看它與 define 宏的區(qū)別。 (很多人誤以為 define 是關(guān)鍵字,然而并不是)。在C和C++中都有const關(guān)鍵字,但是他們的各自表示的意義是有所差別的。
2. const 修飾的只讀變量
定義 const 只讀變量,具有不可變性。
例如:
const int Max=100;
intArray[Max];
這里請(qǐng)?jiān)?Visual C++6.0 里分別創(chuàng)建.c 文件和.cpp 文件測(cè)試一下。你會(huì)發(fā)現(xiàn)在.c 文件中,編譯器會(huì)提示出錯(cuò),而在.cpp 文件中則順利運(yùn)行。為什么呢?我們知道定義一個(gè)數(shù)組必須指定其元素的個(gè)數(shù)。這也從側(cè)面證實(shí)在 C 語(yǔ)言中, const 修飾的 Max 仍然是變量,只不過(guò)是只讀屬性罷了;而在 C++里,擴(kuò)展了 const 的含義,我們?cè)诤竺嬗懻摗?/p>
注意: const 修飾的只讀變量必須在定義的同時(shí)初始化,想想為什么?
答:只讀,不可寫(xiě)。因此定義后不可再次賦值。
留一個(gè)問(wèn)題: case 語(yǔ)句后面是否可以是 const 修飾的只讀變量呢?請(qǐng)動(dòng)手測(cè)試一下。
答:case后面只能跟整形或者字符型的常量或常量表達(dá)式;因此,在C語(yǔ)言中不可以,C++中可以。void select(int a){ const int b = 10; switch (a) { case b: cout << "hello" << endl; break; default: break; }}int main(){ select(10); return 0;}
3. 節(jié)省空間,避免不必要的內(nèi)存分配,同時(shí)提高效率
編譯器通常不為普通 const 只讀變量分配存儲(chǔ)空間,而是將它們保存在符號(hào)表中,這使得它成為一個(gè)編譯期間的值,沒(méi)有了存儲(chǔ)與讀內(nèi)存的操作,使得它的效率也很高。
例如:
#define M 3 //宏常量 const int N=5; //此時(shí)并未將 N 放入內(nèi)存中 ...... int i=N; //此時(shí)為 N 分配內(nèi)存,以后不再分配! int I=M; //預(yù)編譯期間進(jìn)行宏替換,分配內(nèi)存 int j=N; //沒(méi)有內(nèi)存分配 // 注:取第一次分配時(shí)的地址給 j int J=M; //再進(jìn)行宏替換,又一次分配內(nèi)存!
const 定義的只讀變量從匯編的角度來(lái)看, 只是給出了對(duì)應(yīng)的內(nèi)存地址, 而不是象#define一樣給出的是立即數(shù),所以, const 定義的只讀變量在程序運(yùn)行過(guò)程中只有一份拷貝(因?yàn)樗侨值闹蛔x變量,存放在靜態(tài)區(qū)),而#define 定義的宏常量在內(nèi)存中有若干個(gè)拷貝。
#define 宏是在預(yù)編譯階段進(jìn)行替換,而 const 修飾的只讀變量是在編譯的時(shí)候確定其值。
#define 宏沒(méi)有類型,而 const 修飾的只讀變量具有特定的類型。
4. 使用cosnt修飾
4.1 修飾一般變量
一般常量是指簡(jiǎn)單類型的只讀變量。這種只讀變量在定義時(shí),修飾符 const 可以用在類型說(shuō)明符前,也可以用在類型說(shuō)明符后。例如:int const i=2;
或 const int i=2;
4.2 修飾數(shù)組
定義或說(shuō)明一個(gè)只讀數(shù)組可采用如下格式:
int const a[5]={1, 2, 3, 4, 5};
或const int a[5]={1, 2, 3, 4, 5};
4.3 修飾指針
const int *p; // p 可變, p 指向的對(duì)象不可變 int const *p; // p 可變, p 指向的對(duì)象不可變 int *const p; // p 不可變, p 指向的對(duì)象可變 const int *const p; //指針 p 和 p 指向的對(duì)象都不可變
先忽略類型名(編譯器解析的時(shí)候也是忽略類型名),我們看 const 離哪個(gè)近。 “近水樓臺(tái)先得月”,離誰(shuí)近就修飾誰(shuí)。
const int *p; //const 修飾*p,p 是指針, *p 是指針指向的對(duì)象,不可變 int const *p; //const 修飾*p,p 是指針, *p 是指針指向的對(duì)象,不可變 int *const p; //const 修飾 p, p 不可變, p 指向的對(duì)象可變 const int *const p; //前一個(gè) const 修飾*p,后一個(gè) const 修飾 p,指針 p 和 p 指向的對(duì)象 都不可變
4.4 修飾函數(shù)的參數(shù)
const 修飾符也可以修飾函數(shù)的參數(shù),當(dāng)不希望這個(gè)參數(shù)值被函數(shù)體內(nèi)意外改變時(shí)使用。例如:void Fun(const int i);
告訴編譯器 i 在函數(shù)體中的不能改變, 從而防止了使用者的一些無(wú)意的或錯(cuò)誤的修改。
注:void Fun(int i) 在 void Fun(const int i)在C++中是一個(gè)函數(shù),不會(huì)被認(rèn)為是重載。 可使用 typeid(i).name() 函數(shù)查看類型都為 int 類型
4.5 修飾函數(shù)的返回值
const 修飾符也可以修飾函數(shù)的返回值,返回值不可被改變。例如:const int Fun (void);
在另一連接文件中引用 const 只讀變量:
extern const int i; //正確的聲明
extern const int j=10; //錯(cuò)誤!只讀變量的值不能改變。
注意這里是聲明不是定義,注意聲明和定義的區(qū)別。
C與C++中cosnt的區(qū)別
首先,const的作用表示,使用const修飾的變量不能作左值。在初始化完成后不能被修改。
1. 在C語(yǔ)言中
1.const修飾的量,可以不用初始化(測(cè)試得)。
2.cosnt修飾的量,稱之為常變量,不可以用來(lái)初始化數(shù)組長(zhǎng)度。
3.cosnt修飾的量,無(wú)法直接修改,但可以通過(guò)指針或匯編指令等方式修改。
在 .c
文件中
const int b; // 無(wú)初始化, ok const int a = 10; //int arr[a] = {}; // 初始化數(shù)組長(zhǎng)度 ,error int* p = (int*)&a; *p = 30; // 30 30 30 printf("%d %d %d \n", a, *p, *(&a));
2. 在C++語(yǔ)言中
1.const修飾的量,必須初始化。
2.cosnt修飾的量,稱之為常量,預(yù)編譯階段全部替換,可以用來(lái)初始化數(shù)組長(zhǎng)度。
3.cosnt修飾的量,無(wú)法修改。
在 .cpp
文件中
//const int b; // error const int a = 10; int arr[a] = {}; int* p = (int*)&a; *p = 30; // 10 30 10 printf("%d %d %d \n", a, *p, *(&a)); // 注,這里的 a 和 *(&a) ,以及int arr[a]中的常量a在與編譯階段都被替換成10.
關(guān)于C++中通過(guò)指針修改常量這一點(diǎn),可參考博客:C++中如何修改const變量
特殊情況:常量退化為常變量
int b = 20; const int a = b;
3. cosnt修飾指針
3.1 常量指針
常量指針,即指向常量的指針。
const int *p;
int const *p; // const 與 int 不分先后,意義相同。
此類指針我們稱之為常量指針。顧名思義,指針指向的值是一個(gè)常量(語(yǔ)法上的,編譯器認(rèn)為該值不可通過(guò)指針修改)。
記憶方法:const修飾的 (*p),*p解引用后就是指針?biāo)?strong>指向的值。則const直接修飾該值,該值為常量。所以常量指針修飾的值為常量(不可做左值被修改)。
示例代碼:
{ int a = 10; const int* p = &a; int *q = p; // 此語(yǔ)句錯(cuò)誤的, int* <== const int* 的指向賦值,普通指針存在修改常量的風(fēng)險(xiǎn),編譯器報(bào)錯(cuò)。 }
3.2 指針常量
指針常量。即指針本身是一個(gè)常量。
int* const p;
指針是常量,即不可改變指針的指向。而指針指向的內(nèi)容任然是可修改的。
特點(diǎn):指針常量本身任然是一個(gè)指針,也就是說(shuō) int* const p 與 int p 的類型都是 "int "類型指針。因此,我們可以認(rèn)為指針常量是一個(gè)限定了指向的指針。
記憶方法:const 修飾了 (p),p是一個(gè)指針,也就是說(shuō)const限制的p不能改變指向。
示例代碼:
{ int a = 10; int* const p = &a; int *q = p; // 此語(yǔ)句正確,本質(zhì)上是指針的 int* <== int* 的指向賦值 }
3.3 指向常量的指針常量
不可改變指向,且不可修改內(nèi)容的指針。const int* const p = &a;
4. cosnt修飾二級(jí)指針
const修飾一級(jí)指針:
int a; const int* p1 = &a; int const* p2 = &a; int* const p2 = &a;
const修飾二級(jí)指針:
int a; int* p = &a; const int* p1 = &a; /* cosnt無(wú)修飾類型 */ int** pp0 = &p; int** const pp1 = &p; /* cosnt修飾一級(jí)指針 */ int* const* pp2 = &p; /* cosnt修飾二級(jí)指針 */ int const** pp3 = &p1; // int const** pp31 = &p; // 無(wú)法從“int * *”轉(zhuǎn)換為“const int** ” const int** pp4 = &p1; // const int** pp41 = &p; // .. /* cosnt修飾一級(jí)和二級(jí)指針 */ const int* const* pp5 = &p; int const* const* pp6 = &p;
5. cosnt指針練習(xí)
題目一:下列表達(dá)式語(yǔ)句賦值錯(cuò)誤的是?
int a = 10; const int* p = &a; int* q = p; int a = 10; int* const p = &a; int* q = p; int a = 10; int* const p = &a; int* const q = p; int a = 10; int* const p = &a; const int* q = p;
題目二:下列表達(dá)式語(yǔ)句錯(cuò)誤的有。
// 選項(xiàng)A int a = 10; int* p1 = &a; const int** q1 = &p1; // 選項(xiàng)B int a = 10; int* p2 = &a; int* const* q2 = &p2; // 選項(xiàng)C int a = 10; int* p3 = &a; int** const q3 = &p3; // 選項(xiàng)D int a = 10; int* const p4 = &a; int** q4 = &p4; // 選項(xiàng)E int a = 10; const int* p5 = &a; int* const* q5 = &p5;
題目解析請(qǐng)參看博客 練習(xí)題:C++指針練習(xí) 。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C語(yǔ)言版約瑟夫問(wèn)題算法實(shí)現(xiàn)
大家好,本篇文章主要講的是C語(yǔ)言版約瑟夫問(wèn)題算法實(shí)現(xiàn),感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你又幫助的話記得收藏一下,方便下次瀏覽2021-12-12C/C++中的sizeof運(yùn)算符和size_t類型的詳解
今天小編就為大家分享一篇關(guān)于C/C++中的sizeof運(yùn)算符和size_t類型的詳解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié)
這篇文章主要介紹了C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11c++調(diào)用python實(shí)現(xiàn)圖片ocr識(shí)別
所謂c++調(diào)用python,實(shí)際上就是在c++中把整個(gè)python當(dāng)作一個(gè)第三方庫(kù)引入,然后使用特定的接口來(lái)調(diào)用python的函數(shù)或者直接執(zhí)行python腳本,本文介紹的是調(diào)用python實(shí)現(xiàn)圖片ocr識(shí)別,感興趣的可以了解下2023-09-09C++ 中"priority_queue" 優(yōu)先級(jí)隊(duì)列實(shí)例詳解
這篇文章主要介紹了C++ 中"priority_queue" 優(yōu)先級(jí)隊(duì)列實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04C++設(shè)置系統(tǒng)時(shí)間及系統(tǒng)時(shí)間網(wǎng)絡(luò)更新的方法
這篇文章主要介紹了C++設(shè)置系統(tǒng)時(shí)間及系統(tǒng)時(shí)間網(wǎng)絡(luò)更新的方法,涉及網(wǎng)絡(luò)程序設(shè)計(jì)與系統(tǒng)函數(shù)的使用,需要的朋友可以參考下2014-10-10C++實(shí)現(xiàn)關(guān)系與關(guān)系矩陣的代碼詳解
這篇文章主要介紹了C++實(shí)現(xiàn)關(guān)系與關(guān)系矩陣,功能實(shí)現(xiàn)包括關(guān)系的矩陣表示,關(guān)系的性質(zhì)判斷及關(guān)系的合成,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04詳解MFC/C++調(diào)用易語(yǔ)言的整數(shù)型和文本型與VS2010互動(dòng)
在本篇文章里我們給大家分享了MFC/C++調(diào)用易語(yǔ)言的整數(shù)型和文本型與VS2010互動(dòng)相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以參考下。2018-11-11