C++中的字符串(1)
1、字符串
1.1 字符串定義
字符串就是連續(xù)的一連串字符,在C++當(dāng)中, 處理字符串的方式有兩種類型。一種來自于C語言,也被稱為C風(fēng)格字符串。另外一種是基于string
類庫。
C風(fēng)格的字符串其實就是字符存儲在char
數(shù)組當(dāng)中。不過它和一般的數(shù)組有一些區(qū)別,擁有一些特殊的性質(zhì)。比如一空字符\0結(jié)尾,它的ascii
碼是0,用來標(biāo)記字符串的結(jié)尾。
char str[5] = {'h', 'e', 'l', 'l', 'o'}; char str2[5] = {'h', 'e', 'l', 'l', '\0'};
對于上面的兩個例子,第一個例子雖然也是char數(shù)組,但是由于它的結(jié)尾不是\0,所以它不能看成是字符串。因為很多算法都是以\0的位置為標(biāo)記的,比如計算字符串長度的算法,以及cout等等。
上面我們采用的是數(shù)組常規(guī)的初始化方式,這當(dāng)然是可以的,不過這樣會很不方便。一個是需要一位一位地填寫字符,會非常地麻煩。另外還需要手動填充\0,也容易忘記,
所以對于字符串而言我們還有更好的初始化方式:
char hello[6] = "hello"; char world[] = "world";
用引號括起來的字符串隱式地包含了結(jié)尾的\0,需要注意的是,我們在確定數(shù)組長度的時候需要將結(jié)尾的\0也計算在內(nèi)。
這里要提醒大家注意引號的區(qū)別, 在C++當(dāng)中單引號表示單個字符,而雙引號表示字符串。所以下面這種寫法是錯誤的:
char c = "S";
并且“S”其實表示的是字符串所在的內(nèi)存地址,當(dāng)我們把一個內(nèi)存地址賦值給一個char類型的時候自然就會報錯了。
咦,不是說好的是字符串么,怎么又扯到地址了?不要急,等后面講到指針的地方就明白了。
1.2 字符串的讀入
直接用字符串常量來初始化字符數(shù)組只是一種方式,另外一種常用的方式是只定義字符數(shù)組的長度,從外部讀入數(shù)據(jù),
如:
char str[100]; scanf("%s", str); cin >> str;
無論是使用scanf
還是cin
,都是一樣的效果。
但是沒有這么簡單,比如我們再來看一段代碼:
char name[100]; char level[100]; scanf("%s", name); scanf("%s", level);
在這段代碼當(dāng)中,我們定義了name和level兩個字符串變量。當(dāng)我們執(zhí)行的時候,就會發(fā)現(xiàn)問題:
我剛輸入完名字,還沒來得及輸level
就結(jié)束了。如果我們把name
和level
分別輸出的話就會發(fā)現(xiàn),name
的值是liang
,level
的值是tang
。
這說明了什么?說明了我們讀入字符串的時候它并不是按行讀入的,而是按照空格分隔的!它不像是隔壁的Python
,input
默認(rèn)就是讀入一行,C++的讀入默認(rèn)都是按照空格分隔的。
那問題來了,假如我們需要讀入一行應(yīng)該怎么辦呢?也有辦法,我們可以使用cin.getline
代替之前的scanf
或者是cin
。
我們來看下它的函數(shù)簽名:
istream& getline ( istream& is, string& str, char delim ); istream& getline ( istream& is, string& str );
C++允許參數(shù)列表不同的同名函數(shù)重載,這兩個簽名都是OK的。兩者的差別在于第三個參數(shù),但三個參數(shù)表示分隔符,如果不傳的話,默認(rèn)是'\n'。第二個參數(shù)表示字符串的長度,所以如果要按照行來讀入字符串的話,剛剛的代碼應(yīng)該寫成:
cin.getline(name, 100); cin.getline(level, 100);
除了可以使用getline
之外,還可以使用get
。get
有好幾種變體,一種變體是讀入一個字符,它有一種變體也可以讀入一行字符串。不過唯一的區(qū)別是,get函數(shù)不會處理行尾的換行符。如果我們要讀入兩行字符的話,需要手動將這個換行符處理掉。
cin.get(name, 100); // 讀入一行數(shù)據(jù) cin.get(); // 讀入換行符 cin.get(level, 100);// 讀入第二行數(shù)據(jù)
寫成三行看起來有些繁瑣,我們還可以進(jìn)行簡化,簡化成一行:
cin.get(name, 100).get().get(level, 100);
看起來很像是Java8
的流式編程,能夠這樣做的原因是get
和getline
函數(shù)會返回一個cin
的對象。所以我們可以這樣連續(xù)調(diào)用。
相信有些同學(xué)已經(jīng)注意到了,同樣的函數(shù)名,根據(jù)我們傳入的參數(shù)不同執(zhí)行了不同的邏輯。這在C++當(dāng)中叫做函數(shù)重載,是一個非常重要的概念。
1.3 排坑
關(guān)于getline
有一個比較大的坑,當(dāng)我們同時使用cin
和getline
的時候,有時候會出現(xiàn)問題。
比如下面這段代碼:
int a; char name[100]; cin >> a; cin.getline(name, 100); cout << "a = " << a << endl; cout << "name = " << name << endl;
這段代碼很簡單,我們定義了兩個變量。一個是int
型的a
,一個是字符串name
。我們使用cin
讀入a,使用getline
讀入name
。
這看起來一點問題也沒有,但是當(dāng)我們運行的時候就會出現(xiàn)問題。
會發(fā)現(xiàn)我都沒有來得及輸入name
,程序就結(jié)束了,而name
讀到了一個空。
這并不是C++
有bug,而是我們在輸入32的時候,敲了一個回車。所以在使用getline
讀入一行的時候,看到了回車,直接退出了,讀入了一個空行,這就是為什么我們沒有機(jī)會輸入name
的原因。
要解決這個問題怎么辦呢?其實也很簡單,我們額外讀入一個字符,把換行符給讀取掉就行了。
int a; char name[100]; cin >> a; cin.get(); // getchar() C語言版本 cin.getline(name, 100); cout << "a = " << a << endl; cout << "name = " << name << endl;
類似的問題在競賽的題目當(dāng)中很常見,我們經(jīng)常要同時讀入字符串和數(shù)字,很容易遇到這樣的問題。遇到了不要緊張,仔細(xì)檢查一下數(shù)據(jù)和邏輯,看看是不是讀入到了換行符。
到此這篇關(guān)于C++中的字符串(1)的文章就介紹到這了,更多相關(guān)C++字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
注:文章轉(zhuǎn)自微信公眾號:Coder梁(ID:Coder_LT)
相關(guān)文章
C++?std::chrono庫使用示例(實現(xiàn)C++?獲取日期,時間戳,計時等功能)
std::chrono是C++標(biāo)準(zhǔn)庫中的一個組件,用于表示和處理時間,這篇文章主要介紹了C++?std::chrono庫使用指南(實現(xiàn)C++?獲取日期,時間戳,計時等功能),需要的朋友可以參考下2023-06-06