1、數組
聲明格式:float loans[20];
loans的類型不是“數組”,而是“float 數組”。這強調數組是使用float類型創建的。其中,方括號中的元素個數必須為整型常數或const值,也可以是常量表達式(如8*sizeof(int)),但不能是變量,因為變量的值是在程序運行時設置的。
需要注意的是:C++數組從0開始編號,C++使用帶索引的方括號表示法來指定數組元素。例如months[0]是months數組的第一個元素,months[11]是最後一個元素。注意,最後一個元素的索引比數組長度小1.
(1)有效下標值的重要性
編譯器不會檢查使用的下標是否有效。例如,如果將一個值賦給不存在的元素months[101],編譯器並不會指出錯誤。但是程序運行後,這種賦值可能引發問題,它可能破壞數據或代碼,也可能導致程序異常終止。所以必須保證程序使用只使用有效的下標。
(2)初始化數組
int yamcosts[3] = {20, 30, 5};
只需提供一個用逗號分隔的值列表(初始化列表),並將它們用花括號括起來即可。如果沒有初始化函數中定義的數組,則其元素值將是不確定的。這意味著元素的值為以前駐留在該內存單元中的值。
當數組中元素數目與初始化器中值的數目不想同時情況。只有在定義數組時才能使用初始化,此後就不能使用了,也不能將一個數組賦給另一個數組:
int cards[4] = {3, 6, 8, 10};
int hand[4] ;
hand[4] ={5, 6, 7, 9}; //這種是不正確的
hand = cards; //不正確
要想給數組賦值,必須使用下標分別給數組中的元素賦值。如果只對數組的一部分進行初始化,則編譯器將把其他元素設置為0。
2、字符串
字符串是存儲在內存的連續字節中的一系列字符。C++處理字符串的方式有兩種。一種是來自C語言,常被稱為C-風格字符串(C-style string)。另一種是基於string類庫的方法。
(1)C-風格字符串
存儲在連續字節中的一系列字符意味著將字符串存儲在char數組中,其中每個字符都位於自己的數組元素中。C-風格的字符串有一種特殊的性質:以空字符結尾,空字符被寫為\0。其ASCII碼為0,用來標識字符串的結尾。例如下面兩個字符串:
這兩個數組中,只有第二個是字符串。空字符對C-風格字符串而言至關重要。C++有很多處理字符串的函數,其中包括cout使用的那些函數。它們都逐個的處理字符串中的字符,直到到達空字符為止。
例如上面兩個數組,如果用cout輸出字符串,第二個數組輸出到\0就結束了,所以會輸出7個字符;但是第一個數組並沒有\0字符,所以cout會一直輸出後面內存中的字符,直到遇到\0為止。雖然也很容易會有\0存在,但是還是不應該將不是字符串的字符數組當作字符串來處理。
如果像上面那樣用{}和‘’處理字符串,工作會變得很麻煩。不必擔心,有一種更好的、將字符數組初始化為字符串的方法----只需使用一個用引號括起來的字符串即可,這種字符串被稱為字符串常量或字符串字面值。如下所示:
char bird[11] = "Mr. Cheeps";
char fish[] = "Bubbles";
用引號括起來的字符串隱式的包括結尾的空字符,因此不用顯式的包括它。
①關於字符串的長度:
注意區分兩個運算符:sizeof運算符指出整個數組的長度,比如說char cat[12] = "hello";,用sizeof(cat)得到的是12,即數組的長度;但是使用strlen函數返回的是存儲在數組中的字符串的長度,而不是數組本身的長度,而且不包括空字符在內,所以上例strlen(cat)得到的是5,即hello的長度。
②關於字符串的輸入:
字符串的輸入存在兩個缺陷,第一個缺陷是cin使用(空格、制表符和換行符)來確定字符串的結束位置;第二個缺陷是輸入的字符串可能比目標數組長。
先看第一個例子:
來看一下這個例子的輸出結果:
看看有什麼問題呢?cin在獲取字符串數組輸入時只讀取一個單詞,讀取該單詞之後cin把該字符串放到數組中,並自動在結尾添加空字符。
這個例子的結果是cin把Alistair作為第一個字符串,並把它放到name數組中,把Dreeb留在輸入隊列中。當cin在輸入隊列中搜索用戶喜歡的甜點時,它發現了Dreeb,因此cin讀取Dreeb,並將它放在dessert數組中。
第二個缺陷的例子是cin不能防止將包含30個字符的字符串放到20個字符的數組中。
後面章節會介紹到cin的高級功能會解決這兩個問題,大家不要著急。
③每次讀取一行字符串輸入
每次讀取一個字符串顯然不是很好的選擇,比如程序要求輸入城市名New York,使用cin得到的只是第一個單詞New,顯然這並不是你想要的完整的城市名。要想將整條短語而不是單詞作為字符輸入,需要采用另一種字符串讀取方法。具體地說,需要采用面向行而不是面向單詞的方法。
istream中的類正好提供了這樣的兩個函數:getline()和get()。這兩個函數都讀取一行輸入,直到到達換行符。然而,隨後getline()將丟棄換行符,而get()將換行符保留在輸入隊列中。下面將分別介紹這兩個函數。
a、面向行的輸入:getline()
getline()函數讀取整行,使用回車鍵輸入的換行符來確定輸入結尾,但是並不將換行符保存到隊列中。要調用這種方法,可以使用cin.getline()。
例如:假設使用getline()將姓名讀入到一個包含20個元素的name數組中,可以使用這樣調用:
cin.getline(name,20);
第一個參數是用來存儲輸入行的數組的名稱,第二個參數是要讀取的字符數。如果這個參數為20,則函數最多讀取19個字符,余下的空間用於存儲自動在結尾處添加的空字符。getline()成員函數在讀取指定數目的字符或遇到換行符時停止讀取。
同樣用上節中的例子:
該程序現在可以讀取完整的姓名和用戶喜歡的甜點了。getline()函數每次讀取一行,它通過換行符來確定行尾,但不保存換行符。相反,在存儲字符串時,它用空字符來替換換行符。
b、面向行的輸入:get()
istream類有另一個名為get()的成員函數,該函數有幾種變體用法如下:
其中一種與getline()類似,參數相同,並且都讀取到行尾,但是get()將換行符留在輸入隊列中,假如我們連續兩次調用get():
cin.get(name,ArSize);
cin.get(dessert,Arsize);
由於第一次調用後,換行符留在輸入隊列中,因此第二次調用時看到的第一個字符就是換行符,get()認為已經到行尾了,而沒有發現任何可讀取的內容。所以在上面兩條語句中,name中存儲了一行字符串,而dessert中是空的。
get()還有另一種變體。即使用不帶任何參數的cin.get()調用讀取下一個字符(即使是換行符),因此可以用它來處理換行符,為讀取下一行做好准備。上面語句可以換成如下:
cin.get(name,ArSize);
cin.get();
cin.get(dessert,Arsize);
這樣第二個語句就把換行符讀取了,然後再讀第三條語句就沒有影響了。
還有一種方式就是使用get()的方式將兩個類成員函數拼接起來(合並),如下所示:
cin,get(name, ArSize).get();
同樣,getline()也可以這麼用:
cin.getline(name1,ArSize).getline(name2,ArSize);
還是上面的例子,可以這麼表達:
從上面幾個例子的對比我們可以總結一下,輸入一行完整的字符串的方法有這麼幾種:使用cin.getline(name,20)或者使用cin.get(name,20).get()。那麼我們應該選擇使用哪一種呢?
當然,都可以,但是使用get()輸入更仔細。例如,假如使用get()將一行讀入數組中,如何知道停止讀取的原因是由於已經讀取了整行,而不是由於數組已經填滿了呢?查看下一個字符,如果是換行符,說明已讀取了整行,否則,說明該行中還有其他輸入。總之,getline()使用起來更簡單一些,但get()使得檢查錯誤更簡單些。
④混合輸入字符串和數字
混合輸入數字和面向行的字符串會導致跟上面同樣的問題。
用戶根本沒有輸入地址的機會,問題在於當cin讀取年份之後,將回車鍵留在了輸入隊列中,後面的getline()看到換行符認為是一個空行,並將這個空字符串給了address數組。解決的方法也就是上面介紹的幾種:
cin>>year;
cin.get();
或者(cin>>year).get(); 或者 (cin>>year).get(ch);
C++程序常使用指針(而不是數組)來處理字符串,以後會講到。
(2)string類簡介
ISO/ANSI C++98標准通過添加string類擴展了C++庫,因此現在可以用string類型的變量而不是字符串數組來存儲字符串。string類使用起來比數組簡單,同時提供了將字符串作為一種數據類型的表示方法。
要使用string類,必須在程序中包含頭文件string。string類位於名稱空間std中,因此需要使用using namespace std;指令。string類定義隱藏了字符串的數組性質,使得處理字符串像處理普通變量那樣簡單。
看下面的例子:
下面是運行結果:
從上面這個例子中可以看到,string對象和使用字符數組有很多相同之處:
可以使用C風格字符串來初始化string對象;
可以使用cin來將鍵盤輸入存儲到string對象;
可以使用cout來顯示string對象;
可以使用數組表示法來訪問存儲在string對象中的字符(即可以將string對象看作一個數組,可以訪問其中的某一個元素)。
字符串數組和string對象的主要區別是:可以將string對象聲明為簡單變量,而不是數組:
string str1; string str2 = "panther";
類設計讓程序能夠自動處理string的大小。例如,str1的聲明創建一個長度為0的string對象,但是將輸入讀取到str1中時,將自動調整str1的長度;這使得與數組相比string對象更方便,也更安全。
①賦值、拼接和附加
string類的操作比使用數組時更簡單。例如,不能將一個數組賦給另一個數組,但可以將一個string對象賦給另一個string對象。例如: string str1; string str2 ="pantner"; str1 = str2;
string類簡化了字符串的合並操作。可以使用運算符+將兩個string對象合並起來,還可以使用運算符+=將字符串附加到string對象末尾。如 string str3; str3 = str1+str2; str1+=str2;
處理string對象的語法通常比使用C字符串函數簡單,尤其是執行較為復雜的操作時。例如:
str3 = str1 + str2;
使用C-風格字符串時,需要使用的函數如下:strcpy(charr3,charr1); strcat(charr3, charr2);
另外,使用字符數組時總是存在目標數組過小而無法存儲指定信息的危險,如下例:char site[10] = "house";
strcat(site, " of pancakes"); 函數strcat()試圖將全部12個字符復制到數組site中,這將覆蓋相鄰的內存。這可能道枝程序終止或程序數據被破壞。而string類具有自動調整大小的功能,從而避免這種問題的發生。
確定字符串字數的方法也有區別:int len = str1.size(); int len2 = strlen(charr1);
②string類的I/O
可以使用cin或cout來輸入存儲到string對象或輸出,其句法與處理C-風格字符串相同。但是每次讀取一行而不是一個單詞。