從零開始學C++(2 字符串、向量和數組)

  能夠說string和vector是C++標準庫中最重要的兩種類型,string支持可變長字符串,而vector表示可變長的集合。git

 

  string數組

  頭文件:<string>ide

  定義在命名空間 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

   這裏須要區分直接初始化和拷貝初始化(後面學了類相關的知識就會知道,這兩種初始化調用分別調用的是構造函數和拷貝控制的某種構造函數)。spa

  使用等號(=)初始化一個變量,實際上執行的就是拷貝初始化(copy initialization),編譯器把等號右側的初始值拷貝到新建立的對象中去。反之,不使用等號,則執行的就是直接初始化(direct initialization)設計

  

  string的操做指針

    os << s        將s寫到輸出流os中,返回oscode

    is >> s        從is中讀取字符串賦給s,字符串以空白分隔,返回is對象

    getline(is, s)  從is中讀取一行賦給s,返回isblog

    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個元素,十、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++的基礎知識,後面再單獨寫其餘深刻的內容。

相關文章
相關標籤/搜索