結合示例說明C 中const和指標結合時怎麼理解

2022-05-04 04:18:09 字數 3721 閱讀 6675

在之前隨筆《c++中const使用要點(一)》中簡單敘述了const int*、int* const和const int* const的區別,記住三句話就能在實際運用時用對,但是看書時發現了指標常量、常量指標這些名詞,發現明白這些概念對閱讀文章時還是比較重要的。

關鍵:const和指標結合時**從右往左看

1、常量指標(const pointer)

概念:常量是形容詞,也就是說常量指標是乙個指標,用const修飾的指標。

按照**從右往左(概念名詞從左往右)的閱讀順序,不妨試著寫一下。

step1: i; // 變數名

step2: const i;  // 第乙個名詞是const,寫在i的左邊

step3: int* const i;  // 第二個名詞是pointer(*),以具體型別int*為例,寫在const i的左邊

2、指向常量的指標(pointer to const),一般簡稱為指標常量(這種翻譯很不好,容易混淆)

概念:指向常量是形容詞,指向常量的指標也是乙個指標,但是本身不是const,指向的物件是const

繼續來試著寫一下。

step1: i; // 變數名

step2: * i; // 第乙個名詞是pointer,*寫在i的左邊

step3: const int* i; // 第二個名詞是const,以const int為例,寫在*的左邊。

int const* i;  // 這種寫法也對,可以理解為先在* i左邊寫個const,表示指向的是常量,再在const* i左邊寫上這個常量的具體型別

3、指向常量的常量指標

同樣的寫法,先在變數名的左邊寫上const,再在const左邊寫上*,之後左邊是const int或int const都行

int i = 0, j = 1;

// 常量指標, p1是const, p1指向的是int(而不是const int)

int* const p1 = &i; // 必須初始化, 因為指向的物件不能更改

// p1 = &j; // 這句想把j的位址賦值給p1, 而p1又是const

*p1 = 2; // 指向的是int, 沒有const修飾, 可以更改

// 指向常量的指標, p2不是const, p2指向的是const int

const int* p2; // 可以不初始化(懸掛指標), 反正以後可以選擇指向的物件

p2 = &j; p2 = &i; // 隨意修改指向的物件

//*p2 = 1; // 指向的是const int, 不可以更改

// 指向常量的常量指標, p3是const, p3指向的也是const

const int* const p3 = &i;

// p3 = &j; // 錯誤, 因為p3是const

// *p3 = 3; // 錯誤, 因為p3指向的也是const

為了**的易讀性,使用typedef把指標簡化比較常見

以前最顯著的用法就是把函式指標(指向函式的指標)給簡化。

函式指標的**閱讀方法是從裡到外

int (*func)(int, int);

step1: 最裡面的是變數名func,它是乙個函式指標

step2: 往左讀,func返回的是int;往右讀,func引數是2個int

複雜一點的話……

float (*(*func)(int,int))(int);

step1: 最裡面的是變數名func,它是乙個函式指標,接受1個int引數,返回的還是個函式指標

step2: 設返回的函式指標為func1,即typedef float(*func1)(int);

step3: 這下就好讀了,func1接受1個int引數,返回float。

好吧,回歸正題。用typedef要注意的一點就是不能跟c語言常用的#define等價,雖然在c++中確實是用來代替#define的。

因為typedef不是直接替換**,而是把這段**當成乙個型別。

直接上**說明吧

typedef int* pint;

int i = 0, j = 1;

// 這裡把pint就當成個暫時未知基本資料型別, 說明p1是const

// 再來看看pint的具體型別, 是個指向int的指標

// 也就是說p1是指標, p1是const, 指向的是int(不是const int)

const pint p1 = &i; // 等價於pint const或int* const

// p1 = &j; // 錯誤

*p1 = 2;

int *p2 = &i, *p3 = &j;

int **pp1 = &p2, **pp2 = &p3;

// pp2是個指標, 指向的是const pint

const pint* pp3;

pp3 = pp1;

pp3 = pp2; // 可以隨便改變指向的物件

// *pp3 = p2; // 錯誤, pp3指向的是const型別(const pint), 不能修改

*(*pp3) = 4; // 正確, [pp3指向的const pint]指向的是pint(這個pint指向的是int, 可以修改)

另外,在c++ primer上還看到了頂層(top-level)const底層(low-level)const的概念

底層const:指向的物件不能修改(比如const int*)

頂層const:指標或變數本身不能修改(比如const int、int* const)

const int* const兼具底層和頂層性質

關鍵1:只有有底層const性質的指標才能轉換為相同底層const資格的指標!

比如const int* const兼具底層和頂層const性質。

int i = 1;

const int* p1 = &i;

const int* const p2 = &i;

p1 = p2;

// p2 = p1; // 錯誤, 因為p2本身不能修改

其實不知道頂層底層也能理解,就像const t能轉換為t一樣。(t為資料型別)

t&不能轉換為const t&,t&也不能繫結const t(常見錯誤,在《c++中const使用要點(二)》中提過類似)的

t*不能你轉換為const t*。但是指標的情況比較特殊,比如可以像下列**一樣強制轉換

const int* pint1 = &i;

int* pint2 = &i;

// 可以強制轉換

pint2 = (int*)pint1;

pint2 = const_cast(pint1);

關鍵2:auto型別只能推測出底層const性質!

auto a = &ci;  // a是const int*, 底層const保留

auto b = ci; // b是int, 頂層const被忽略

針對這個問題,c++ 11新增了decltype型別,可以保留頂層const。

比如上述**第二行改為decltype(b) = ci;後b就是const int型別

C 中頂層const和底層const

指標本身是乙個物件,由於,指標實際相應著記憶體單元的一段儲存空間,然而,指標所指向的也是乙個資料物件,因此,指標是乙個常量與指標所指向的是乙個常量是兩個全然不同的概念,頂層 const 表示的是 指標本身是乙個常量,底層 const 表示的是 指標所指的物件是乙個常量,更普通情況下,頂層 const...

C 中頂層const和底層const

頂層const表示指標本身是個常量,底層const表示指標所指的物件是乙個常量。int i 0 int const p1 i 不能改變p的值,p是乙個指標,所以p是乙個頂層const const int p2 i 表示不能改變指標所指i的值,所以是乙個底層const const的頂層和底層不只是限定...

c 中const和引用

c 和c語言裡面的const 1 在c語言裡面的const修飾的量是乙個常變數,不能作為左值,但是可以通過洩露指標和引用去修改它,int a 10 int p a 洩露了常量的引用。但是 int a 10 const int p a 是正確的。因為a本來就是普通的變數,而通過常量 p不能改變它,但a...