外管局網(wǎng)站上做預(yù)收登記廊坊seo
今天我們來探討C/C++中const、指針和引用的相關(guān)問題。這些概念是編程中的重要組成部分,它們的正確使用對于代碼的可讀性和可維護性至關(guān)重要。通過深入了解const的不可變性、指針的靈活性以及引用的簡潔性,我們能夠更好地掌握編程的精髓,并寫出更加健壯和高效的代碼😊😊😊
淺談C/C++
- (1)const + 一級指針
- (2)const + 二級(多級)指針
- (3)引用操作符 &
先來看看對const的描述,C/C++中的const關(guān)鍵字用于聲明一個常變量,即一個“不可修改的值”,通過使用關(guān)鍵字const,我們可以明確地指定一個變量、函數(shù)參數(shù)、函數(shù)返回值或類成員函數(shù)為只讀,從而禁止對其進(jìn)行修改,增強程序的健壯性??梢娢覀儗τ?const 的描述,常見為一個不可修改!!!,但在C和C++中,編譯器對于 const 的反應(yīng)也是 有差異的
1、我們先來看看.c文件 -》 C語言中的const,猜猜有何問題?
#include<stdio.h> int main() {const int a;int array[a] = { 0 };const int b = 0;b = 5;int* p = (int*)&a; *p = 30;printf("%d %d %d\n", a, *p, *(&a)); }
我們不難想到
array[a]
會報錯,因為a沒有被初始化,定義數(shù)組需要有一個常量值作為數(shù)組的長度,而a不可推測;b = 5
,變量b為常變量,不可被修改- 然而,對于涉及到變量
p
的語句,朋友是否有些疑惑🤔🤔🤔,p
是指向變量a
地址的普通指針,而*p = 30
就是將它指向的地址上對應(yīng)的值改為30,即分配給變量a
的地址空間中的值 被改了🤣🤣🤣,我們?nèi)サ翦e誤語句,加上a = 20
后,看看執(zhí)行的結(jié)果
由此可見,我們可以歸納出 C語言編譯器 下有關(guān)
const
的特性在C語言編譯器中 a) const修飾可以不進(jìn)行初始化,被看作常變量 b) 被const修飾的變量只是不能作為左值被修改,通過指針或引用的方式能夠修改
2、我們再來看看.cpp文件 -》C++語言中的const,猜猜有何問題?
int main() {const int b;int c = 5;const int a = c;//const int a = 20;int array[a] = { 0 };int before = a;int* p = (int*)&a; *p = 30; int after = *(int*) & a;cout << before << endl << after << endl; cout << a << " " << *p << " " << *(&a) << endl;return 0; }
不難想到
const int b;
會報錯,因為在C++中const修飾的變量被看作常量,不能夠不對它進(jìn)行初始化- 在
array[a]
報錯,變量a
為變量c
賦值而來,而c
是一個變量,賦給變量a
后,變量a
也作為變量,而array[]里需要一個常量,所以出現(xiàn)錯誤,如下圖
除去錯誤語句,把const int a = 20
后的執(zhí)行結(jié)果由此我們可以了解到
在C++語言編譯器中 a) const修飾的變量必須初始化,不能作為左值 b) 被const修飾的變量只是不能作為左值被修改,通過指針或引用的方式能夠修改 c) 被const修飾的變量被叫做常量,若直接賦值一個變量,不能直接作為數(shù)組的長度 c) 在C++編譯器中,執(zhí)行程序遇到const變量的時候,會直接被看作是常量,直接用初值替換,即*(&a) -> 20
本來我們使用const修飾變量的目的就是保證變量不被修改,然上面我們能夠看到,如果我們把一個常量的地址泄露給了一個普通指針或者引用,那么就會有被修改的風(fēng)險,因此我們需要對此問題做相應(yīng)的處理,也就是下面我們將要介紹的 const + 指針
的結(jié)合
📢📢📢注意:在C++語言規(guī)范中,const修飾的類型是離它最近的類型
(1)const + 一級指針
我們先來看看一級指針 + const
的情況,如下:
//根據(jù)上面的注意項,有
const int *p; -> const修飾int,即值*p不可修改,指針可以任意指向p = &a
int const *p; -> const修飾int,同上
int* const p; -> const修飾int*,即指針指向p不可修改,值*p可以任意
int* const *p; -> const同時修飾int*和int,都不能修改
看到這,我們就能夠自己解決:當(dāng)泄露了常量的指針或引用時,常量可能被修改的問題。但是對于const
和指針
的各種組合類型中,也并非都能夠相互進(jìn)行強制轉(zhuǎn)化的。
📢📢📢這里又需要注意一點:const右邊如果沒有指針*的話,const是不會參與進(jìn)推測的類型
int* q1 = nullptr;
int* const q2 = nullptr;
const int* q3 = nullptr;
int const* q4 = nullptr;
int* const* q5 = nullptr;
cout << typeid(q1).name() << endl; // -> int*
cout << typeid(q2).name() << endl; // -> int*
cout << typeid(q3).name() << endl; // -> const int* / int const*
cout << typeid(q4).name() << endl; // -> const int* / int const*
cout << typeid(q5).name() << endl; // -> int* const*
//以上代碼,朋友可以自己去驗證一下是否正確
這里我們再給出一段代碼,來看看是否正確🤔🤔🤔
#include<iostream> using namespace std;int main() {int a = 5;const int* pp = &a;//const int* pp = nullptr;int* qq = p;//cout << typeid(pp).name() << endl;char s = 'a';const char* ss = &s;char* sss = ss;return 0; }
整形常量指針
p
指向的是普通變量a
的地址,整形變量指針p
,也是普通變量a
的地址,既然是普通變量,那么普通變量a
的值應(yīng)該是能被修改是吧🤫🤫,然當(dāng)我們放在visual studio 2022上時,發(fā)現(xiàn)它報錯了!!!,其實這更變量a
無關(guān),若我們將pp
指向nullptr
,仍然是一樣的結(jié)果。因為在類型上,編譯器是禁止將const int*
類型的數(shù)據(jù)轉(zhuǎn)換成int*
類型的,使用char
等其他類型也是如此
(2)const + 二級(多級)指針
我們再來看看const + 二級(多級)指針
的情況,如下:
const int**q; -> **q 不能被賦值
int* const *q; -> *q 不能被賦值
int** const q; -> q不能被賦值
📢📢📢注意:對于const + 多級指針
的結(jié)合,涉及到類型轉(zhuǎn)化時
錯誤:const int* -> int* ;int** -> const int** ;int* const* -> int** //const修飾一級指針《=》 const* -> *《=》 const int* -> int* 是錯誤的!const int** -> int** ;正確:int* -> const int* ;int** -> int* const* 《=》 * -> const*《=》 int* -> const int* 是正確的!
這里我們給出一段代碼,來看看是否正確🤔🤔🤔
#include<iostream> using namespace std; int main() {int a = 10;int* p = &a;const int **q = &p; // const int** <- int**return 0; }
這里我們可以把換換const int* *q
,即*q
是整形常量的指針 《=》p
,所以當(dāng)我們把一個整形常量的地址賦值給*q
時,const int b = 20; *q = &b
,相當(dāng)于直接就修改了p
,使其指向了常量的地址,把變量b
的指針間接地泄露給了普通指針*p
,系統(tǒng)報錯!!!
—>
解決方法:const int* const*q = &p;
- 我們讓其不能夠給
*q
賦值,即禁用*q = &b
(3)引用操作符 &
引用是C++種的一種特殊數(shù)據(jù)類型,它提供了對現(xiàn)有別名的訪問,通過引用可以使用相同的變量名來訪問同一個內(nèi)存地址的內(nèi)容,一旦被初始化后,它將一致引用同一個對象,并且不能再引用其他對象,因此引用也被叫做更安全的指針!對比一下指針和引用的區(qū)別:
- 引用是必須初始化的,指針可以不被初始化
- 引用只有一級,而指針有多級
- 在匯編層面上,定義或修改引用變量和指針變量是一樣的
從以下代碼即圖例可以看出:
#include<iostream> using namespace std; void swap(int& a, int& b) { int t = a; a = b; b = t; } //引用底層還是轉(zhuǎn)化為指針>實現(xiàn) void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; }int main() {int a = 10, b = 20;swap(&a, &b);swap(a, b);int *p = &a;int &q = a;int array[5] = {};int (&vv)[5] = array;return 0;
引用又可分為兩種:左值引用 和 右值引用
- 左值引用: 對象的一個命名引用,它綁定到左值(如一個具名變量),即有名字、有內(nèi)存,通過左值引用,可以修改被引用對象的值。
- 右值引用: 對臨時對象或?qū)⒁N毀的對象的引用,它綁定到右值(如一個臨時對象,一個匿名對象,或一個將要銷毀的對象),通過右值引用,可以實現(xiàn)資源的高效轉(zhuǎn)移和移動語義
#include<iostream>
using namespace std;
{int a = 10;//int &&b = a; //錯誤右值引用變量無法綁定到左值int &&c = 20; //c++11提供了右值引用,匯編指令上產(chǎn)生臨時量const int &d = a; //左值引用可以指向左值int &e = a;int &f = c; //右值引用本身是一個左值return 0;
📢📢📢注意:左值引用變量能夠擁有右值和左值,但右值引用變量只能引用右值
上面就是關(guān)于const 、 指針 、 引用
的問題,學(xué)而不思則罔,思而不學(xué)則殆,下面給出幾道題目,來檢驗一下我們的學(xué)習(xí)成果
A) int a = 10const int *p = &aint *q = p xxx
B) int a = 10int* const p = &aint *q = p gggC) int a = 10int* const p = &aconst int *q = p gggD) int a = 10int *p = &aconst int **q = &p xxxE) int a = 10int *p = &aint* const* q = &p gggF) int a = 10int *p = &aint ** const q = &p gggG) int a = 10int* const p = &aint **q = &p int** <- int* const*xxxH) int a = 10const int*p = &aint* const* q = &p int* const* <- const int**《=》 int* <- const int*xxx引用是不參與推測類型的I) int a = 10int *p = &aint *&q = p 《=》 int **q = &pgggJ) int a = 10int* const p = &aint *&q = p 《=》 int **q = &pxxxK) int a = 10int *p = &aconst int* &q = p; 《=》 const int**q = &pggg
🌻🌻🌻以上就是淺談C/C++的常量const、指針和引用的有關(guān)問題,如果聰明的你瀏覽到這篇文章并覺得文章內(nèi)容對你有幫助,請不吝動動手指,給博主一個小小的贊和收藏 🌻🌻🌻