原文鏈接:(只是格式化了一下好看。)
https://blog.csdn.net/u012611878/article/details/78291036
相同點(diǎn)
1. 首先 這兩種類型都可以對應(yīng)一個(gè)字符串焙压,比如:
char * a="string1";
char b[]="string2";
printf("a=%s, b=%s", a, b);
其中a是一個(gè)指向char變量的指針段审,b則是一個(gè)char數(shù)組(字符數(shù)組),
2. 其次 德迹,很多時(shí)候二者可以混用芽卿,像函數(shù)傳參數(shù)的時(shí)候,實(shí)參可以是char*
,形參可以是 char[]
胳搞,比如:
void fun1(char b[])
{
printf("%s", b);
}
int main()
{
char *a = "HellowWorld";
fun1(a);
}
反過來卸例,實(shí)參可以是char[],形參可以是 char *也是可以的。
存在即合理肌毅,char *和char[]肯定是有本質(zhì)的不同筷转。
不同點(diǎn)
1. char*是變量,值可以改變芽腾, char[]是常量旦装,值不能改變。
比如:
char * a="string1";
char b[]="string2";
a=b摊滔; //OK
a="string3"; //OK
b=a; //報(bào)錯(cuò)阴绢!左邊操作數(shù)只讀
b="string3" //報(bào)錯(cuò)店乐!左邊操作數(shù)只讀
解釋: a是一個(gè)char型指針變量,其值(指向)可以改變呻袭;
b是一個(gè)char型數(shù)組的名字眨八,也是該數(shù)組首元素的地址,是常量左电,其值不可以改變 廉侧。
2. char[]對應(yīng)的內(nèi)存區(qū)域總是可寫,char*指向的區(qū)域有時(shí)可寫篓足,有時(shí)只讀
比如:
char * a="string1";
char b[]="string2";
gets(a); //試圖將讀入的字符串保存到a指向的區(qū)域段誊,運(yùn)行崩潰!
gets(b) //OK
解釋: a指向的是一個(gè)字符串常量栈拖,即指向的內(nèi)存區(qū)域只讀连舍;
b始終指向他所代表的數(shù)組在內(nèi)存中的位置,始終可寫涩哟!
注意索赏,若改成這樣gets(a)就合法了:
char * a="string1";
char b[]="string2";
a=b; //a,b指向同一個(gè)區(qū)域,注意這里改變了a的指向
gets(a) //OK
printf("%s",b) //會(huì)出現(xiàn)gets(a)時(shí)輸入的結(jié)果
解釋:a的值變成了是字符數(shù)組首地址贴彼,即&b[0]潜腻,該地址指向的區(qū)域是char *或者說 char[8],習(xí)慣上稱該類型為字符數(shù)組器仗,其實(shí)也可以稱之為"字符串變量"融涣,區(qū)域可讀可寫。
注意:char *本身是一個(gè)字符指針變量青灼,但是它既可以指向字符串常量暴心,又可以指向字符串變量,指向的類型決定了對應(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ū)域劃分知識(shí)策橘,我們知道炸渡,局部變量都創(chuàng)建在棧區(qū),而常量都創(chuàng)建在文字常量區(qū)丽已,顯然蚌堵,a、b都是棧區(qū)的變量,但是a指向了常量(字符串常量)吼畏,b則指向了變量(字符數(shù)組)督赤,指向了自己(&b==b==&b[0])。
說明以下問題:
char * a="string1";
是實(shí)現(xiàn)了3個(gè)操作:
- 聲明一個(gè)char*變量(也就是聲明了一個(gè)指向char的指針變量)泻蚊。
- 在內(nèi)存中的文字常量區(qū)中開辟了一個(gè)空間存儲(chǔ)字符串常量"string1"躲舌。
- 返回這個(gè)區(qū)域的地址,作為值性雄,賦給這個(gè)字符指針變量a
最終的結(jié)果:指針變量a指向了這一個(gè)字符串常量"string1"(注意没卸,如果這時(shí)候我們再執(zhí)行:char * c="string1";則秒旋,c==a约计,實(shí)際上,只會(huì)執(zhí)行上述步驟的1和3滩褥,因?yàn)檫@個(gè)常量已經(jīng)在內(nèi)存中創(chuàng)建)
char b[]="string2";
則是實(shí)現(xiàn)了2個(gè)操作:
- 聲明一個(gè)char 的數(shù)組病蛉,
- 為該數(shù)組"賦值"炫加,即將"string2"的每一個(gè)字符分別賦值給數(shù)組的每一個(gè)元素瑰煎,存儲(chǔ)在棧上。
最終的結(jié)果:"數(shù)組的值"(注意不是b的值)等于"string2"俗孝,而不是b指向一個(gè)字符串常量
PS:
實(shí)際上酒甸, char * a="string1"; 的寫法是不規(guī)范的!
因?yàn)閍指向了即字符常量赋铝,一旦strcpy(a,"string2")就糟糕了插勤,試圖向只讀的內(nèi)存區(qū)域?qū)懭耄绦驎?huì)崩潰的革骨!盡管VS下的編譯器不會(huì)警告农尖,但如果你使用了語法嚴(yán)謹(jǐn)?shù)腖inux下的C編譯器GCC,或者在windows下使用MinGW編譯器就會(huì)得到警告良哲。
所以盛卡,我們還是應(yīng)當(dāng)按照"類型相同賦值"的原則來寫代碼: const char * a="string1";
保證意外賦值語句不會(huì)通過編譯。
小結(jié)
對于
const char * a="string1"
char b[]="string2";
a是const char 類型筑凫, b是char const類型
( 或者理解為 (const char)xx 和 char (const xx) )a是一個(gè)指針變量滑沧,a的值(指向)是可以改變的,但a只能指向(字符串)常量巍实,指向的區(qū)域的內(nèi)容不可改變滓技;
b是一個(gè)指針常量,b的值(指向)不能變棚潦;但b指向的目標(biāo)(數(shù)組b在內(nèi)存中的區(qū)域)的內(nèi)容是可變的
作為函數(shù)的聲明的參數(shù)的時(shí)候令漂,char []是被當(dāng)做char *來處理的!兩種形參聲明寫法完全等效!