進一步了解const指標

2022-09-22 21:18:29 字數 4216 閱讀 9156

問題

今天群裡有人發了個問題,問題如下:

第乙個賦值可以,為什麼第二個不行

[cpp]  

int * x = null;  

int const * y = null;  

y = x;  

int ** z = 0;  

int const ** n = 0;  

n = z  

當時我懵了一下,隨即想到可能是int const **的問題,便把**改成:

[cpp] 

int ** z = 0;  

int * const * n = 0;  

n = z;  

編譯通過,以為解決了問題,想也沒想,便發回給提問者。

殊不知,提問者問了好幾個問題後,我又懵了,-_-!

這個const是屬於那一邊的?

可以是[cpp]  

int (* const) * n = 0;  

那麼n就是乙個指向(int * const)的int指標

也可以是

[cpp]  

int * (const *) n = 0;  

那麼n就是乙個指向(int *)的const int 指標

後來提問者發了書裡面的一句話:

如果const和(或)volatile關鍵字後面緊跟型別說明符(如int, long等),它作用於型別說明符,在其他情況下,const和(或)volatile關鍵字作用於它左邊緊鄰的指標星號。

本人覺得這句話不夠確切,一般情況下,我們會把**寫成:

[cpp]  

const int * p;  

這和書中描述的一致,const 此時作用於int。但我們也有另外一種寫法

[cpp]  

int const * p;  

雖然大家都知道這個const 必定作用於int的,但按照那句話的方法,const找不到作用的地方了。

好吧,這有點鑽牛角了。既然是從書**來的,還是得用**來證明一下。 試驗

回歸到頂部問題,其實就是型別匹配問題,如果型別不匹配,那麼編譯就會報錯,所以通過編譯器(vs2010)來作為我們的裁判,const到底是作用於誰。

先鋪好兩個必須的變數:

[cpp]  

int * p_to_v_1 = new int(1);;  

int * p_to_v_2 = new int(2);  

第一試驗

[cpp] 

int * * pptest1 = &p_to_v_1;  

pptest1 = &p_to_v_2;  

*pptest1 = p_to_v_2;  

**pptest1 = 10;  

這個應該理解上沒有多大的問題,所以不解釋。

編譯通過,沒報任何錯誤,結論:

*pptest1也是int * 型別。

**pptest1是int型別。

第二試驗

[cpp] 

int const * * pptest2 = &p_to_v_1;  

pptest2 = &p_to_v_2;  

*pptest2 = p_to_v_2;  

**pptest2 = 10;  

這個比較簡單,pptest2指向的是int const *的指標,所以第三個**pptest2的賦值編譯器報錯:表示式必須是可修改的左值。

*pptest2也是int const * (或const int *)型別。

**pptest2是const int 型別,不可改變,所以賦值時出錯。

第三試驗

[cpp] 

int * const * pptest3 = &p_to_v_1;  

pptest3 = &p_to_v_2;  

*pptest3 = p_to_v_2;  

**pptest3 = 10;  

const 來到兩個星號中間,那麼就是上面我遇到的問題了。

編譯器此時報錯是 *pptest3 = p_to_v2; 這行**,錯誤是:表示式必須是可修改的左值。

p_to_v2是指標變數,那麼*pptest3就是指標常量

*pptest3是int * const型別。(印證了書中那句話)

**pptest3那一行沒報錯,那麼**pptest3就是int型別

第四試驗

[cpp]  

int * * const pptest4 = &p_to_v_1;  

pptest4 = &p_to_v_2;  

*pptest4 = p_to_v_2;  

**pptest4 = 10;  

報錯的是「pptest4 = p_to_v2;」這行,錯誤資訊和上面例子一樣,那麼pptest4就是乙個指向指標的指標常量,pptest4是不可更改的。

第五試驗

[cpp]  

int const * const * pptest5 = &p_to_v_1;  

pptest5 = &p_to_v_2;  

*pptest5 = p_to_v_2;  

**pptest5 = 10;  

有了前面的基礎,應該很容易判斷這裡報錯的是哪個。

沒錯,第3行和第4行錯誤,*pptest5是指標常量,**pptest5是常量。

第六試驗

[cpp]  

int * const const * pptest6 = &p_to_v_1;  

pptest6 = &p_to_v_2;  

*pptest6 = p_to_v_2;  

**pptest6 = 10;  

這個定義看起來有點奇怪,雖然會有編譯警告,但是可以通過的。

報錯的只有第3行(*pptest6 = p_to_v_2;),因為*pptest6是指標常量。

為什麼第2行不報錯呢?pptest6是指向指標常量的指標,&p_to_v_2的結果又是指向指標變數的指標。

因為這個賦值的道理就如const int * 型別可以被int *型別賦值一樣(如函式void f(const int * cp)中的引數,f被呼叫時,傳入的引數可以是const int*,也可以為int *),乙個是指向int常量的指標,乙個是指向int變數的指標。

這裡的定義(int (* const) (const *) pptest6 )還有個地方需要注意一下,剛才說了,pptest6是指向指標常量的指標;而剛好,*pptest6又是指標常量,那這個定義就相當於

[cpp]  

int * const * pptest6   

第七試驗

[cpp]  

int * const * const pptest7 = &p_to_v_1;  

pptest7 = &p_to_v_2;  

*pptest7 = p_to_v_2;  

**pptest7 = 10;  

2和3行報錯,pptest7是常量,*pptest7也是。

第八試驗

[cpp]  

int const * const * const pptest8 = &p_to_v_1;  

pptest8 = &p_to_v_2;  

*pptest8 = p_to_v_2;  

**pptest8 = 10;  

這個2、3、4都報錯,應該不用怎麼解釋了吧。。。

總結一下,剛才那句話大部分還是對的,就差了我剛才提到的那一點,嘿嘿。

如果const和(或)volatile關鍵字後面緊跟型別說明符(如int, long等),它作用於型別說明符,在其他情況下,const和(或)volatile關鍵字作用於它左邊緊鄰的指標星號。

解決問題

剛才說明了const在不同位置所起的不同作用,現在回過頭來看原先的問題:

[cpp]  

int * x = null;  

int const * y = null;  

y = x;  

int ** z = 0;  

int const ** n = 0;  

n = z  

現在來看這些指標,應該比較明確:

z就是指向int *的指標;

而n就是指向const int *的指標;

n和z最終指向型別(乙個是int, 乙個是const int)是不一樣的,所以賦不了值。

就如以下**

[cpp]  

int * x = null;  

int * const y = null;  

y = x;  

進一步了解Makefile

mkdir p add src 一層一層建立目錄。touch add makefile 建立 makefile include 目錄中存放標頭檔案。scripts 存放指令碼檔案。存放方式 按照核心管理原始碼來管理。為什麼學習makefile?編譯大型專案 讀懂別人的開源 找到程式入口 看專案的順序...

進一步了解Spring Cloud

spring cloud是 系列框架的有序集合。它利 spring boot的開發便利性巧妙地簡化了分布式系統基礎設施的開發,如服務發現註冊 配置中 訊息匯流排 負載均衡 斷路器 資料監控等,都可以 spring boot的開發 格做到 鍵啟動和部署。spring cloud並沒有重複製造輪 它只是...

進一步了解pip

在python中,安裝第三方模組,是通過包管理工具pip完成的。當我們試圖載入乙個模組時,python會在指定的路徑下搜尋對應的.py檔案,如果找不到,就會報錯。預設情況下,python直譯器會搜尋當前目錄 所有已安裝的內建模組和第三方模組,搜尋路徑存放在sys模組的path變數中 import s...