轨道
/
C++
C++
/
练习
/
成绩评定
成绩评定

成绩评定

学习练习

简介

数组和向量

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组成的vector。 学校要求的取整方式是截断。 幸运的是,C++ 可以用static_cast把一个类型转换成另一个类型。 从double到int的static_cast转换会截去小数点后的所有数字。 这个函数应接收输入的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.

2. 不及格的学生

批改考试时,你注意到有些学生表现得没有你期望的那么好。 但你当时分了心,忘了记下到底有多少名学生。

创建函数 count_failed_students(),它接收一个由student_scores组成的vector。 这个函数应数出没有达到及格分数的学生人数,并以整数返回该人数。 学生在考试中需要拿到大于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。 把 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"}

5. “完美”分数

虽然考试中拿到“完美”的 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});
// => ""
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
C++ Exercism

准备好开始 成绩评定 了吗?

注册 Exercism,借助 19 个概念100 个练习 和真人导师指导,学习并掌握 C++,全部免费。