---
# System prepended metadata

title: 'Lecture 3 Strings, Vectors and Arrays'

---

# Lecture 3 Strings, Vectors and Arrays

String
---
C++ 標準函式庫提供 string，可以使用這個類別來建立字串，便於進行高階的字串操作，像是字串指定、串接等。string 可以將字串指定給另一個字串，使用 size() 或 length() 來取得字串長度，使用 empty() 測試字串是否為空，使用 == 比較兩個字串的內容是否相同若要表現字串。C++ 建議使用 string，但要先 include string 標頭檔，並以下方式來建立實例，例如：

```
string str1;                 // 內容為空字串
string str2("caterpillar");  // 內容為指定的字串常量
string str3(str2);           // 以 str1 實例建立字串
string str4 = "Justin";      // 內容為指定的字串常量
```
另外在 string 的 input/output 中，需要注意若以 cin>>string 的寫法由終端機輸入的文字遇到空白格會忽略後續的文字，若要輸入一段文字則以 getline() 的寫法達成目的。

```
string s;
cin >> s; //input Hello World!
cout << s << endl; //output Hello

string line;
getline(cin, line); //input Hello World!
cout << line << endl; //output Hello World!

string s;
while (cin >> s) // CTRL+D to end loop
cout << s << endl;
```
loop over strings，並使用 [ ] 指定索引來存取相對應位置的 char
```
for(auto index = 0; index != s.size(); index++)
    cout << s[index] << endl;
for(auto ch : s): // for each element in s
    cout << ch << endl;
    
```

Vector
---
如果需要長度可變的資料容器，可以使用 vector，使用時需要包含< vector >標頭檔。vector 可以裝載指定型態的資料，如建立一個可裝載 int 的 vector < int >：
```
vector<int> ivec1 = {10, 20, 30}; // equal to vector<int> ivec{10, 20, 30}
vector<int> ivec2{3, 'oop'}; // equal to vector<int> ivec{'oop', 'oop', 'oop'}
vector<Sales_item> salesVec;
vector<vector<int> > matInt;
vector<int> ivec3(ivec1); // has a copy of each elements in ivec1
```
若要使用陣列的元素來建構 vector，可以透過以下的方式
```
int number[] = {10, 20, 30, 40, 50};
vector<int> v(begin(number) + 2, end(number)); // 包含 30, 40, 50
```
如果打算對 vector 進行排序、尋找、反轉等操作，可以使用包含< algorithm >標頭檔：
* 排序
```
vector<int> ivec = {30, 12, 55, 31, 98, 11, 41, 80, 66, 21};

sort(ivec.begin(), ivec.end());
for(auto i : ivec)
    cout << i << " ";
// 11 12 21 30 31 41 55 66 80 98
```
* 搜尋
```
// find() returns An iterator to the first element in the range that compares equal to val.
// If no elements match, the function returns last.
cout << "輸入搜尋值：";
int search = 0;
cin >> search;

auto it = find(ivec.begin(), ivec.end(), search);
cout << (it != ivec.end() ? "找到" : "沒有")
     << "搜尋值" 
     << endl;
/*輸入搜尋值：22
沒有搜尋值*/
```
* 反轉
```
reverse(ivec.begin(), ivec.end());
for(auto i : ivec) 
    cout << i << " ";

// 98 80 66 55 41 31 30 21 12 11
```

#### some operation of vector
vector 的 size 方法得知元素的個數，empty 方法可以得知是否為空，front 方法可以取得第一個元素，back 方法可以取得最後一個元素，想要新增元素，可以使用 push_back、insert 方法，想取出最後一個元素可以用 pop_back，clear 可以清空 vector 等。
```
ivec1.empty(); // returns true if ivec1 is empty; otherwise returns false
ivec1.size(); // returns the number of elements in ivec1

ivec1[0]; // get the n element in ivec1, equal to ivec.at(n)
ivec1.front(); // get the first element in ivec1
ivec1.back(); // get the last element in ivec1

ivec1.pop_back(); // removes last element
ivec1.push_back(40); // ivec{10,20,40}
ivec1.insert(ivec1.begin(), 5); // inserts 5 at the beginning
ivec2 = ivec1; // replace the elements in ivec2 with a copy of those in ivec1
if(ivec1 == ivec2)
    cout << "ivec has the same elements in ivec2" << endl;
ivec1.clear(); // erases the vector

```

