简介
数组与动态数组
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 获取元素数量。
任务说明
你是一名助教,负责批改学生试卷。手动记录成绩既繁琐又容易出错,于是决定编写一些函数,统计和计算全班成绩,让这项工作更有趣。
1. 成绩取整
单道题可以给部分分,但考试总成绩必须是 int。因此,在进行其他统计前,需要遍历成绩,把 double 成绩转换为 int。
创建 round_down_scores() 函数,接收 student_scores 动态数组。学校要求直接截去小数部分。C++ 可以用 static_cast 转换类型,double 转为 int 时会去掉小数点后的数字。函数应返回一个新的动态数组,其中所有成绩都已转换为 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.
2. 统计不及格人数
批改时,你注意到一些学生的表现不如预期,但当时分了神,忘了记录具体有多少人。
创建 count_failed_students() 函数,接收 student_scores 动态数组,统计未达到及格要求的学生人数,并以整数返回。考试成绩必须大于 40 分才算及格。
count_failed_students({90,40,55,70,30,25,80,95,38,40});
// => 5
3. 计算字母等级
你协助的教师喜欢同时给出数字成绩和字母等级。由于学生很少得到 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}
4. 将姓名与成绩对应
现有按成绩降序排列的分数,以及按相同顺序排列的学生姓名。你希望将姓名与分数对应,输出全班排名。
创建 student_ranking() 函数,接收 student_scores 和 student_names。将姓名动态数组中的每个学生与分数动态数组中的对应成绩匹配。可以假设两个数组都已按成绩从高到低排列。返回字符串动态数组,每项格式为 <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"}
5. 查找满分学生
尽管考试中很少有人得到 100 分,知道是否至少有一人满分仍然很有意义。
创建 perfect_score() 函数,接收 student_scores 和 student_names,使用与任务 4 相同的数组。返回第一个得到 100 分的学生姓名,类型为字符串。
如果没有满分,返回空字符串 ""。
perfect_score({"Nur", "Tony", "Fatima"}, {90, 80, 100});
// => "Fatima"
perfect_score({"Nur", "Tony"}, {90, 80});
// => ""