現(xiàn)在讓我們把已經(jīng)習(xí)慣的int型數(shù)組轉(zhuǎn)換為char型。一般來講,char型數(shù)組通常是用于'a', 'b', 'c', 'd'這類具有可讀性的字符。在《類型與變量》一節(jié)中講過,char類型的數(shù)據(jù)占用1個(gè)字節(jié)的存儲(chǔ)空間,本質(zhì)上它是一種小整型類型。這表明char型數(shù)組也可用來處理數(shù)據(jù),如保存一張圖像的像素值,保存接收到來自服務(wù)器的回復(fù)信息等。隨著以后對(duì)指針的深入理解,我們會(huì)對(duì)此有更深的見解。此時(shí),我們只用它來處理可閱讀字符。
首先,讓我們嘗試輸出"hello"這個(gè)字符串,不同的是,這次是使用數(shù)組輸出。
為了明確的看到各種輸出之間的不同,我以大寫串END_STR來標(biāo)識(shí)當(dāng)前輸出的結(jié)束。
最后兩個(gè)"hello",我們都是使用printf函數(shù)加%s格式符輸出,為什么最后一個(gè)亂碼了?最明顯的不同之處在于數(shù)組的定義。str2的最后一個(gè)字符是'\0'值,而str1沒有這個(gè)值。這說明這個(gè)'\0'有特殊意義。
我們知道數(shù)組傳遞給函數(shù)時(shí),會(huì)轉(zhuǎn)換為對(duì)應(yīng)的指針類型,也就是說str2、str1傳遞給printf函數(shù)時(shí),實(shí)際會(huì)形成類似printf( char *str )形式。回想一下計(jì)算數(shù)組平均值的函數(shù),對(duì)于傳遞數(shù)組的函數(shù),除了數(shù)組變量本身外,通常還需要一個(gè)int變量以指明數(shù)組元素的個(gè)數(shù)。而我們把str2,str1傳遞給printf函數(shù)時(shí),并沒有給定元素的個(gè)數(shù)!
但是由于str2具有特殊標(biāo)記'\0',%s格式符對(duì)于該字符數(shù)組輸出了正確值,但str1卻沒有這么幸運(yùn),它亂碼了!這就說明了,'\0'指示了字符串的結(jié)束,如同給函數(shù)間接傳遞了元素個(gè)數(shù)一般。實(shí)際情況也確實(shí)如此,當(dāng)printf+%s輸出char*類型時(shí),碰到'\0'就認(rèn)為字符串結(jié)束了。
可以看到,"world"沒有被輸出,這表明C的字符串是以'\0'表示 “我的話講完了”。
那'\0'到底是什么呢?咳咳~~,又到了說說ASCII碼表的時(shí)候了!'\0'是一個(gè)轉(zhuǎn)義字符,它代表的是ASCII碼值為0的值,也是ASCII碼表中的第一個(gè)值,在C語言中用于表示字符串結(jié)尾標(biāo)記。 注意數(shù)值0與字符'0'是不同的概念,字符'0'可以理解為是書寫上用于交流0值的0。
現(xiàn)在你可以嘗試將第一個(gè)'\0'變?yōu)閿?shù)值0,你會(huì)發(fā)現(xiàn)得到同樣的輸出。再嘗試將0變?yōu)樽址?0',再次觀察輸出并思考一下。假如你一直跟隨我們的教程在學(xué)習(xí),還是有點(diǎn)緊張你會(huì)用什么樣的方式來完成這個(gè)試驗(yàn)?zāi)??我們已?jīng)學(xué)習(xí)過數(shù)組的基礎(chǔ)操作,希望你能使用下標(biāo)運(yùn)算符去修改數(shù)組中的某個(gè)值,而不是把代碼拷貝多份......
假定你現(xiàn)在在編寫一款RPG游戲,主人公有千言萬語要向玩家訴說?;诂F(xiàn)在所掌握的知識(shí),把每個(gè)字符用單引號(hào)括起來并放到數(shù)組中,那簡直就是噩夢(mèng)!好在你的擔(dān)心是多余的,你發(fā)現(xiàn)的問題,語言的設(shè)計(jì)者已經(jīng)解決了,那就是使用char*指向常量字符串!
與單個(gè)字符賦值到數(shù)組相比,這種方式真的是輕松多了,而且也具有更好的可讀性。這個(gè)程序會(huì)完整的輸出"hello, world!",也不會(huì)出現(xiàn)亂碼。這就表明,以這種賦值方式保存的字符串,語言自身會(huì)在結(jié)束加上結(jié)束標(biāo)記。
這就是C風(fēng)格的字符串,以0結(jié)束。
在這種形式下,你可能想要嘗試修改一下某個(gè)字符,如hw[0]='a',程序可以編譯過去,但執(zhí)行會(huì)出錯(cuò)。這是因?yàn)?hello, world!"是字面常量,確切的說是常量字符串,是不可修改的。(在古老的編譯環(huán)境下可能是正確的,如VC++6.0。另外,我們的聲明還可以更加精確一些,使用const chr *hw代替會(huì)更好一些,由于目前沒有學(xué)習(xí)const的意義,所以先不加;如果使用的是vs2017之類的編譯器,這里的聲明估計(jì)有問題。)
詳細(xì)的說,可以這么理解:想像一下,不管是變量還是常量,總要有能存儲(chǔ)這種東西的地方,這地方就是內(nèi)存,是內(nèi)存就有地址,對(duì)于常量存儲(chǔ)區(qū)域,具有不可寫標(biāo)記(即只讀)。hw僅是一個(gè)指針,指針的有效性就是指向一個(gè)地址,當(dāng)為hw賦值后它就指向了這個(gè)常量地址,因此編譯時(shí)是成功的。當(dāng)使用下標(biāo)修改時(shí),系統(tǒng)發(fā)現(xiàn)你想要修改只讀內(nèi)存,然后被無情打臉。
你可能會(huì)抱怨,如果我真的想要修改字符串該怎么辦?1:把常量字符串轉(zhuǎn)換為數(shù)組。2:使用動(dòng)態(tài)內(nèi)存分配。作為練習(xí),你可以基于現(xiàn)有的知識(shí),嘗試按自己的思路去實(shí)現(xiàn)方法1。當(dāng)然,這些知識(shí)在后續(xù)的教程中也會(huì)一一道來。
聯(lián)系客服