可以說string和vector是C++標準庫中最重要的兩種類型,string支持可變長字元串,而vector表示可變長的集合。 string 頭文件:<string> 定義在命名空間 std 中,using std::string; string s1; // 預設初始化,s1是一個空串 stri ...
可以說string和vector是C++標準庫中最重要的兩種類型,string支持可變長字元串,而vector表示可變長的集合。
string
頭文件:<string>
定義在命名空間 std 中,using std::string;

string s1; // 預設初始化,s1是一個空串
string s2(s1); // s2是s1的副本
string s3 = s1; // s3是s1的副本
string s4("value"); // s4是字面值"value"的副本,除了字面值最後的那個空字元外
string s5 = "value"; // 等價於上面的括弧初始化
string s6(n, 'c'); // 把s6初始化為由連續n個字元c組成的串
View Code
這裡需要區分直接初始化和拷貝初始化(後面學了類相關的知識就會知道,這兩種初始化調用分別調用的是構造函數和拷貝控制的某種構造函數)。
使用等號(=)初始化一個變數,實際上執行的就是拷貝初始化(copy initialization),編譯器把等號右側的初始值拷貝到新創建的對象中去。反之,不使用等號,則執行的就是直接初始化(direct initialization)。
string的操作
os << s 將s寫到輸出流os中,返回os
is >> s 從is中讀取字元串賦給s,字元串以空白分隔,返回is
getline(is, s) 從is中讀取一行賦給s,返回is
s[n] 返回s中第n個字元的引用,位置n從0計起
s1 + s2 返回s1和s2連接後的結果

// 讀取未知數量的string對象
int main()
{
string word;
while (cin >> word)
cout << word << endl;
return 0;
}
View Code
string的size()函數返回類型為string::size_type,它是一個無符號類型的值,而且能足夠存放下任何string對象的大小。
string對象與字元字面值或者字元串字面值相加時,必須確保每個加法運算符(+)的兩側的運算對象至少有一個是string對象:

int main()
{
string str1("hell");
string str2 = str1 + 'o' + " world";
cout << str2 << endl;
return 0;
}
View Code
如何處理string對象中的字元呢?
頭文件cctype中定義了一組標準庫函數
isalnum(c) 當c是字母或數字時為真
isalpha(c) 當c是字母時為真
iscntrl(c) 當c是控制字元時為真
isdigit(c) 當c是數字時為真
isgraph(c) 當c不是空格但可列印時為真
islower(c) 當c是小寫字母時為真
isprint(c) 當c是可列印字元時為真
ispunct(c) 當c是標點符號時為真
isspace(c) 當c時空白時為真(即c是空格、橫向製表符、縱向製表符、回車、換行、進紙符)
isupper(c) 當c是大寫字母時為真
isxdigit(c) 當c是十六進位數字時為真
tolower(c) 如果c是大寫字母,輸出對應的小寫字母;否則原樣輸出c
toupper(c) 如果c是小寫字母,輸出對應的大寫字母;否則原樣輸出c

