天天看點

[C++]string、vector和數組stringvector疊代器數組

string

需要注意,為了跟C語言相容,字元串字面值與string是不同的類型。要使用string,先包含如下的内容:

#include <string>
using std::string;
           

初始化string的方式:

[C++]string、vector和數組stringvector疊代器數組

如果不指派,就得到空字元。如果使用“=”就是拷貝初始化,否則就是直接初始化。像S4那樣的操作,隻能使用直接初始化;而S2和S3則直接初始化和拷貝初始化都可以使用。

string操作:

[C++]string、vector和數組stringvector疊代器數組

使用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++]string、vector和數組stringvector疊代器數組

還有對C風格字元串的操作(位于<cstring>):

[C++]string、vector和數組stringvector疊代器數組

上述函數不能作用于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的初始化:

[C++]string、vector和數組stringvector疊代器數組

如果未初始化,得到的是空的vector。=是拷貝初始化。如果提供初始元素值,則使用“{}”來初始化。注意跟使用“()”的差别,它是指n個val來初始化vector,val可以是預設值,有對象T本身的類型決定預設值是什麼。“{}”可以做“()”能做的初始化,而反過來則不行。

vector的操作:

[C++]string、vector和數組stringvector疊代器數組

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傳回的都是尾後。

标準容器疊代器的操作:

[C++]string、vector和數組stringvector疊代器數組

而string和vector支援的更多:

[C++]string、vector和數組stringvector疊代器數組

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;
}
           

傳回的指針也是一個指向數組開頭,一個指向數組尾後。

繼續閱讀