トラック
/
C++
C++
/
演習
/
成績をつける
成績をつける

成績をつける

学習演習

はじめに

配列とベクター

C++には、同じ型の要素を順序を保って格納するための、さまざまなコンテナーが用意されています。 サイズが固定されたコンテナーにはstd::arrayがあり、動的にサイズを変更できるstd::vectorもあります。

初期化

配列やベクターを宣言するときは、そのコンテナーが保持する要素の型を指定する必要があります。 配列の場合は、サイズも指定します。 次の例で、2つのコンテナーの初期化のしかたを見てみましょう。

#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に変換する必要があります。

student_scoresのvectorを仮引数として受け取る関数round_down_scores()を作成しましょう。 学校が求めている丸め方は、切り捨てです。 幸いなことに、C++ではstatic_castを使ってある型を別の型にキャストできます。 doubleからintへのstatic_cast変換では、小数点以下の桁が切り捨てられます。 この関数は、入力のvectorを受け取り、すべての点数をintに変換した新しいvectorをreturnするようにします。

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. 合格点に届かない学生

試験を採点していると、思っていたほど成績が振るわない学生がいることに気づきました。 しかし、気を取られて、_何人_いたのかを正確に記録するのを忘れてしまいました。

student_scoresのvectorを仮引数として受け取る関数count_failed_students()を作成しましょう。 この関数は、合格点に届いていない学生の数を数え、その数を整数として返すようにします。 試験で合格するには、40より大きい点数が必要です。

count_failed_students({90,40,55,70,30,25,80,95,38,40});
// => 5

3. 評定を計算する

お手伝いしている先生は、数値の点数だけでなく評定も付けたがります。 学生が試験で100点を取ることはめったにないので、「評定」の下限のしきい値は、達成された最高点をもとに計算し、その最高点と不合格のしきい値である**<= 40**の間で均等に刻みます。

試験の「最高点」を仮引数として受け取り、アメリカ式の各評定区間に対応する下限のしきい値のarray(vectorではありません)を返す関数letter_grades()を作成しましょう:["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_scoresとstudent_namesを受け取る関数student_ranking()を作成しましょう。 student_namesのvectorにある各学生の名前を、student_scoresのvectorにある点数と対応させます。 それぞれの引数のvectorは、点数の高い順に並んでいるものとします。 この関数は、<rank>. <student name>: <student score>という形式の文字列のvectorを返すようにします。

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点という「完璧な」点数を取ることはめったにありませんが、少なくとも1人の学生が達成したかどうかは気になるところです。

仮引数student_scoresとstudent_namesを受け取る関数perfect_score()を作成しましょう。 リストはタスク4と同じです。 この関数は、試験で100点を取った学生の_最初の_<name>を(文字列として)returnするようにします。

100点の学生が見つからなければ、空文字列""を返します。

perfect_score({"Nur", "Tony", "Fatima"}, {90, 80, 100});
// => "Fatima"

perfect_score({"Nur", "Tony"}, {90, 80});
// => ""
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
C++ Exercism

成績をつけるを始める準備はできましたか?

Exercismに登録すれば、19個のコンセプト100個の演習、そして本物の人間によるメンタリングとともに、C++を学んでマスターできます。すべて無料です。