情景分析“C語言的const關(guan)鍵(jian)字”
C語言(yan)中(zhong)的(de)const一(yi)直是C語言(yan)初學(xue)者心中(zhong)的(de)痛,這是因(yin)為const在(zai)不同位置(zhi)有不同作用,在(zai)不同情景有不同角色。這讓(rang)(rang)初學(xue)者摸不清頭腦(nao)。今(jin)天(tian),和(he)大家一(yi)起研究一(yi)下const,讓(rang)(rang)它(ta)的(de)每(mei)個角色都“深入人心”!
==============================================================================================
情景一:最簡單的const用法
#include<stdio.h> int main() { int const a; a=5; printf("a=%d\n",a); return 0; }
如(ru)果編譯這個c文件,就(jiu)會報錯:
1071.c: In function ‘main’:
1071.c:5: error: assignment of read-only variable ‘a’
顯(xian)而易見,這是(shi)const在搞鬼,因為聲明了const的變量是(shi)不能修(xiu)改的!
如果將(jiang)源代碼修改(gai)為如下這樣,就沒(mei)有(you)問題了!
#include<stdio.h> int main() { int const a=5; printf("a=%d\n",a); return 0; }
總結(jie):const聲明的變量(liang)(liang)必須要進行初始(shi)化(hua)賦(fu)值,如果錯過這(zhe)個機會(hui),以(yi)后再想給const的變量(liang)(liang)賦(fu)值,可就沒門了!切(qie)記(ji)~
PS:int const和(he)const int是(shi)一(yi)回事,“顛倒寫”都是(shi)可以的(de)。以后遇到了別(bie)犯暈,呵呵。但是(shi),還是(shi)要留個心眼,當const和(he)指(zhi)針攙(chan)和(he)到一(yi)起(qi)時,這個“顛倒寫”的(de)規(gui)律可未(wei)必成立。
==============================================================================================
情景二:發明const為了什么?
在const誕生(sheng)(sheng)之(zhi)前,開發者一直(zhi)使用#define VAR 100來定(ding)義一些有特(te)殊用途(tu)的類常(chang)量,不過這(zhe)樣定(ding)義是存在一些劣(lie)勢(shi)的。因此const應運而生(sheng)(sheng),之(zhi)后(hou)開發者可以使用const int VAR=100;來定(ding)義類常(chang)量了。
至于(yu)為什么#define有其劣勢,還(huan)要(yao)讀者(zhe)自己去google下。:)
==============================================================================================
情景三:const和指針的配合是噩夢!
你能分辨得清(qing)這些聲明么:
const int *A; int const *A; int *const A; const int *const A;
如果有點犯(fan)暈的話,那就先(xian)給出它們(men)的講解(jie),然后(hou)(hou)繼續看(kan)后(hou)(hou)面的情景分析吧。
const int *A; //修飾指向的對象,A可變,A指向的對象不可變
int const *A; //修飾指向的對象,A可變,A指向的對象不可變
int *const A; //修飾指針A, A不可變,A指向的對象可變
const int *const A; //指(zhi)針A和A指(zhi)向的對象都不可變
==============================================================================================
情景四:const int *A
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; const int *A=# printf("result=%d\n",*A); return 0; }
編譯執行結果為:
[rocrocket@wupengchong const_test]$ cc test1.c
[rocrocket@wupengchong const_test]$ ./a.out
result=12
接(jie)下來,我們(men)動(dong)(dong)動(dong)(dong)手腳,在(zai)代(dai)碼中加(jia)入(ru)了(le)(*A)++;這(zhe)條語句:
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; const int *A=# (*A)++; printf("result=%d\n",*A); return 0; }
編譯這個c文件:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
test1.c: In function ‘main’:
test1.c:6: error: increment of read-only location ‘*A’
可以(yi)看到,報(bao)(bao)錯(cuo)了,報(bao)(bao)錯(cuo)的內(nei)容表示”*A”是(shi)只讀(du)的,不能修(xiu)改。
我們再修改一下源(yuan)代碼為下面這樣:
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int tmp=100; const int *A=# A=&tmp; printf("result=%d\n",*A); return 0; }
編譯執行結果為:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
[rocrocket@wupengchong const_test]$ ./a.out
result=100
好了(le),如(ru)果你仔細看了(le)這幾個小(xiao)得不能再(zai)小(xiao)的程(cheng)序,你自己都(dou)可(ke)以(yi)給(gei)出結論了(le)!
結論:如(ru)果聲明了(le)const int *A,那么A值(zhi)是(shi)可以修(xiu)改的,而*A是(shi)不可以修(xiu)改的。更通俗的說(shuo),A指(zhi)(zhi)針(zhen)可以隨(sui)便指(zhi)(zhi)向一個整型,但只(zhi)要(yao)被A盯(ding)上了(le)的整型變量在使用*A引(yin)用時就不能修(xiu)改了(le)。
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int tmp=100; const int *A=# A=&tmp; tmp=3; printf("result=%d\n",*A); return 0; }
編譯執行的結果為:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
[rocrocket@wupengchong const_test]$ ./a.out
result=3
結論2:即使A指(zhi)向了(le)tmp,我雖然不(bu)能修改*A,但(dan)是我仍然是可以用tmp來修改這(zhe)個值的,完全不(bu)管*A的存在。呵(he)呵(he)
==============================================================================================
情景五:int *const A
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int *const A=# printf("result=%d\n",*A); return 0; }
編譯執行結果為:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
[rocrocket@wupengchong const_test]$ ./a.out
result=12
我們稍微修改下源代碼:
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int tmp=100; int *const A=# A=&tmp; printf("result=%d\n",*A); return 0; }
編譯時報錯了:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
test1.c: In function ‘main’:
test1.c:7: error: assignment of read-only variable ‘A’
[rocrocket@wupengchong const_test]$ cat test1.c
可(ke)見A本身(shen)的值已(yi)經(jing)不能(neng)再(zai)變了。
繼續修改(gai)源代碼如下:
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int *const A=# (*A)=100; printf("result=%d\n",*A); return 0; }
編譯執行結果為:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
[rocrocket@wupengchong const_test]$ ./a.out
result=100
可以(yi)看(kan)出,(*A)是可以(yi)改(gai)變(bian)的(de)。
結(jie)論又可以(yi)輕易(yi)推出了:int *const A; //const修飾(shi)指針(zhen)A, A不(bu)可變,A指向的對(dui)象可變
==============================================================================================
情景六:const int *const A; //指針A和A指向的對象都不可變
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int const *const A=# (*A)=100; printf("result=%d\n",*A); return 0; }
編譯會報錯:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
test1.c: In function ‘main’:
test1.c:6: error: assignment of read-only location ‘*A’
改下源代碼:
[rocrocket@wupengchong const_test]$ cat test1.c
#include<stdio.h> int main() { int num=12; int tmp=100; int const *const A=# A=&tmp; printf("result=%d\n",*A); return 0; }
編譯仍然會報錯:
[rocrocket@wupengchong const_test]$ !cc
cc test1.c
test1.c: In function ‘main’:
test1.c:7: error: assignment of read-only variable ‘A’
呵呵,結論很明顯了,const int *const A; //指針A和A指向的對象都不(bu)可變
當(dang)然const int *const A;和int const *const A=#是等(deng)價的!
情景七(qi):如果const用在函數形參(can)里呢?是不是又(you)要復雜很(hen)多?
答案是NO!一點(dian)也不復雜。
來看(kan)看(kan)這個(ge)函數投(tou):int addnum(const int num, int a, int b);
這個(ge)函(han)數聲明中(zhong)的第(di)一個(ge)形參是(shi)const int num,這就(jiu)表(biao)明如(ru)果我(wo)調用(yong)了這個(ge)函(han)數,那么第(di)一個(ge)實(shi)參被(bei)傳到addnum函(han)數里之(zhi)后,就(jiu)不能再做修(xiu)改了!呵(he)呵(he) 就(jiu)這么簡單。
給個例(li)子吧,讓大家(jia)能更一目了然:
[rocrocket@wupengchong const_test]$ cat test2.c
#include<stdio.h> int addto(const int num, int a, int b) { if(num==1){ return a+b; }else{ return 0; } } int main(){ int num=100; int a=12,b=22; int res; num=1; res=addto(num,a,b); printf("res=%d\n",res); return 0; }
編譯執行結果為:
[rocrocket@wupengchong const_test]$ !cc
cc test2.c
[rocrocket@wupengchong const_test]$ ./a.out
res=34
如果(guo)我修改一下,編譯就會出錯:
[rocrocket@wupengchong const_test]$ cat test2.c
#include<stdio.h> int addto(const int num, int a, int b) { if(num==1){ num=3; return a+b; }else{ return 0; } } int main(){ int num=100; int a=12,b=22; int res; num=1; res=addto(num,a,b); printf("res=%d\n",res); return 0; }
編譯報錯為:
[rocrocket@wupengchong const_test]$ !cc
cc test2.c
test2.c: In function ‘addto’:
test2.c:5: error: assignment of read-only location ‘num’
可見在函數里形參被(bei)聲明為const的變量也是不能修(xiu)改的哦!呵呵~
const其實不難(nan),把(ba)本文(wen)的幾個小例子(zi)看懂就OK了!
除了傳遞要(yao)求為(wei)const的參(can)數以(yi)外,自己(ji)聲明(ming)對(dui)(dui)象沒(mei)有什(shen)么必須要(yao)加,但是(shi)對(dui)(dui)于一個邏輯上不應(ying)該被修改(gai)(gai),應(ying)該為(wei)常量的對(dui)(dui)象,沒(mei)有聲明(ming)為(wei)const,就必須由程(cheng)序員(yuan)自己(ji)來維護,來記(ji)住這個變量不應(ying)該被修改(gai)(gai),即使你不小心修改(gai)(gai)導致程(cheng)序整體混(hun)亂了,編譯器(qi)也不會報錯
另,const和普通(tong)變量的聲明存在(zai)于(yu)頭文件時有區別(bie),總之(zhi)這(zhe)些都是(shi)與你具體寫(xie)程(cheng)(cheng)序的規劃有關系,const這(zhe)個玩意只是(shi)方便程(cheng)(cheng)序設計和程(cheng)(cheng)序編寫(xie),能夠使程(cheng)(cheng)序更加的清晰(xi),如果說我(wo)就是(shi)不(bu)愛用,就是(shi)喜歡一路變量用到(dao)底,那也沒(mei)什么不(bu)行