string str3("abcdefgh0123");
for (auto c : str3) {
if (isxdigit(c)) {
cout << "0x" << c << endl;
} else {
cout << c << endl;
}
}
View Code
vector
也被稱為容器(container),頭文件<vector>,using std::vector;
vector是一個類模板(class template)。模板本身不是類或函數,可以將模板看作為編譯器生成類或函數編寫的一份說明。編譯器根據模板創建類或函數的過程稱為實例化(instantiation),當使用模板時,需要指出編譯器應該把類或函數實例化成何種類型。
vector的使用
vector<int> ivec; // ivec保存int類型的對象
vector<ClassObj> co_vec; // co_vec保存ClassObj類類型的對象
vector<vector<string>> files; // files保存的元素是vector對象
定義和初始化
vector<T> v1; // v1是一個空vector,它潛在的元素是T類型的,執行預設初始化
vector<T> v2(v1); // v2中包含有v1所有元素的副本
vector<T> v2 = v1; // 等價於v2(v1)
vector<T> v3(n, val); // v3包含了n個重覆的元素,每個元素的值都是val
vector<T> v4(n); // v4包含了n個重覆地執行了值初始化的對象
vector<T> v5{a,b,c...}; // 列表初始化,包含了{}中的元素
vector<T> v6={a,b,c...}; // 同上
使用列表初始化時,註意:
vector<int> v1{10}; // v1只有一個元素
vector<int> v2(10); // v2有10個元素
vector<int> v3{10, 1}; // 2個元素,10、1
vector<int> v4(10, 1); // 10個元素,值都是1
用圓括弧:提供的值用來構造(construct)vector對象
用花括弧:列表初始化該vector對象,也就是說,初始化過程會儘可能地把花括弧內的值當成是元素初始值的列表來處理,只有在無法執行列表初始化時才會考慮其他初始化方式。
vector<string> v5{10}; // v5有10個預設初始化的元素
vector<string> v6{10, "hi"}; // v6有10個值為"hi"的元素
上面兩條語句儘管使用了花括弧,但是花括弧中的值(10)與元素類型(string)不匹配,不能作為元素的初始值,編譯器會嘗試使用構造函數去初始化對象。
vector<string> v7{10, "hi", "hello"}; // 錯誤
使用push_back向vector對象中添加元素
vector<int> ivec;
for (int i = 0; i != 10; ++i) {
ivec.push_back(i);
}
迭代器(iterator)
提供迭代器的類型,擁有begin和end成員函數,begin返回指向第一個元素(或第一個字元)的迭代器;end返回容器(或string對象)“尾元素的下一位置”的迭代器。
auto b = ivec.begin(), e = ivec.end();
如果容器為空,則begin和end返回的是同一個迭代器,都是尾後迭代器。
擁有迭代器的標準庫類型使用iterator和const_iterator來表示迭代器的類型:
vector<int>::iterator iter1; // iter1能讀寫vector<int>的元素
string::iterator iter2;
vector<int>::const_iterator iter3; // iter3 只能讀元素,不能寫元素
vector和string迭代器支持的運算
iter + n iter - n iter += n iter -= n
iter1 - iter2 兩個迭代器相減的結果是它們之間的距離,參與元素的兩個迭代器必須指向的是同一個容器中的元素或尾元素的下一位置
>、>=、<、<=
註意:兩個迭代器不能相加!!!(沒有意義)
數組
在C++代碼中,儘可能地使用vector,而不使用數組。
數組的聲明:a[d],其中a是數組的名字,d是數組的維度。維度說明瞭數組中元素的個數,因此必須大於0。數組中元素的個數也屬於數組類型的一部分,編譯的時候維度必須是已知的,因此,維度必須是一個常量表達式:
unsigned cnt = 10;
constexpr unsigned sz = 10;
int arr[10]; // 正確
int *parr[sz]; // 含有10個整型指針的數組
string err[cnt]; // 錯誤:cnt不是常量表達式
string strs[GetSize()]; // 當GetSize()是constexpr時正確,否則錯誤
數組下標的類型為size_t,size_t是一種機器相關的無符號類型,被設計得足夠大以便能表示記憶體中任意對象的大小,在頭文件<cstddef>中。
在很多用到數組名字的地方,編譯器都會自動地將其替換為一個指向數組首元素的指針:
string nums[] = {"a", "b", "c"};
string *p = &nums[0]; // 指向nums的第一個元素
string *ps = nums; // 等價
在一些情況下,數組的操作實際上是指針的操作,所以當使用數組作為一個auto變數的初始值時,推斷得到的類型是指針而非數組:
int ia[] = {0,1,2,3,4,5};
auto ia2(ia); // ia2是一個整型指針,指向ia的第一個元素
當使用decltype關鍵字時上述轉換不會發生:
decltype(ia) ia3 = {0,1,2,3,4,5};
ia3[4] = 10;
標準庫函數begin和end,與容器中的兩個同名成員功能類似,作用於數組。
C風格字元串
它不是一種類型,而是為了表達和使用字元串而形成的一種約定俗成的寫法。按此習慣書寫的字元串存放在字元數組中並以空字元結束。
strlen(p) 返回p的長度,空字元不計算在內
strcmp(p1, p2) 比較p1和p2,如果p1==p2,返回0,如果p1>p2,返回正值,否則返回一個負值
strcat(p1, p2) 將p2附加到p1之後,返回p1
strcpy(p1, p2) 將p2拷貝給p1,返回p1
string對象轉換為C風格字元串:str.c_str();
本來想把《STL源碼剖析》中的vector實現寫出來,但是內容就太多了,所以現階段就只寫C++的基礎知識,後面再單獨寫其他深入的內容。