C-风格字符串
C-風格字符串
字符串是存儲在內存的連續字節中的一系列字符。C++處理字符串的方式有兩種。第一種來自C語言,常被稱為C-風格字符串(C-style string);另一種是基于string類庫的方法。
本文介紹C-風格字符串。
存儲在連續字節中的一系列字符意味著可以將字符串存儲在char數組中,其中每個字符都位于自己的數組元素中。C-風格字符串具有一種特殊的性質:以空字符(null character)結尾,空字符被寫作\0,起ASCII碼為0,用來標記字符串的結尾。例如:
char dog[8] = {'b','e','a','u','x',' ','I','I'}; //不是字符串 char cat[8] = {'f','a','t','e','s','s','a','\0'}; //是字符串- 這兩個都是char數組,但只有第二個是字符串。空字符對C-風格字符串至關重要。C++有很多處理字符串的函數,包括cout使用的那些函數,它們都逐個地處理字符串中的字符,直到發現空字符為止。
如果使用cout顯示上面的dog數組(它不是字符串),cout將打印出數組中的8個字母,并接著將內存中隨后的各個字節解釋為要打印的字符,直到遇到空字符為止。
在cat數組示例中,將數組初始化為字符串的方法要使用大量的單引號,且必須記住加上空字符,這種方法十分麻煩。有一種更好的將字符數組初始化為字符串的方法——只需使用一個用雙引號闊氣的字符串即可,這種字符串被稱為字符串常量(string constant)或字符串字面值(string literal),如下所示:
char bird[11] = "Mr. Cheeps"; //結尾自動包含\0 char fish[] = "Bubbles"; //讓編譯器自動計數用雙引號括起的字符串隱式地包含結尾的空字符,各種C++輸入工具輸入字符串到char數組中時,將自動加上結尾的空字符。
應確保數組足夠大,能夠存儲字符串中的所有字符——包括空字符。使用字符串常量初始化字符數組時,讓編譯器自動計算元素數目更為安全。
字符串常量(使用雙引號)與字符常量(使用單引號)不能互換。
字符常量(如’S’)是字符串編碼的簡寫表示,而”S”不是字符常量,它表示字符S和\0組成的字符串。而且,”S”實際上表示的是字符串所在的內存地址。
1.拼接字符串常量
有時候,字符串很長,無法放到一行中。C++允許拼接字符串常量,講講兩個用雙引號括起的字符串合并為一個。事實上,任何兩個由空白(空格、tab和換行符)分隔的字符創常量都將自動拼接成一個。因此,西面所有的輸出語句都是等效的:
cout << "I'd give my right arm to be" " a great violinist.\n"; cout << "I'd give my right arm to be a great violinist.\n"; cout << "I'd give my right ar" "m to be a great violinist.\n";注意:拼接時不會在被連接的字符串之間添加空格,第二個字符串的第一個字符將緊跟在第一個字符串的最后一個字符(不考慮\0)后面。第一個字符串中的\0將被第二個字符串的第一個字符取代。
2.在數組中使用字符串
程序4.2
#include<iostream> #include<cstring> //使用strlen()函數 int main() {using namespace std;const int Size = 15;char name1[Size]; //空數組char name2[Size] = "C++owboy"; //初始化數組cout << "Howdy! I'm " << name2;cout << "! What's your name?\n";cin >> name1;cout << "Well, " << name1 << ", your name has ";cout << strlen(name1) << " letters and is stored\n";cout << "in an array of " << sizeof(name1) << " bytes.\n";cout << "Your initial is " << name1[0] << ".\n";name2[3] = '\0'; //設置空字符cout << "Here are the first 3 charaters of my name: ";cout << name2 << endl;cin.get();cin.get();return 0; }運行結果:
sizeof()返回整個數組的長度:15字節;
strlen()返回存儲在數組中的字符串的長度,而不是數組本身的長度。strlen()只計算可見的字符,而不把空字符計算在內。
程序4.2將name2[3]設置為空字符,使得該字符串在第三個字符后就結束。
3.字符串輸入
程序4.2有一個缺陷,但該缺陷由于精心選擇輸入而被掩蓋掉了。
程序4.3
行結果:
在輸入完name(CSDN blog)后,還沒有輸入dessert,程序便將它顯示出來了,并立即顯示了最后一行。
cin如何確定字符串輸入的完成呢?
由于不能用鍵盤輸入空字符,因此cin使用空白(空格、制表符和換行符)來確定字符串的結束位置。
這意味著cin在獲取字符數組輸入時只讀取一個單詞,讀取該單詞后,cin將該字符串放到數組中,并自動在結尾添加空字符。
因此,程序4.3中,cin把CSDN作為第一個字符串,并將它放到name數組中,并自動在結尾添加空字符。這把blog留在了輸入隊列中,當cin在輸入隊列中搜索dessert時,發現了blog,因此cin讀取blog并存在dessert中。
另一個問題是,輸入字符串的長度可能比目標數組長。
4. 每次讀取一行字符串輸入
每次讀取一個單詞通常不是最好的選擇。要將整條短語而不是一個單詞作為字符串輸入,需要采用面向行而不是面向單詞的方法。
istream中的類(如cin)提供了一些面向行的類成員函數:getline()和get()。這兩個函數都能讀取一行,直到到達換行符。不同的是,getline()將丟棄換行符,而get()將換行符保留在輸入序列中。
1. 面向行的輸入:getline()
使用cin.getline()函數有兩個參數,第一個參數是用來存儲輸入行的數組名稱;第二個參數是要讀取的字符數,如果這個參數為20,則最多讀取19個字符,余下的空間用于存儲在動在結尾處添加的空字符。getline()成員函數在讀取指定數目的字符或遇到換行符時停止讀取。
cin.getline(name,20); //將輸入讀入到一個包含20個元素的name數組中程序4.4
#include<iostream> int main() {using namespace std;const int ArSize = 20;char name[ArSize];char dessert[ArSize];cout << "Enter your name:\n";cin.getline(name, ArSize); //讀取一行cout << "Enter your favorite dessert:\n";cin.getline(dessert, Arsize);cout << "I have some delicious " << dessert;cout << " for you, " << name << ".\n";cin.get();cin.get();return 0; }2. 面向行的輸入:get()
cin.get()與getline()類似,它們的參數相同。但到行尾時,get()不丟棄換行符,而是將換行符保留在輸入隊列中。假設我們連續兩次調用get():
cin.get(name, Arsize); cin.get(dessert, Arsize); //第二次調用看到的第一個字符便是換行符,因此get()認為已到達行尾,//而沒有發現任何可讀取的內容.get()有另一種變體,使用不帶任何參數的cin.get()調用可讀取下一個字符(即使是換行符),因此可以用它來處理換行符,為讀取下一行做準備,如:
cin.get(name, Arsize); cin.get(); cin.get(dessert, Arsize);或者將兩個類成員函數合并起來:
cin,get(name, Arsize).get();- ?
之所以可以這樣做,是因為cin.get(name,Arsize)返回一個cin對象,該對象隨后調用get()函數。同樣,下面的語句將連續輸入的兩行分別讀入到數組name1和name2中,其效果與兩次調用cin.getline()相同:
cin.getline(name1, Arsize).getline(name2, Arsize);- ?
程序4.5
#include<iostream> int main() {using namespace std;const int ArSize = 20;char name[ArSize];char dessert[ArSize];cout << "Enter your name:\n";cin.get(name, ArSize).get(); //讀取一行cout << "Enter your favorite dessert:\n";cin.get(dessert, ArSize).get();cout << "I have some delicious " << dessert;cout << " for you, " << name << ".\n";cin.get();cin.get();return 0; }3. 空行和其他問題
當get()讀取空行后,將設置失效位(failbit),接下來的輸入將被阻斷,但可以用下面的命令來恢復輸入:
cin.clear();- ?
如果輸入行包含的字符數比指定的多,則getline()和get()將把余下的字符留在輸入隊列中。getline()還會設置失效位,并關閉后面的輸入。
5. 混合輸入字符串和數字
混合輸入數字和面向行的字符串會導致問題。
程序4.6
運行結果:
用戶根本沒有輸入address的機會。問題在于,當cin讀取年份是,將回車鍵生成的換行符留在了輸入隊列中。后面的cin.getline()看到換行符后,將認為是一個空行,并將一個空字符串賦給address數組。
解決辦法是,在讀取地址之前先丟棄換行符。如:
- ?
- ?
C++程序常用指針(而不是數組)處理字符串。
總結
- 上一篇: Linux Vim多窗口编辑,Vim打开
- 下一篇: 怎样调整vim分屏窗口的宽度和高度?