# 第三章 字串、向量和陣列 練習 註:此章節以後,都改為使用 using 的方式做宣告,而程式碼主體中都將省略 namescope ## 練習 3.1 以適當的 using 宣告改寫 1.4.1 和 2.6.2 的練習 解: ```cpp // 1.4.1 #include <iostream> using std::cin; using std::cout; using std::endl; int main() { int sum = 0, val = 1; while (val <= 10) { sum += val; ++val; } cout << "Sum of 1 to 10 inclusive is " << sum << endl; return 0; } ``` ```cpp // 2.6.2 #include <iostream> #include <string> #include "Sales_data.h" using std::cerr; using std::cin; using std::cout; using std::endl; int main() { Sales_data data1, data2; double price = 0; cin >> data1.bookNo >> data1.units_sold >> price; data1.revenue = data1.units_sold * price; cin >> data2.bookNo >> data2.units_sold >> price; data2.revenue = data2.units_sold * price; if (data1.bookNo == data2.bookNo) { unsigned totalCnt = data1.units_sold + data2.units_sold; double totalRevenue = data1.revenue + data2.revenue; cout << data1.bookNo << " " << totalCnt << " " << totalRevenue << " "; if (totalCnt != 0) cout << totalRevenue / totalCnt << endl; else cout << "(no sales)" << endl; return 0; } else { cerr << "Data must refer to the same ISBN" << endl; return -1; } } ``` ## 練習 3.2 寫一個程式,一次讀取一行的標準輸入。修改你的程式,改成一次讀取一個字詞 解: ```cpp // 一次讀取一行 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::getline; using std::string; int main() { string s; while (getline(cin, s)) cout << s << endl; return 0; } ``` ```cpp // 一次讀取一個詞 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::getline; using std::string; int main() { string s; while (cin >> s) cout << s << endl; return 0; } ``` ## 練習 3.3 解釋空白字元(whitespace characters)在 string 輸入運算子及 getline 函式中是如何被處理的 解: - 以輸入運算子讀取:string 物件會忽略開頭的空白(例如 spaces、newlines、tabs)並且從第一個非空白的自員開始讀取,直到遇見下一個空白為止 - 以 getline 讀取:string 物件會從輸入流讀取字串,直到遇見 newline 為止 ## 練習 3.4 寫一個程式來讀取兩個 string,並回報這些 string 是否相等。如果不是,就回報何者較大。現在,變更此程式來回報這些 string 是否有相同的長度,若非如此,就回報哪個比較長 解: ```cpp // 比較字串大小 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::string; int main() { string str1, str2; while (cin >> str1 >> str2) if (str1 == str2) cout << "The two strings are equal." << endl; else cout << "The larger string is " << ((str1 > str2) ? str1 : str2); return 0; } ``` ```cpp // 比較字串長度 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::string; int main() { string str1, str2; while (cin >> str1 >> str2) if (str1.size() == str2.size()) cout << "The two strings have the same length." << endl; else cout << "The longer string is " << ((str1.size() > str2.size()) ? str1 : str2) << endl; return 0; } // 註:if else 僅為一個 statement,因此 while // 後面可不加上大括號,但通常依然會加入,此範例僅為示範,實際專案請勿使用此較無可讀性的寫法 ``` ## 練習 3.5 寫一個程式從標準輸入讀取 string,並將讀取到的串接起來放到一個大型的 string 中。將串接後的 string 印出。接著,更改程式,以一個空格(space)分隔相鄰的輸入 解: ```cpp // 直接串接字串,不使用空格(space)分隔 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::string; int main() { string result, str; while (cin >> str) result += str; cout << result << endl; return 0; } ``` ```cpp // 串接後須使用空格(space)分隔 #include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::string; int main() { string result, str; while (cin >> str) result += str + " "; cout << result << endl; return 0; } ``` ## 練習 3.6 使用一個範圍 for 來將一個 string 中的所有字元改為 X 解: ```cpp #include <cctype> #include <iostream> #include <string> using std::cout; using std::endl; using std::string; int main() { string str = "this is a string"; for (auto &c : str) c = 'X'; cout << str << endl; return 0; } ``` ## 練習 3.7 如果你將前面練習的迴圈控制變數定義型別 char,會發生什麼事?預測結果,然後修改你的程式,使用一個 char 看看你是否正確 解: 必須要使用 char 參考才能修改到 string 中原本的字串,因此如果單純只是定義為 char,原本的字串將不會被修改 ## 練習 3.8 改寫第一個練習中的程式,先使用 while,接著再使用一個傳統的 for 迴圈,這三種中你比較喜歡哪一個?為什麼? 解: ```cpp // 使用 while #include <iostream> #include <string> using std::cout; using std::endl; using std::string; int main() { string str = "this is a string"; decltype(str.size()) i = 0; while (i != str.size()) { str[i] = 'X'; ++i; } cout << str << endl; return 0; } ``` ```cpp // 使用傳統 for #include <iostream> #include <string> using std::cout; using std::endl; using std::string; int main() { string str = "this is a string"; // 此 for 迴圈非可讀性寫法,僅測試讀者對語法理解度練習使用,請勿在多人協作中使用 for (decltype(str.size()) i = 0; i < str.size(); str[i] = 'Y', ++i) ; cout << str << endl; return 0; } ``` 使用範圍 for 述句(range for stetement)更好,因為不需要操控索引值(index),更簡潔 ## 練習 3.9 下列程式會做什麼事?它是有效的嗎?如果不是,為何呢? ```cpp string str; cout << str[0] << endl; ``` 解: 無效。使用下標運算子(subscript operator)存取空字串是非法的行為 ## 練習 3.10 寫出一個程式,讀取一串字元,包括標點符號,然後寫出所讀到的東西,但移除標點符號 解: ```cpp #include <cctype> #include <iostream> #include <string> using std::cout; using std::endl; using std::string; int main() { string str = "this, is. a :string!"; string result; for (auto c : str) if (!ispunct(c)) result += c; cout << result << endl; return 0; } // 註:if else 僅為一個 statement,因此 for // 後面可不加上大括號,但通常依然會加入,此範例僅為示範,實際專案請勿使用此較無可讀性的寫法 ``` ## 練習 3.11 下面的範圍 for 合法嗎?如果是,c 的型別是什麼呢? ```cpp const string s = "Keep out!"; for (auto &c : s) { /* ... */ } ``` 解: 要根據 for 循環中的 body 來看是否合法,c 是 string 物件中字元的參考,s 是常數,因此如果 body 中的程式碼對 c 指定(assign)就會是非法,但如果不改變,就是合法 ## 練習 3.12 如果有的話,下列哪個 vector 定義是錯誤的?對於合法的那些,請解釋那些定義做些什麼。而不合法的那些,請解釋它們為何不合法 ```cpp (a)vector<vector<int>> ivec; (b)vector<string> svec = ivec; (c)vector<string> svec(10, "null"); ``` - (a):合法 - (b):不合法,一個型別是 vector\<int>,另一個型別是 vector\<string>,不一樣 - (c):合法 ## 練習 3.13 下列每個 vector 中各有多少元素?那些元素的值又是什麼? ```cpp (a)vector<int> v1; // size:0, no values. (b)vector<int> v2(10); // size:10, value:0 (c)vector<int> v3(10, 42); // size:10, value:42 (d)vector<int> v4{10}; // size:1, value:10 (e)vector<int> v5{10, 42}; // size:2, value:10, 42 (f)vector<string> v6{10}; // size:10, value:"" (g)vector<string> v7{10, "hi"}; // size:10, value:"hi" ``` - (a):size 為 0,容器內沒有任何元素,因此沒有 value - (b):size 為 10,value 為 0 - (c):size 為 10,value 為 42 - (d):size 為 1,value 為 10 - (e):size 為 2,value 為 10, 42 - (f):size 為 10,value 為 "" - (g):size 為 10,value 為 "hi" ## 練習 3.14 寫一個程式從 cin 讀取一序列的 int,並將那些值儲存在一個 vector 中 解: ```cpp #include <iostream> #include <vector> using std::cin; using std::vector; int main() { vector<int> vec; int i; while (cin >> i) vec.push_back(i); return 0; } ``` ## 練習 3.15 重複前一個程式,但這次改讀取 string 解: ```cpp #include <iostream> #include <string> #include <vector> using std::cin; using std::string; using std::vector; int main() { vector<string> vec; string str; while (cin >> str) v.push_back(str); return 0; } ``` ## 練習 3.16 寫出一個程式印出練習 3.13 中那些 vector 的大小與內容。檢查你對於那個練習的解答是否正確。若非如此,重新研讀 3.3.1 直到你了解為何出錯為止 解: ```cpp #include <iostream> #include <iterator> #include <string> #include <vector> using std::cout; using std::endl; using std::string; using std::vector; void check_and_print(const vector<int>& vec) { cout << "size: " << vec.size() << " content: ["; for (auto i : vec) cout << i << ", "; cout << "]\n" << endl; } void check_and_print(const vector<string>& vec) { cout << "size: " << vec.size() << " content: ["; for (auto i : vec) cout << i << ", "; cout << "]\n" << endl; } int main() { vector<int> v1; vector<int> v2(10); vector<int> v3(10, 42); vector<int> v4{10}; vector<int> v5{10, 42}; vector<string> v6{10}; vector<string> v7{10, "hi"}; check_and_print(v1); check_and_print(v2); check_and_print(v3); check_and_print(v4); check_and_print(v5); check_and_print(v6); check_and_print(v7); return 0; } ``` 輸出: ``` size: 0 content: [] size: 10 content: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] size: 10 content: [42, 42, 42, 42, 42, 42, 42, 42, 42, 42, ] size: 1 content: [10, ] size: 2 content: [10, 42, ] size: 10 content: [, , , , , , , , , , ] size: 10 content: [hi, hi, hi, hi, hi, hi, hi, hi, hi, hi, ] ``` ## 練習 3.17 從 cin 讀取一序列的字詞,並將那些值儲存為一個 vector。在你讀完了所有的字詞之後,就處理那個 vector 並將每個字詞變為大寫。印出變換後的元素,一行八個字 解: ```cpp #include <iostream> #include <string> #include <vector> using std::cin; using std::cout; using std::endl; using std::string; using std::vector; int main() { vector<string> vec; string str; while (cin >> str) v.push_back(str); for (auto &str : vec) for (auto &c : str) c = toupper(c); for (auto s : vec) cout << s << endl; return 0; } // 註:此為非可讀性寫法 ``` ## 練習 3.18 下列的程式合法嗎?若非,你會如何修正之? ```cpp vector<int> ivec; ivec[0] = 42; ``` 解: 不合法,應改為: ```cpp ivec.push_back(42); ``` ## 練習 3.19 列出定義一個 vector 的三種方法,並賦予它們十個元素,每個都有值 42。指出要這麼做是否有偏好的方式以及原因 ```cpp vector<int> ivec1(10, 42); vector<int> ivec2{42, 42, 42, 42, 42, 42, 42, 42, 42, 42}; vector<int> ivec3; for (int i = 0; i < 10; ++i) ivec3.push_back(42); ``` 第一種方式最好、最簡潔 ## 練習 3.20 將一組整數讀到一個 vector 中。印出每個對相鄰元素的和。更改你的程式,改印出第一與最後一個元素的和,後面接著第二個和倒數第二個元素的和 解: ```cpp // 印出每個相鄰元素的和 #include <iostream> #include <vector> using std::cin; using std::cout; using std::endl; using std::vector; int main() { vector<int> ivec; int i; while (cin >> i) ivec.push_back(i); for (int i = 0; i < ivec.size() - 1; ++i) cout << ivec[i] + ivec[i + 1] << " "; return 0; } ``` ```cpp // 印出前後相對元素的和 #include <iostream> #include <vector> using std::cin; using std::cout; using std::endl; using std::vector; int main() { vector<int> ivec; int i; while (cin >> i) ivec.push_back(i); for (int m = 0, n = ivec.size() - 1; m <= n; cout << ivec[m] + ivec[n] << endl, ++m, --n) ; return 0; } // 非可讀性寫法 ``` ## 練習 3.21 使用迭代器重新做一遍 3.3.3 的第一個練習 解: ```cpp #include <iostream> #include <iterator> #include <string> #include <vector> using std::cout; using std::endl; using std::string; using std::vector; void check_and_print(const vector<int>& vec) { cout << "size: " << vec.size() << " content: ["; for (auto it = vec.begin(); it != vec.end(); ++it) cout << *it << (it != vec.end() - 1 ? ", " : ""); cout << "]\n" << endl; } void check_and_print(const vector<string>& vec) { cout << "size: " << vec.size() << " content: ["; for (auto it = vec.begin(); it != vec.end(); ++it) cout << *it << (it != vec.end() - 1 ? ", " : ""); cout << "]\n" << endl; } int main() { vector<int> v1; vector<int> v2(10); vector<int> v3(10, 42); vector<int> v4{10}; vector<int> v5{10, 42}; vector<string> v6{10}; vector<string> v7{10, "hi"}; check_and_print(v1); check_and_print(v2); check_and_print(v3); check_and_print(v4); check_and_print(v5); check_and_print(v6); check_and_print(v7); return 0; } ``` ## 練習 3.22 修改會印出 text 第一個段落的迴圈,改為將 text 中對應到第一個段落的元素全都變為大寫。更新 text 之後,印出其內容 解: ```cpp #include <iostream> #include <string> #include <vector> using std::cin; using std::cout; using std::endl; using std::string; using std::vector; int main() { vector<string> text; for (string line; getline(cin, line);) text.push_back(line); for (auto it = text.begin(); it != text.end() && !it->empty(); ++it) { for (auto& c : *it) c = toupper(c); cout << *it << endl; } return 0; } ``` ## 練習 3.23 寫一個程式來建立帶有十個 int 元素的一個 vector。使用一個迭代器將每個元素的指定為目前值的兩倍。印出這個 vector 來測試你的程式 解: ```cpp #include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; int main() { vector<int> v(10, 1); for (auto it = v.begin(); it != v.end(); it++) *it *= 2; for (auto one : v) cout << one << endl; return 0; } ``` ## 練習 3.24 使用迭代器重做 3.3.3 的最後一個練習 解: ```cpp // 印出每個相鄰元素的和 #include <iostream> #include <vector> using std::cin; using std::cout; using std::endl; using std::vector; int main() { vector<int> ivec; int i; while (cin >> i) ivec.push_back(i); for (auto it = ivec.begin(); it != ivec.end() - 1; ++it) cout << *it + *(it + 1) << " "; return 0; } ``` ```cpp // 印出前後相對元素的和 #include <iostream> #include <vector> using std::cin; using std::cout; using std::endl; using std::vector; int main() { vector<int> ivec; int i; while (cin >> i) ivec.push_back(i); for (auto it1 = ivec.begin(), it2 = ivec.end() - 1; it1 <= it2; cout << *(it1++) + *(it2--) << " ") ; return 0; } // 非可讀性寫法 ``` ## 練習 3.25 使用迭代器來取代下標,改寫 3.3.3 的成績叢集程式 解: ```cpp #include <iostream> #include <vector> using std::cin; using std::cout; using std::endl; using std::vector; int main() { vector<int> scores(11, 0); int grade; while (cin >> grade) ++*(scores.begin() + grade / 10); for (auto result : scores) cout << result << " "; cout << endl; } ``` ## 練習 3.26 在前面的二元搜尋中,為什麼我們寫的是 mid = beg + (end - beg) / 2;,而非 mid = (beg + end) / 2;? 解: 兩個迭代器(iterator)相互之間支持的運算只有減號,而沒有加號,但是迭代器和迭代器之間的差值(difference_type)為整數型別,支持加號的運算 ## 練習 3.27 假設 txt_size 是一個函式,它不接受引數(arguments),並回傳一個 int 值,下列哪些定義是非法的?解釋原因 ```cpp unsigned buf_size = 1024; (a)int ia[buf_size]; (b)int ia[4 * 7 - 14]; (c)int ia[txt_size()]; (d)char st[11] = "fundamental"; ``` 解: - (a)非法,陣列的大小(dimensioin)必須是一個 constant expression - (b)合法 - (c)非法,txt_size() 的值必須要到執行時期才能得到 - (d)非法,陣列的大小應為 12,後面應含有一個 /0 字元結尾 ## 練習 3.28 下列陣列中的值是什麼? ```cpp string sa[10]; int ia[10]; int main() { string sa2[10]; int ia2[10]; } ``` 解: 陣列中的所有元素都會被默認初始化(default initialize) sa 的元素全部為空字串,ia 的元素全部為 0 sa2 的元素值全部為空字串,ia2 的元素值全部為未定義 ## 練習 3.29 列出使用陣列而非 vector 的一些缺點 解: - 陣列的大小必須是確定的 - 不能隨意增加元素 - 不允許拷貝和指定 ## 練習 3.30 辨識出下列程式碼中的索引錯誤: ```cpp constexpr size_t array_size = 10; int ia[array_size]; for (size_t ix = 1; ix <= array_size; ++ix) ia[ix] = ix; ``` 解: 當 ix 達到 10 的時候,會發生越界,產生未定義行為(undefined behavior) ## 練習 3.31 寫一個程式來定義由十個 int 所構成的陣列。賦予每個元素與其在陣列中所在位置的相同值 ```cpp #include <iostream> using std::cout; using std::endl; int main() { int arr[10]; for (auto i = 0; i < 10; ++i) arr[i] = i; for (auto i : arr) cout << i << " "; cout << endl; return 0; } ``` ## 練習 3.32 將你前面定義的陣列拷貝到另一個陣列。使用 vector 改寫你的程式 ```cpp // copy array #include <iostream> using std::cout; using std::endl; int main() { int arr[10]; for (auto i = 0; i < 10; ++i) arr[i] = i; int arr2[10]; for (auto i = 0; i < 10; ++i) arr2[i] = arr[i]; for (auto i : arr) cout << i << " "; cout << endl; return 0; } ``` ```cpp // copy vector #include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; int main() { vector<int> v(10); for (auto i = 0; i != 10; ++i) v[i] = i; vector<int> v2(v); for (auto i : v2) cout << i << " "; cout << endl; return 0; } ``` ## 練習 3.33 如果我們沒有初始化前面程式中的 scores 陣列,會發生什麼事? 解: 陣列中所有元素的值將會是未定義的值 ## 練習 3.34 如果 p1 和 p2 指向同一個陣列中的元素,下列的程式碼會做什麼呢?有 p1 或 p2 的值會讓這段程式碼變得不合法嗎? ```cpp p1 += p2 - p1; ``` 解: 意思是將 p1 移動到 p2 的位置,且任何情況下的合法 ## 練習 3.35 使用指標寫一個程式來將一個陣列中的元素設為 0 解: ```cpp #include <iostream> using std::cout; using std::endl; int main() { const int size = 10; int arr[size]; for (auto ptr = arr; ptr != arr + size; ++ptr) *ptr = 0; for (auto i : arr) cout << i << " "; cout << endl; return 0; } ``` ## 練習 3.36 寫一個程式來比較兩個陣列的相等性。寫一個類似的程式來比較兩個 vector 解: ```cpp #include <iostream> #include <vector> #include <iterator> using std::begin; using std::end; using std::cout; using std::endl; using std::vector; // pb point to begin of the array, pe point to end of the array. bool compare(int* const pb1, int* const pe1, int* const pb2, int* const pe2) { if ((pe1 - pb1) != (pe2 - pb2)) // have different size. return false; else { for (int* i = pb1, *j = pb2; (i != pe1) && (j != pe2); ++i, ++j) if (*i != *j) return false; } return true; } int main() { int arr1[3] = { 0, 1, 2 }; int arr2[3] = { 0, 2, 4 }; if (compare(begin(arr1), end(arr1), begin(arr2), end(arr2))) cout << "The two arrays are equal." << endl; else cout << "The two arrays are not equal." << endl; cout << "==========" << endl; vector<int> vec1 = { 0, 1, 2 }; vector<int> vec2 = { 0, 1, 2 }; if (vec1 == vec2) cout << "The two vectors are equal." << endl; else cout << "The two vectors are not equal." << endl; return 0; } ``` ```cpp // compare vector #include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; int main() { vector<int> vec1 = {0, 1, 2}; vector<int> vec2 = {0, 1, 2}; if (vec1 == vec2) cout << "The two vectors are equal." << endl; else cout << "The two vectors are not equal." << endl; return 0; } ``` ## 練習 3.37 下列程式會做什麼事呢? ```cpp const char ca[] = { 'h', 'e', 'l', 'l', 'o' }; const char *cp = ca; while (*cp) cout << *(cp++) << endl; ``` 解: 會將 ca 字元陣列中的字元都印出來,但是因為沒有空字元作為結尾(null terminated),因此後面可能還會印出其它未定義的字元 ## 練習 3.38 在本節中,我們注意到試著將兩個指標相加不只是非法的,也沒有意義。為何將兩個指標相加是沒有意義的呢? 解: 將兩個指標相減可以表是兩個指標(在同一個陣列中)相距的距離,將指標加上一個整數也可以表示移動這個指標到某一位置。但是兩個指標ㄒ央加並沒有邏輯上的意義,因此兩個指標不能相加 ## 練習 3.39 撰寫一段程式來比較兩個 string。現在撰寫一個程式來比較兩個 C-style 字元字串的值 解: ```cpp // compare two strings by std::string #include <iostream> #include <string> using std::cout; using std::endl; using std::string; int main() { string str1("Mooophy"), str2("Pezy"); if (str1 == str2) cout << "same string." << endl; else if (str1 > str2) cout << str1 << " > " << str2 << endl; else cout << str1 << " < " << str2 << endl; return 0; } ``` ```cpp // compare two strings by cstring(strcmp) #include <cstring> #include <iostream> using std::cout; using std::endl; int main() { const char* cstr1 = "Wangyue"; const char* cstr2 = "Pezy"; auto result = strcmp(cstr1, cstr2); if (result == 0) cout << "same string." << endl; else if (result < 0) cout << cstr1 << " < " << cstr2 << endl; else cout << cstr1 << " > " << cstr2 << endl; return 0; } ``` ## 練習 3.40 寫一個程式來定義從字串字面值初始化的兩個字元陣列,現在定義第三個陣列來存放那兩個陣列串接的結果。使用 strcpy 和 strcat 來將那兩個陣列拷貝到第三個中 解: ```cpp #include <cstring> #include <iostream> using std::cout; using std::endl; int main() { const char cstr1[] = "Hello,"; const char cstr2[] = "world!"; // cstring 中的 strlen 並非 constexpr 函數,放在 stack // 中可能會出錯,因此必須放在 heap 中 const size_t new_size = strlen(cstr1) + strlen(cstr2) + 1; char *cstr3 = new char[new_size]; strcpy(cstr3, cstr1); strcat(cstr3, cstr2); cout << cstr3 << endl; return 0; } ``` ## 練習 3.41 寫出一個程式從一個 int 陣列初始化一個 vector ```cpp #include <iostream> #include <vector> using std::begin; using std::cout; using std::end; using std::endl; using std::vector; int main() { int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; vector<int> vec(begin(arr), end(arr)); for (auto n : vec) cout << n << " "; cout << endl; return 0; } ``` ## 練習 3.42 寫出一個程式來將由 int 所構成的一個 vector 拷貝到一個 int 陣列 解: ```cpp #include <iostream> #include <vector> using std::begin; using std::cout; using std::end; using std::endl; using std::vector; int main() { vector<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int arr[10]; for (int i = 0; i != vec.size(); ++i) arr[i] = vec[i]; for (auto n : arr) cout << n << " "; cout << endl; return 0; } ``` ## 練習 3.43 寫出三種不同版本的程式來印出 ia 的元素。一個版本應該使用範圍 for 來管理迭代動作,另外兩個應該使用一個普通的 for 迴圈,其中一個使用下標,另一個使用指標。在所有的三個程式中,直接寫出所有的型別。也就是說,別使用型別別名、auto,或 decltype 來簡化程式碼 解: ```cpp #include <iostream> using std::cout; using std::endl; int main() { int arr[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}}; // by range for // 不會更改的值要習慣加上 const for (const int(&row)[4] : arr) { for (const int col : row) cout << col << " "; cout << endl; } cout << endl; // by for loop for (size_t i = 0; i != 3; ++i) { for (size_t j = 0; j != 4; ++j) cout << arr[i][j] << " "; cout << endl; } cout << endl; // by pointers // 不會更改的值要習慣加上 const for (const int(*row)[4] = arr; row != arr + 3; ++row) { for (const int *col = *row; col != *row + 4; ++col) cout << *col << " "; cout << endl; } return 0; } ``` ## 練習 3.44 改寫前面的練習,使用一個型別別名(type alias)作為迴圈控制變數的型別 解: ```cpp #include <iostream> using std::cout; using std::endl; int main() { int ia[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}}; // by range for // type alias using int_array = int[4]; // 不會更改的值要習慣加上 const for (const int(&row)[4] : ia) { for (const int col : row) cout << col << " "; cout << endl; } cout << endl; // by for loop // 使用下標運算子不需要使用 type alias for (size_t i = 0; i != 3; ++i) { for (size_t j = 0; j != 4; ++j) cout << ia[i][j] << " "; cout << endl; } cout << endl; // by pointers // 不會更改的值要習慣加上 const for (const int_array *row = ia; row != ia + 3; ++row) { for (const int *col = *row; col != *row + 4; ++col) cout << *col << " "; cout << endl; } return 0; } ``` ## 練習 3.45 再次改寫程式,這次使用 auto 解: ```cpp #include <iostream> using std::cout; using std::endl; int main() { int ia[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}}; // by range for // 自動推斷成 const int(&row)[4] for (const auto &row : ia) { // 不會更改的值要習慣加上 const for (const auto col : row) cout << col << " "; cout << endl; } cout << endl; // by for loop for (size_t i = 0; i != 3; ++i) { for (size_t j = 0; j != 4; ++j) cout << ia[i][j] << " "; cout << endl; } cout << endl; // by pointers // 自動推斷成 int(*row)[4] for (auto row = ia; row != ia + 3; ++row) { for (const int *col = *row; col != *row + 4; ++col) cout << *col << " "; cout << endl; } return 0; } ```