@
開始回顧C基礎知識。C中使用指針是很危險的事情,一個不慎就會造成程序崩潰,因此對於傳入函數的參數進行保護就是必須的了,特別是針對數組。
const關鍵字
const
關鍵字用於將一個變量聲明為只讀,也就是常量,無法被修改。
const int constant = 10;//聲明constant為常量的同時對它進行初始化賦值
int const constant = 10;//也可以將const放在int后面
const修飾數組
使用const來修飾數組聲明了一個數組常量,是對數組里面數據的一種保護,當試圖修改一個被const修飾的數組內容時,編譯時會產生錯誤。
const int days[5] = {1,2,3,4,5};//int const days[5]一樣
//想要把days[0]重新賦值為6,報錯
days[0] = 6;
//Cannot assign to variable 'days' with const-qualified type 'const int [5]'
但是我們有一點要注意,是不是days
里面的數據一定無法修改呢?我們做個試驗:
const int days[5] = {1,2,3,4,5};
int * p = days;
*p = 6;
for (int i = 0; i < 5; ++i) {
printf("%d\n",*p++);
}
結果:
6
2
3
4
5
所以雖然數組days被聲明為只讀的,但是如果通過指針去訪問數組,還是可以改變數組元素的,這也就是指針的強大與易錯。
const修飾指針
const修飾指針創建了一個指針常量,但是const的位置會導致這個指針常量有不同的含義。
int days[5] = {1,2,3,4,5};
const int *p1;//const修飾的是int,表示p1指向的變量值不可改變,指針本身可以改變
//p1指向的值為常量
p1 = days;
*p1 = 6;//報錯,不允許修改指針指向的值。Read-only variable is not assignable
p1[1] = 7;//報錯,不允許修改
days[0] = 6;//允許,days不是常量
p1++;//合法,p1這個指針本身是可以修改的,這里讓其指向days的第二個元素
int * const p2 = days;//const修飾的是p2,表示p2這個指針本身是無法修改的,但是其指向的值是可以修改的
//這里p2本身是常量,因此聲明p2的時候就要初始化,否則后面無法對p2進行初始化
*p2 = 10;//合法,p2指向的值可以修改
p2 = &days[1];//不合法,報錯,p2是常量,因此想要修改指針的值使其指向days[1]不合法。
//Cannot assign to variable 'p2' with const-qualified type 'int *const'
上面就說明了兩種const修飾的指針常量的區別。這里有以下幾點需要注意:
- 將常量或非常量數據的地址賦值給指向常量的的指針是合法的。但是非常量數據的地址可以賦值給普通指針,而常量數據的地址就不可以賦值給普通指針。這樣做只會提示不合法,卻仍然可以這樣操作,但最好不要這樣做,數據既然數據已經被聲明為常量,那么就不要試圖去修改,因此指針不要這樣賦值,以免修改了倡廉打個值,就像上面const修飾數組里面說的。
double un_locked[3] = {1.2,2.3,3.1};
const double locked[3] = {1.0,2.0,3.0};
const double * p3 = locked;//合法
p3 = un_locked;//合法
p3 = &un_locked[1];//合法
double *p4;
p4 = un_locked;//合法
p4 = locked;//非法,但是程序可以運行,
- const用來修飾形式參量。C語言的傳參特性這里不提,如果函數並不想修改本來的數據,一般會把相應的形式參量修飾為const的,告訴編譯器這里要把傳進來的指針地址當做常量來對待,不允許修改,當函數體內部想要做修改時,編譯器會報錯。需要注意的是並不要求傳進來的參數是常量,而是編譯器這樣做保證函數執行過程中對源數據不會修改而已。
void foo(const int *bar);
//foo接受一個指針,並把這個指針當做常量對待
void foo1(int *bar);
//foo1聲明接受一個普通指針
int main() {
int test1[2] = {1,2};
const int test2[2] = {3,4};
foo(test1);//合法
foo(test2);//合法
foo1(test1);//合法
foo1(test2);//不合法,不提倡這樣做。Passing 'const int [2]' to parameter of type 'int *' discards qualifiers
}
void foo(const int *bar){
}
void foo1(int *bar){
}
用兩個const修飾指針
用兩個const
修飾符修飾指針會使得這個指針本身既不可以更改所指向的地址,也無法修改所指向的數據。
int days[3] = {1,2,3};
const int * const p = days;
p = &days[2];//不合法
*p = 6;//不合法
const
修飾函數本身我還沒用過,碰到了再來補上。