string
需要注意,為了跟C語言相容,字元串字面值與string是不同的類型。要使用string,先包含如下的内容:
#include <string>
using std::string;
初始化string的方式:
如果不指派,就得到空字元。如果使用“=”就是拷貝初始化,否則就是直接初始化。像S4那樣的操作,隻能使用直接初始化;而S2和S3則直接初始化和拷貝初始化都可以使用。
string操作:
使用cin輸入到string對象,會自動忽略開頭的空白,值到遇到下一個空白為止,其間的内容才會被放到string對象中,也即是string對象中不會有空白字元。如果想要保留輸入的空白字元,可以使用getline()函數,它會将換行符之前的所有内容都放到string對象,注意不包含換行符本身。當然,兩者遇到EOF(按Ctrl+z再按Enter)都會退出。
size()傳回的類型是string::size_type,它是無符号類型,且足夠放下任何string對象的大小。注意size()的傳回沒有包含字元串最後的空字元(其實是沒有空字元),是以"a"這個字元串的size()傳回值是1:
int main()
{
string st("a");
cout << st.size() << endl;
return 0;
}
這裡列印的結果是1。
string對象中的字元可以單獨修改。可以通過for來周遊字元:
int main()
{
string s("Hello World");
for (auto a : s) {
cout << a << endl;
}
return 0;
}
也可以修改字元:
int main()
{
string s("Hello World");
for (auto &a : s) {
a = toupper(a);
}
cout << s << endl;
return 0;
}
這裡将string對象中的字元都轉換成了大寫。需要注意跟上一個例子的差異,這裡for循環中使用了引用而不是新的變量,否則修改沒有意義。
string對象也可以通過[]用下标通路:
int main()
{
string s("Hello World");
for (auto i = 0; i <= s.size(); i++) {
s[i] = toupper(s[i]);
}
cout << s << endl;
return 0;
}
像toupper這樣的函數,在C語言也有相同功能和名稱的函數,在C++中也可以使用,如下:
還有對C風格字元串的操作(位于<cstring>):
上述函數不能作用于string對象。注意C風格字元串其實是數組,且以空字元結束。C++中最好不要使用它們。
從内置類型轉到string可以使用to_string()函數:
int main()
{
int i = 42;
// converts the int i to its character representation
string s = to_string(i);
return 0;
}
vector
vector表示對象的集合,包含的對象類型需要是相同的,但是不能包括引用(因為引用不是對象)。vector是容器的一種,後面還會介紹其它容器。要使用vector,先包含如下的内容:
#include <vector>
using std::vector;
vector的初始化:
如果未初始化,得到的是空的vector。=是拷貝初始化。如果提供初始元素值,則使用“{}”來初始化。注意跟使用“()”的差别,它是指n個val來初始化vector,val可以是預設值,有對象T本身的類型決定預設值是什麼。“{}”可以做“()”能做的初始化,而反過來則不行。
vector的操作:
size()傳回的值不是vector::size_type,而是vector<T>::size_type,T是具體的類型,比如int。通過下标可以索引vector,但是不能添加元素,添加元素使用push_back()。
vector的示例:
int main()
{
// list initialization, articles has 3 elements
vector<string> articles = {"a", "an", "the"};
vector<string> svec; // default initialization has no elements
vector<int> ivec; // ivec holds objects of type int
vector<Sales_item> Sales_vec; // holds Sales_items
vector<vector<string>> file; // vector whose elements are vectors
vector<vector<int>> vecOfvec; // each element is itself a vector
// all five vectors have size 0
cout << svec.size() << " " << ivec.size() << " "
<< Sales_vec.size() << " "
<< file.size() << " " << vecOfvec.size() << endl;
vector<int> ivec2(10); // ten elements, each initialized to 0
vector<int> ivec3(10, -1); // ten int elements, each initialized to -1
vector<string> svec2(10); // ten elements, each an empty string
vector<string> svec3(10, "hi!"); // ten strings; each element is "hi!"
cout << ivec2.size() << " " << ivec3.size() << " "
<< svec2.size() << " " << svec3.size() << endl;
// 10 is not a string, so cannot be list initialization
vector<string> v1(10); // construct v1 with ten value-initialized elements
vector<string> v2{10}; // ten elements value-initialized elements
vector<string> v3(10, "hi"); // ten elements with value "hi"
// again list initialization is not viable, so ordinary construction
vector<string> v4{10, "hi"}; // ten elements with values "hi"
// all four vectors have size ten
cout << v1.size() << " " << v2.size()
<< " " << v3.size() << " " << v4.size() << endl;
vector<string> vs1{"hi"}; // list initialization: vs1 has 1 element
vector<string> vs2{10}; // ten default-initialized elements
vector<string> vs3{10, "hi"}; // has ten elements with value "hi"
cout << vs1.size() << " " << vs2.size() << " " << vs3.size() << endl;
vector<int> v5(10, 1); // ten elements with value 1
vector<int> v6{10, 1}; // two elements with values 10 and 1
cout << v5.size() << " " << v6.size() << endl;
// intention is clearer
vector<int> alt_v3 = {10}; // one element with value 10
vector<int> alt_v4 = {10, 1}; // two elements with values 10 and 1
cout << alt_v3.size() << " " << alt_v4.size() << endl;
for (auto a : alt_v4) {
cout << a << endl;
}
for (auto i = 0; i < alt_v4.size(); i++) {
cout << alt_v4[i] << endl;
}
return 0;
}
這裡需要主要v2和v4,它們都使用了“{}”,但是因為成員是string,是以10不會被解釋成string,而是解釋成了個數,是以v2是10個空字元串的vector,跟v1一緻;v4是包含10個"hi"的vector,跟v3一緻。
疊代器
前面使用了for、下标等方式通路string和vector,還可以使用疊代器來周遊string和vector。疊代器跟指針類似,就是通過從頭到尾通路元素的方式完成周遊。string和vector,以及後面會介紹的容器,都支援疊代器,它們擁有begin()和end()兩個成員用于傳回疊代器,前者指向開頭,後者指向尾後,即最後一個元素的下一個(不存在的)元素。如果疊代器類型對象本身為空,則begi和end傳回的都是尾後。
标準容器疊代器的操作:
而string和vector支援的更多:
n是一個整型數值,但是兩個疊代器相減,得到的是類型為difference_type的值,它是帶符号整型數。
關于疊代器的示例:
int main()
{
string s("Hello World");
for (auto iter = s.begin(); iter != s.end(); iter++) {
*iter = toupper(*iter);
}
cout << s << endl;
return 0;
}
對于疊代器的類型,一般直接就寫auto了,讓編譯器來決定。不過實際上我們還是可以确定其類型的,比如上面的示例中,iter的類型是string::iterator。begin()和end()傳回的疊代器可用于修改值,因為*iter是引用,但是如果想要傳回的疊代器隻用于讀操作,則可以使用其const版本:cbegin()和cend(),它傳回的是const_iterator。
vector可以通過push_back()插入元素,此時原本的疊代器就失效了,這需要注意。
數組
數組跟C語言中的沒有太大差別。C++中增加了疊代器給數組用,使用begin()和end()函數(它們屬于std),并傳回成員的指針,也就是說指針成了疊代器,可以使用疊代器的運算操作。兩個指針相減得到的是類型為ptrdiff_t的值。在C++中編譯器在使用數組的時候會把它轉換成指針。
關于數組周遊的示例:
int main()
{
int a[] = {1, 2, 3, 4};
int *pb = std::begin(a);
int *pe = std::end(a);
for (; pb != pe; pb++) {
cout << *pb << endl;
}
return 0;
}
傳回的指針也是一個指向數組開頭,一個指向數組尾後。