C++ 提供了不同的容器,讓你能以有序的方式儲存相同型別的元素。
std::array 用於固定大小的容器,而 std::vector 則具備動態調整大小的能力。
當你宣告陣列或向量時,必須指定容器要存放的元素型別。 陣列還需要指定大小。 看看以下範例,了解這兩種容器型別的初始化方式:
#include <array>
#include <string>
// std::array<element_type, size> variable_name {list of elements}
std::array<std::string, 3> indie_rock {"yeah", "yeah", "yeah"};
// indie_rock contains the elements "yeah" three times
向量通常需要更多空間,因為它們會配置記憶體以備後續成長。 你不需要指定大小:
#include <vector>
// std::vector<element_type> variable_name {list of elements}
std::vector<int> countdown {3, 2, 1};
// countdown contains the elements 3, 2 and 1
注意:你還不需要了解模板概念背後的確切機制,它在課程大綱樹的後段會有專屬的概念。
向量與陣列存取元素的函式相同。
你可以使用成員函式front和back取得容器的第一個與最後一個元素。
另外還有at以及[]運算子,可以存取特定的元素。
countdown[0];
// => 3
countdown.at(2);
// => 1
countdown[1] = 4;
// countdown now contains 3, 4 and 1
indie_rock.back() = "yeahs";
// indie_rock is now "yeah", "yeah", "yeahs"
注意:如果你選擇的位置不在容器的範圍內,
[]可能導致未定義行為。at函式則會拋出例外,長期來看這或許能讓你的生活輕鬆一些。
由於vector的大小並非固定,因此可以新增或移除元素。
為此,兩個常用的函式是emplace_back和pop_back。
std::vector<std::string> witches {"Holly", "Alyssa", "Shannen"};
witches.pop_back();
// Shannen is no longer with the witches
witches.emplace_back("Rose");
// Rose has joined the team
你可以用成員函式empty檢查容器是否為空。
如果你想知道元素的數量,可以使用size。
你是負責批改學生考卷的教學助理。 手動追蹤成績不只變得枯燥乏味,還很容易出錯。 你決定讓事情變得更有趣一點,動手寫幾個函式來統計並計算全班的成績。
考試題目可以給「部分分數」,但整體的考試成績必須是int。
所以在對全班成績做任何其他處理之前,你得先逐一檢查分數,並把所有double分數轉成int。
建立函式round_down_scores(),它接收一個student_scores的vector。
學校要求的捨入方式是無條件捨去。
幸好 C++ 可以用static_cast把一種型別轉換成另一種。
用static_cast把double轉成int時,會直接截掉小數點後的所有位數。
這個函式應該接收輸入的vector,並return一個新的 vector,其中所有分數都已轉成int。
std::vector<double> student_scores {90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3};
round_down_scores(student_scores)
// => {90, 40, 55, 70, 30, 25, 80, 95, 38, 40}
還有其他方法能達到同樣的結果,但_型別轉換_是常見的做法。
int new_PI{static_cast<int>(3.14) + static_cast<int>(0.001592653589)};
// new_PI is 3.
批改考卷時,你注意到有些學生的表現不如預期。 但你當時分了心,忘記記下到底有_多少_學生。
建立函式count_failed_students(),它接收一個student_scores的vector。
這個函式應該數出沒有拿到及格分數的學生人數,並以整數回傳這個數量。
學生需要拿到高於40的分數,才能在考試中及格。
count_failed_students({90,40,55,70,30,25,80,95,38,40});
// => 5
你協助的這位老師除了分數之外,也喜歡給等第。 由於學生很少在考試中拿到 100 分,「等第」的下限會依實際拿到的最高分來計算,並在最高分和不及格門檻**<= 40**之間平均遞增。
建立函式letter_grades(),它把考試的「最高」分數當作參數,並回傳一個array(不是 vector),內容是每個「美式」等第區間的分數下限:["D", "C", "B", "A"]。
/*Where the highest score is 100, and failing is <= 40.
"F" <= 40
41 <= "D" <= 55
56 <= "C" <= 70
71 <= "B" <= 85
86 <= "A" <= 100
*/
letter_grades(100);
// => {41, 56, 71, 86}
/*Where the highest score is 88, and failing is <= 40.
"F" <= 40
41 <= "D" <= 52
53 <= "C" <= 64
65 <= "B" <= 76
77 <= "A" <= 88
*/
letter_grades(88);
// => {41, 53, 65, 77}
你手上有依降冪排序的考試分數,以及對應的學生姓名(依考試分數排序)。 你想把每位學生的姓名和考試分數配對,並印出全班總排名。
建立函式student_ranking(),參數為student_scores和student_names。
把 student_names vector 中的每個學生姓名,與 student_scores vector 中對應的分數配對起來。
你可以假設每個引數vector都依分數從高到低排序。
這個函式應該回傳一個vector,裡面是格式為<rank>. <student name>: <student score>的字串。
std::vector<int> student_scores {100, 99, 90, 84, 66, 53, 47};
std::vector<std::string> student_names {"Joci", "Sara","Kora","Jan","Indra","Bern", "Fred"};
student_ranking(student_scores, student_names)
// =>
// {"1. Joci: 100", "2. Sara: 99", "3. Kora: 90", "4. Jan: 84", "5. Indra: 66", "6. Bern: 53", "7. Fred: 47"}
雖然考試要拿到 100 分的「完美」成績很罕見,但知道是否至少有一位學生達成,還是挺有意思的。
建立函式perfect_score(),參數為student_scores和student_names。
這些清單和任務 4 中的相同。
這個函式應該return考試拿到 100 分的那位學生的_第一個_<name>(以字串表示)。
如果找不到任何 100 分,應該回傳空字串""。
perfect_score({"Nur", "Tony", "Fatima"}, {90, 80, 100});
// => "Fatima"
perfect_score({"Nur", "Tony"}, {90, 80});
// => ""