#### loop over a vector
1. use for range method
```
vector<int> v{ 1, 2, 3 };
for (auto &i : v) // note: i is a reference{
    i *= i; // square the element value
    cout << i << " "; // print the element
}
cout << endl;
```
2. use index to access elenments with v.size()
```
vector<int> v{ 1, 2, 3 };
for (decltype(v.size()) idx = 0; idx != v.size(); ++idx){
v[idx] = v[idx] * v[idx];
cout << v[idx] << " ";
}
cout << endl;
```
3. use Iterators
iterator 是一個通用指標，不僅用於 vector 這種容器上。其機制便於取得容器中特定位置的元素，且是在 iterate 時非常便利，所寫的程式碼與其他容器具有高度相容性。begin 與 end 方法分別傳回起始位置與結束位置的 vector< int >::iterator，可以把它們看成代表首個元素與最後一個元素的位置，對它們進行 + 或 - 運算，表示元素的位移量，操作上很像指標，至於是不是真的指標，要看底層的實作而定。就 API 的設計來說，不建議將 begin、end 方法的傳回值看成是指標，而建議將之看成迭代器（iterator），這些迭代器重載了相關的運算子，令其看來像是指標操作。如對 iterator 使用 * dereference operator，可以取得該位置實際儲存的物件；並使用 ++ increment operator 來往下一個元素前進。
```
vector<int> vec{1,2,3}
auto b = vec.beign()
*b = 0; vec{0,2,3}

// C++11 way
for (auto iter = ivec.begin(); iter != ivec.end(); ++iter)
    *iter = 0; // set element to which iter refers to 0

// cbegin() & cend() are const_iterator
// const_iterator for reading but not writing to the elements in the container
for (auto iter = text.cbegin(); iter != text.cend(); ++iter)
    cout << *iter << endl;
```

Array
---
C++ 提供陣列（array），可以宣告一個以索引（index）作為識別的資料結構，在宣告時包含儲存的資料型態及陣列長度，而長度必須是個編譯時期常數。若要動態宣告陣列長度，可以使用一些資料結構與動態記憶體宣告來解決。與 vector 相比，陣列不可以直接指定給另一陣列，只能依序進行複製；若直接比較兩個陣列是否相同的話，並不是比較其內容而是比較其位址。想比較陣列元素是否相同，也只能逐一比對。但相較下有較好的執行效率。若打算對陣列進行排序、尋找、反轉等操作，同樣使用< algorithm >標頭檔進行。
```
int intArray[3] = {0}; // {0,0,0}
char ca0[0] = {'\0'}; // 字元陣列會被初始為空字元（'\0'）

int intArray[3] = {0, 1, 2}; // element initialization
int intArray[] = {0, 1, 2}; // element initialization
char ca1[] = {‘C’, ‘+’, ‘+’}; // dim = 3
char ca2[] = {‘C’, ‘+’, ‘+’, ‘\0’}; // dim = 4
char ca3[] = “C++”; // {‘C’,‘+’,‘+’,‘\0’}, dim = 4
```
如果使用 const 或 constexpr 來修飾陣列，每個索引位置就成為唯讀。
```
constexpr int ia[] = {1, 2, 3};
ia[1] = 10; // error: assignment of read-only location 'ia[1]'
```

陣列在使用時，得知陣列長度是必要的。當存取超過陣列長度的記憶體，會發生無法預期的結果，然而陣列本身並不知道自己的長度資訊。可以透過以下方式記錄陣列長度，而當在使用陣列中元素的索引值時，通常會將這個索引值定義為 size_t 的資料型態。這種資料型態確保其記憶體空間夠大以容納陣列中全部元素。
```
const size_t array_size = 5
int ia[array_size] = {0, 1, 2, 3, 4};
int length = sizeof(ia) / sizeof(ia[0]);
for (size_t i=0; i != array_size ; ++i)
    ia[i] = i;
```
#### 陣列與指標
陣列名稱本身就儲存了陣列記憶體的首個位置的位址，陣列的索引值表示陣列元素是相對於第一個位址的位移量（offset）。位移的量與資料型態長度有關，如果是 int 整數，每次位移時是一個 int 整數的長度，例如在上例中 ia[0] 索引值為 0 時，表示位移量為 0，自然就是指第一個元素，而 ia[3] 就是指相對於首個元素的位移量為 3。
```
int ia[] = {0,2,4,6,8};
int *ip = ia; // ip points to ia[0]
int *ip2 = ip+4; // ip2 points to ia[4]
++ip; // ip points to arr[1]
```

#### loop over an array
1. use for range method
```
int ia[5] = {0, 1, 2, 3, 4};

for(auto i : ia)
    cout << i << " ";
cout << endl;
```
2. use index to access elenments
```
const size_t array_size = 10;
int ia[array_size];
cout << "The contents are: ";
for (size_t ix = 0; ix < array_size; ++ix) {
    ia[ix] = ix;
    cout << ia[ix] << ' ';
}
cout << endl;
```
3. use Iterators
```
const size_t array_size = 10;
int ia[array_size];
int *pbeg = begin(ia), *pend = end(ia);
size_t cnt = 0;
cout << "The contents are: ";

// Using begin and end, it is rather easy to write a loop to process the elements in an array.
while (pbeg != pend){
    *pbeg = cnt++;
    cout << *pbeg++ << ' ';
}
cout << endl;
```