(二)字符串
??? c++有兩種類型的字符串跑筝,一種是基于c語言的死讹,另一種是c++中的string類(嚴(yán)格來說string類不是通常意義上的字符串,也就是數(shù)組曲梗,而是用來表示字符串的字符串類)赞警。
1.c風(fēng)格的字符串
??? 什么是c風(fēng)格字符串?c風(fēng)格字符串有一個特殊的性質(zhì)愧旦,以空字符(null character)結(jié)尾,空字符寫作\0(實際上就是ASCII碼編號為零的字符)碘举。C風(fēng)格字符串在C和C++中都是支持的忘瓦。
??? c風(fēng)格字符串的聲明和初始化:采用字符數(shù)組的方式:比如char dog[4]={‘d’,’o’,’g’,’\0’}(初始化列表方法),聲明了一個長度為4的字符數(shù)組,字符依次為d耕皮,o境蜕,g,\0凌停,由于在結(jié)尾有一個\0粱年,因此程序?qū)⑦@個字符數(shù)組看成是字符串(就是說字符串以\0為結(jié)尾標(biāo)志);另外一種更簡單的初始化方法為使用字符串常量,即將字符串用雙引號引起來罚拟,上面的例子可以寫成char dog[]=”dog”(這種寫法相當(dāng)于大括號式的初始化列表的方法{“dog”}台诗,只不過大括號形式的寫法可以省略等號,這種形式不能省略等號);
2.注意的問題:
(1)用引號引起來的字符串隱式地包含了結(jié)尾的空字符\0赐俗。因此在確定存儲字符串所需的最短數(shù)組長度時拉队,別忘了將結(jié)尾的空字符計算在內(nèi)(數(shù)組長度等于字符數(shù)目加一,但一般我們將這份工作交給編譯器自動運行阻逮,即不加中括號里面的字符數(shù)組的長度粱快,比如上面例子里的數(shù)組長度4,而讓程序自己計算)叔扼。
(2)字符串常量不能與字符常量互換事哭,比如“a”就不等于‘a(chǎn)’,因為字符串“a”隱式地包含了\0瓜富,是一個數(shù)組鳍咱,更確切的說是一個字符數(shù)組的指針,而‘a(chǎn)’就表示a的編碼与柑,是一個字符(本質(zhì)是字符的編碼)谤辜。
(3)拼接字符串常量。
??? c++允許拼接字符串字面值仅胞,即將兩個用引號括起的字符串合并為一個每辟。事實上,任何兩個由空白(空格干旧、制表符和換行符)分隔的字符串常量都將自動拼接成一個。比如妹蔽,cout <<“how are”? “you”;不管中間的空白是空格符椎眯,制表符還是換行符,這兩個字符串都將輸出“how areyou”,注意這里沒有漏寫空格胳岂,程序就是會無縫連接编整。這里的機(jī)理就是將第一個字符串的最后面的\0去掉,然后緊跟著后一個字符串乳丰,后一個字符串末尾的\0作為整個新的字符串常量的結(jié)尾標(biāo)記掌测。
(4)字符串長度函數(shù)。有特殊的用于計算字符串長度的函數(shù)strlen()产园,要使用這個函數(shù)需要包含頭文件cstring汞斧,即#include <cstring>(這是標(biāo)準(zhǔn)C語言函數(shù)庫中的頭文件)夜郁。比如:char a[]=”dog”;cout<<a;b=strlen(a);cout<<b;結(jié)果將會輸出dog3(表示字符串有三個字符,當(dāng)然你認(rèn)為是3byte也可以粘勒,因為一個字符占用一個byte)竞端。
(5)需要特別注意strlen()函數(shù)與sizeof運算符的區(qū)別,sizeof()返回的是整個數(shù)組(數(shù)據(jù))的長度庙睡,而strlen返回的是字符串的長度事富,并且strlen()不會把結(jié)尾的\0計入長度范圍。什么意思呢乘陪?舉個例子:char a[]=”dog\0hello”;cout<<sizeof(a);會輸出什么呢统台?實測的結(jié)果是10,因為sizeof()運算符把所有的字符(包括中間那個\0)和結(jié)尾的\0都算進(jìn)去了啡邑,測的是整個字符數(shù)組的長度(字節(jié)byte)饺谬。而如果使用strlen()呢?結(jié)果是3谣拣,也就是計數(shù)了從開頭到第一個\0的長度(因為程序會認(rèn)為這就是一個字符串)募寨,并且\0還不會計算在內(nèi),因此輸出的就是只有dog三個字符的長度了森缠。
3.字符串的輸入問題:
(1)用cin輸入字符串時候會發(fā)生的問題:一是cin指令將空格等空白作為字符串分隔的標(biāo)記拔鹰,這會在輸入名字等中間帶有空格的字符串的時候出現(xiàn)問題。比如贵涵,char str[20];cin>>str;然后我輸入“Ken Thompson”列肢,程序只會在str中存儲“Ken”,整個過程是這樣的宾茂,當(dāng)我們輸入一句話然后回車的時候瓷马,這段話就會進(jìn)入輸入隊列,cin要取得輸入的時候跨晴,會從輸入隊列取第一個單詞(遇到空白即認(rèn)為是取完了一個單詞)欧聘,然后將其他的單詞保留在輸入隊列,如果此時我們再用一次cin輸入端盆,程序會直接讀取剩下的“Thompson”怀骤,而不會要求我們再用鍵盤輸入新內(nèi)容;二是焕妙,cin指令輸入的字符串超過字符數(shù)組的字?jǐn)?shù)限制怎么辦蒋伦。
(2)上面的第一個問題可以使用每次讀取一行的字符串輸入來解決,每次讀入一行的字符串的輸入函數(shù)為getline()和get();其實是面向行的類成員函數(shù)焚鹊,都是屬于cin類痕届,可以用cin對象來調(diào)用,用法為cin.getline(a,b)。getline()函數(shù)讀入后舍去回車符研叫,而get()不舍掉回車符锤窑。
??? cin.getline()有兩個參數(shù)。第一個參數(shù)是用來存儲輸入行的數(shù)組的名稱蓝撇,第二個參數(shù)是要讀取的字符數(shù)(\0計入)(如果這個參數(shù)為20果复,最多讀取19個字符)。用這個函數(shù)會讀取到最大字符數(shù)的位置或換行符的位置渤昌,然后在最后添加空字符\0虽抄,如果最后是換行符,則換行符替換為空字符独柑。
??? 注意:cin對象給string對象賦值的時候會忽略回車符迈窟,但是不丟棄回車符,也就是說回車符依然存在與緩沖隊列中忌栅,如果此時后面跟的是getline函數(shù)车酣,那么很可能就會讀到一個空行(只有回車的行)。
??? get( )的成員函數(shù)索绪,該函數(shù)有幾種變體湖员。其中一種變體的工作方式與getline( )類似, 它們接受的參數(shù)相同瑞驱,解釋參數(shù)的方式也相同娘摔,并且都讀取到行尾。但get不再讀取并丟棄換行符唤反,而是將其留在輸入隊列中凳寺。如果沒有其它幫助,get()的這種用法將不能跨過換行符彤侍。使用函數(shù)cin.get(name,size)肠缨;接著跟一個cin.get();就可以吃掉換行符,效果與cin.getline(name,size)讀取并丟掉換行符的效果一樣盏阶。上面的cin.get()函數(shù)通過不同參數(shù)類型及數(shù)目晒奕,調(diào)用的函數(shù)的效果也不相同,這就是函數(shù)的重載般哼,這在后面函數(shù)部分會再次看到吴汪。
??? getline( )使用起來簡單一些 ,但 get( )使得檢查錯誤更簡單些蒸眠,因為我們可以通過查看下一個字符是否為回車等方式來觀察字符數(shù)組是否將我們輸入的字符完全容納。可以用其中的任何一個來讀取一行輸入:只是應(yīng)該知道杆融,它們的行為稍有不同楞卡。
(3)空行和超過字符數(shù)時候的處理方式:
??? 當(dāng) get( ) (不是getline())讀取空行(空行不是空白行,空行指的是只有回車的行,一般是在用cin或cin.get(str,10)讀取一行后留下的回車符)后將設(shè)置失效位( failbit)蒋腮。這意味著接下來的輸入將被阻斷淘捡,可以使用命令cin.clear()來使阻斷的輸入繼續(xù)。(這里其實可以通過每次查看標(biāo)志位來查看發(fā)生了什么池摧,比如if(cin.rdstate() == ios::failbit))或者cin.eof(),cin.fail(),cin.bad()等方式焦除,然后來確定下一步如何做,一般在循環(huán)語句的時候使用)作彤。
??? 1炱恰!=呋洹4雌稀!輸入字符串可能比分配的空間長: 則getline( )和 get( )將把余下的字符留在輸入隊列中绢慢,而 getline( )還會設(shè)置失效位灿渴,并關(guān)閉后面的輸入,也就是跳過后面的所有的輸入語句胰舆,直到用cin.clear()來恢復(fù)阻斷位骚露。get()函數(shù)不會這樣,它只是將余下的字符當(dāng)成下一行的開頭缚窿,由下面的輸入語句繼續(xù)輸入(直到回車或達(dá)到字符數(shù)限制)棘幸。所以,使用getline我們只需要查看阻斷位就可以判斷是不是數(shù)組容量不夠滨攻,然后進(jìn)行處理够话,并且不會破壞輸入的內(nèi)容;而對于get我們要使用cin.get()來查看下一個字符是不是回車來判斷是否字符數(shù)組容量不夠光绕,如果不是回車的話女嘲,cin.get()本身會吃掉一個字符,造成內(nèi)容的破壞(可以使用cin.peek()來不破壞地查看)诞帐。
(4)綜合以上的考慮欣尼,cin對象的輸入并不是特別好用,cin本身不能跨越空格停蕉;而cin.getline()和cin.get()都是以行為輸入對象愕鼓,而這兩者又所不同,cin.getline()會吃掉回車慧起,并且不能全部容納整行的時候會設(shè)置失效位菇晃;cin.get()則不會去掉回車,并且讀取空行之后會設(shè)置失效標(biāo)志位蚓挤。也就是說磺送,cin忽略空白驻子,只輸入一個單詞;cin.get();不會丟掉換行符估灿,并且有空行的時候會阻斷崇呵;而cin.getline();會丟掉換行符,是面向行來輸入的馅袁,只有行太長的時候會阻斷域慷。即,有空白行汗销,使用get要注意犹褒,有太長的行,使用getline要注意大溜。如果是使用string對象的話化漆,因為不用考慮長度問題,因此使用cin.getline是沒有任何缺點的钦奋。