相同點
首先 這兩種類型都可以對應(yīng)一個字符串,比如:
char* a = "string1";
char b[] = "string2";
printf("a = %s, b = %s ", a, b);
其中a是一個指向char變量的指針,b則是一個char數(shù)組(字符數(shù)組)眯亦,
其次 ,很多時候二者可以混用般码,像函數(shù)傳參數(shù)的時候妻率,實參可以是char*,形參可以是 char[],比如:
void fun1(char b[])
{
printf("%s",b);
}
int main()
{
char* a = "HellowWorld";
fun1(a);
}
反過來板祝,實參可以是char[],形參可以是 char*也是可以的宫静。
存在即合理,char*和char[]肯定是有本質(zhì)的不同券时。
不同點
1.char*是變量孤里,值可以改變, char[]是常量橘洞,值不能改變捌袜。
比如:
char* a = "string1";
char b[] = "string2";
a = b; //OK
a = "string3"; //OK
b = a; //報錯!左邊操作數(shù)只讀
b = "string3" ; //報錯炸枣!左邊操作數(shù)只讀
解釋:a是一個char型指針變量虏等,其值(指向)可以改變弄唧; b是一個char型數(shù)組的名字,也是該數(shù)組首元素的地址霍衫,是常量候引,其值不可以改變 。
2.char[]對應(yīng)的內(nèi)存區(qū)域總是可寫敦跌,char*指向的區(qū)域有時可寫澄干,有時只讀
比如:
char* a = "string1";
char b[] = "string2";
gets(a); //試圖將讀入的字符串保存到a指向的區(qū)域,運(yùn)行崩潰柠傍!
gets(b); //OK
解釋: a指向的是一個字符串常量麸俘,即指向的內(nèi)存區(qū)域只讀;
b始終指向他所代表的數(shù)組在內(nèi)存中的位置惧笛,始終可寫疾掰!
注意,若改成這樣gets(a)就合法了:
char* a = "string1";
char b[] = "string2";
a = b; //a,b指向同一個區(qū)域徐紧,注意這里改變了a的指向
gets(a); //OK
printf("%s",b); //會出現(xiàn)gets(a)時輸入的結(jié)果
解釋: a的值變成了是字符數(shù)組首地址静檬,即&b[0],該地址指向的區(qū)域是char *或者說 char[8]并级,習(xí)慣上稱該類型為字符數(shù)組拂檩,其實也可以稱之為“字符串變量”,區(qū)域可讀可寫嘲碧。
注意:char *本身是一個字符指針變量稻励,但是它既可以指向字符串常量,又可以指向字符串變量愈涩,指向的類型決定了對應(yīng)的字符串能不能改變望抽。
3.char * 和char[]的初始化操作有著根本區(qū)別:
測試代碼:
char* a = "Hello World";
char b[] = "Hello World";
printf("%s, %d\n","Hello World", "Hello World");
printf("%s, %d %d\n", a, a, &a);
printf("%s, %d %d\n", b, b, &b);
結(jié)果:
結(jié)果可見:盡管都對應(yīng)了相同的字符串,但”Hellow World”的地址 和 a對應(yīng)的地址相同履婉,與b指向的地址有較大差異煤篙;&a 、&b都是在同一內(nèi)存區(qū)域毁腿,且&b==b
根據(jù)c內(nèi)存區(qū)域劃分知識辑奈,我們知道,局部變量都創(chuàng)建在棧區(qū)已烤,而常量都創(chuàng)建在文字常量區(qū)鸠窗,顯然,a胯究、b都是棧區(qū)的變量稍计,但是a指向了常量(字符串常量),b則指向了變量(字符數(shù)組)裕循,指向了自己(&b==b==&b[0])臣嚣。
說明以下問題:
char * a=”string1”;是實現(xiàn)了3個操作:
1聲明一個char*變量(也就是聲明了一個指向char的指針變量)净刮。
2在內(nèi)存中的文字常量區(qū)中開辟了一個空間存儲字符串常量”string1”。
3返回這個區(qū)域的地址茧球,作為值庭瑰,賦給這個字符指針變量a
最終的結(jié)果:指針變量a指向了這一個字符串常量“string1”
(注意星持,如果這時候我們再執(zhí)行:char * c=”string1”抢埋;則,c==a督暂,實際上揪垄,只會執(zhí)行上述步驟的1和3,因為這個常量已經(jīng)在內(nèi)存中創(chuàng)建)
char b[]=”string2”;則是實現(xiàn)了2個操作:
1聲明一個char 的數(shù)組逻翁,
2為該數(shù)組“賦值”饥努,即將”string2”的每一個字符分別賦值給數(shù)組的每一個元素,存儲在棧上八回。
最終的結(jié)果:“數(shù)組的值”(注意不是b的值)等于”string2”酷愧,而不是b指向一個字符串常量。
PS:
實際上缠诅, char * a=”string1”; 的寫法是不規(guī)范的溶浴!
因為a指向了即字符常量,一旦strcpy(a,”string2”)就糟糕了管引,試圖向只讀的內(nèi)存區(qū)域?qū)懭胧堪埽绦驎罎⒌模”M管VS下的編譯器不會警告褥伴,但如果你使用了語法嚴(yán)謹(jǐn)?shù)腖inux下的C編譯器GCC谅将,或者在windows下使用MinGW編譯器就會得到警告。
所以重慢,我們還是應(yīng)當(dāng)按照”類型相同賦值”的原則來寫代碼: const char * a=”string1”;
保證意外賦值語句不會通過編譯饥臂。
小結(jié)
對于
const char* a = "string1";
char b[] = "string2";
1.a是const char 類型, b是char const類型
( 或者理解為 (const char)xx 和 char (const xx) )
2.a是一個指針變量似踱,a的值(指向)是可以改變的擅笔,但a只能指向(字符串)常量,指向的區(qū)域的內(nèi)容不可改變屯援;
3.b是一個指針常量猛们,b的值(指向)不能變;但b指向的目標(biāo)(數(shù)組b在內(nèi)存中的區(qū)域)的內(nèi)容是可變的狞洋。
4.作為函數(shù)的聲明的參數(shù)的時候弯淘,char []是被當(dāng)做char *來處理的!兩種形參聲明寫法完全等效吉懊!