1. 程式人生 > >C++中const的“就近原則”

C++中const的“就近原則”

在做題的時候,編譯時經常會遇到關於const的坑,如果在平時不是常用的話就會很容易忘記,在這裡整理一下const的“就近原則”的筆記。

指標

要理解就近原則首先要明白指標。
指標(pointer),可以看作指向(point to)。與引用類似,實現了對其他物件的間接訪問。
但有兩個不同之處:
1.指標本身就是一個物件,允許對指標賦值和拷貝,並且指標在週期內可以先後指向幾個不同的物件(除非是const指標)

const指標是指標變數的值一經初始化,就不可以改變指向,初始化是必要的。其定義形式如下:
int * const pTwo; //指向整形的常量指標 ,它不能在指向別的變數,但指向(變數)的值可以修改。(結合之後會說的就近原則

理解記憶。)

2.指標無需在定義時賦初值(若未初始化,它將有一個不確定得值)。

簡單示例

{
	int a = 0;
	int b = 1;

	int* const p1 = &a;			//p1是指向int型資料的const指標,指向不可改變。
	int* (const p11) = &a;		//p11與p1相同。
	const int *p2 = &a;			//p2是指向int型資料的指標,指向可以改變,
								//但不可以通過p2改變指向地址上的值。
	const int(*p22) = &a;		//p22與p2相同。
	const int*
const p3 = &a; //p3是指向in型資料的const指標,不能通過p3改變指向地址上的值。 p1 = &b; //報錯(指標指向不能被修改) *p1 = b; p2 = &b; *p2 = b; //報錯(指標指向的內容不能被修改) p22 = &b; *p22 = b; //報錯(指標指向的內容不能被修改) p3 = &b; //報錯(指標指向不能被修改且指標指向的內容不能被修改) *p3 = b; //報錯 }

讀const指標的方法,我們可以學習《C++Primer》上 P56的方法,也就是“從右往左讀”。

int errNumb =
0; int *const curErr = &errNumb; const double pi = 3.1415; const double *const pip = π

此例中,從右往左,離curErr最近的是const,意味著curErr本身是一個常量物件,繼續往左看,下一個符號*和int表明curErr是一個指向int型別的指標——結合起來curErr就是一個常量指標,指向不可變,但可通過其本身改變指向地址上的值。
指標pip同理,可以得知:pip是一個指向const double的const指標,指向和指向地址上的值不可變。

const* ———————————修飾指標
const int*——————const修飾指標指向的物件, int * const

就近原則

就近原則我們可以在K & R 《The C Programming Language》(2nd)

A.8.6.1 Pointer Declarators

In a declaration T D where D has the form

  • type-qualifier-listopt D1

and the type of the identifier in the declaration T D1 is
type-modifier T,'' the type of the identifier of D istype-modifier type-qualifier-list pointer to T.’’ Qualifiers
following * apply to pointer itself, rather than to the object to
which the pointer points.

const char **s;

對於以上的宣告,以*號界定,開始讀:
以最右邊第一個 * 號開始,形式為:
const char ** | s
最右面第一個s前沒有修飾符,可以改變指標指向;s是指向const char **的指標(const char *就是指標),因此s也就是指向指標的指標;
再看第二個* 號,形式為:
為const char * | *s
由於*s前沒有修飾符,因此(*s)其值是可以改變的;

最後看const char *,類似於前面的const int *p1,因此表示該指標(***s)指向的(此處為字串)為常量,其值不可改變;

測試:

	const char *fmt = "hello";
	const char **s = &fmt;
	*s++;				//正確,指向改變了
	(*s)++;				//正確,指向的地址上的值,可以改變值
	(**s)++;			//報錯,指向的地址上的值不可改變
	**s++;