「演習:関数」
これまでに、関数の基礎、引数、再帰、オーバーロード、スコープについて学びました。次は、実際にプログラムを作成して、これらすべてを統合してみましょう。このレッスンでは、プログラミングを学ぶ上で最も重要な要素である実践に焦点を当てます。
1. プロジェクト 1:簡単な数学ライブラリ
どこからでも呼び出せる関数を備えた、再利用可能な数学ライブラリを作成してください。
CPP
#include iostream
#include cmath // For sqrt, pow, etc.
// Math utility functions
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
double divide(int a, int b) {
if (b == 0) {
std::cerr << "Error: division by zero!" << std::endl;
return 0;
}
return static_castdouble(a) / b;
}
long long factorial(int n) {
if (n < 0) return -1;
if (n == 0) return 1;
return n * factorial(n - 1);
}
bool isPrime(int n) {
if (n <= 1) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
int main() {
std::cout << "Math Library Demo" << std::endl;
std::cout << "10 + 5 = " << add(10, 5) << std::endl;
std::cout << "10 - 5 = " << subtract(10, 5) << std::endl;
std::cout << "10 * 5 = " << multiply(10, 5) << std::endl;
std::cout << "10 / 5 = " << divide(10, 5) << std::endl;
std::cout << "5! = " << factorial(5) << std::endl;
std::cout << "Is 17 prime? " << (isPrime(17) ? "Yes" : "No") << std::endl;
std::cout << "Is 15 prime? " << (isPrime(15) ? "Yes" : "No") << std::endl;
return 0;
}
💡 ヒント: このような数学ライブラリは、モジュール式設計の好例です。各関数は1つの機能に特化しており、それをしっかりとこなしています。既存の関数を変更することなく、後から機能を追加することも可能です。
2. プロジェクト 2:数字当てゲーム(関数版)
以前の推測ゲームを、関数を使ってより整理された構成になるように書き直してください。
CPP
#include iostream
#include cstdlib
#include ctime
// Function prototypes
int generateSecretNumber(int max);
int getPlayerGuess();
bool checkGuess(int guess, int secret);
int generateSecretNumber(int max) {
std::srand(std::time(0));
return std::rand() % max + 1;
}
int getPlayerGuess() {
int guess;
std::cout << "Your guess: ";
std::cin >> guess;
return guess;
}
bool checkGuess(int guess, int secret) {
if (guess > secret) {
std::cout << "Too high!" << std::endl;
return false;
} else if (guess < secret) {
std::cout << "Too low!" << std::endl;
return false;
} else {
std::cout << "Correct!" << std::endl;
return true;
}
}
int main() {
const int MAX = 100;
int secret = generateSecretNumber(MAX);
int attempts = 0;
bool guessed = false;
std::cout << "I'm thinking of a number between 1 and " << MAX << std::endl;
while (!guessed) {
int guess = getPlayerGuess();
attempts++;
guessed = checkGuess(guess, secret);
}
std::cout << "You got it in " << attempts << " tries!" << std::endl;
return 0;
}
💡 ヒント: 以前のバージョンと比べて、このバージョンは読みやすく、変更もはるかに簡単です。各関数の目的が明確になっています。入力方法を変更したい場合は、
getPlayerGuess() を変更するだけです。フィードバックを変更したい場合は、checkGuess() を変更するだけです。
3. プロジェクト3:オーバーロードされた電卓
関数のオーバーロードを用いて、整数または浮動小数点数のいずれでも処理できる計算機。
CPP
#include iostream
// Integer versions
int calculate(int a, int b, char op) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return (b != 0) ? a / b : 0;
default: return 0;
}
}
// Double versions
double calculate(double a, double b, char op) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return (b != 0) ? a / b : 0;
default: return 0;
}
}
int main() {
// Integer calculation
std::cout << "Integer: 10 + 3 = " << calculate(10, 3, '+') << std::endl;
std::cout << "Integer: 10 / 3 = " << calculate(10, 3, '/') << std::endl;
// Double calculation
std::cout << "Double: 10.0 + 3.0 = " << calculate(10.0, 3.0, '+') << std::endl;
std::cout << "Double: 10.0 / 3.0 = " << calculate(10.0, 3.0, '/') << std::endl;
return 0;
}
4. 実習:学生成績管理システム
複数の関数を用いて学生の成績を管理する完全なプログラム。
CPP
#include iostream
#include string
#include iomanip
const int MAX_STUDENTS = 100;
// Function prototypes
int addStudent(std::string names, int scores, int count);
void displayAll(const std::string names, const int scores, int count);
double calculateAverage(const int scores, int count);
int findHighest(const int scores, int count);
int findLowest(const int scores, int count);
void displayStats(const int scores, int count);
int addStudent(std::string names, int scores, int count) {
if (count >= MAX_STUDENTS) {
std::cout << "Class is full!" << std::endl;
return count;
}
std::cout << "Name: ";
std::cin.ignore();
std::getline(std::cin, names[count]);
std::cout << "Score: ";
std::cin >> scores[count];
return count + 1;
}
void displayAll(const std::string names, const int scores, int count) {
std::cout << "\n--- Student List ---" << std::endl;
for (int i = 0; i < count; i++) {
std::cout << i + 1 << ". " << names[i] << ": " << scores[i] << std::endl;
}
}
double calculateAverage(const int scores, int count) {
if (count == 0) return 0;
int sum = 0;
for (int i = 0; i < count; i++) sum += scores[i];
return static_castdouble(sum) / count;
}
int findHighest(const int scores, int count) {
if (count == 0) return -1;
int maxIdx = 0;
for (int i = 1; i < count; i++) {
if (scores[i] > scores[maxIdx]) maxIdx = i;
}
return maxIdx;
}
int findLowest(const int scores, int count) {
if (count == 0) return -1;
int minIdx = 0;
for (int i = 1; i < count; i++) {
if (scores[i] < scores[minIdx]) minIdx = i;
}
return minIdx;
}
void displayStats(const int scores, int count) {
std::cout << "\n--- Statistics ---" << std::endl;
std::cout << "Total students: " << count << std::endl;
std::cout << "Average score: " << std::fixed << std::setprecision(1)
<< calculateAverage(scores, count) << std::endl;
int highIdx = findHighest(scores, count);
if (highIdx >= 0) {
std::cout << "Highest: " << scores[highIdx];
std::cout << " (student " << highIdx + 1 << ")" << std::endl;
}
int lowIdx = findLowest(scores, count);
if (lowIdx >= 0) {
std::cout << "Lowest: " << scores[lowIdx];
std::cout << " (student " << lowIdx + 1 << ")" << std::endl;
}
}
int main() {
std::string names[MAX_STUDENTS];
int scores[MAX_STUDENTS];
int count = 0;
int choice;
do {
std::cout << "\n=== Student Grade Manager ===" << std::endl;
std::cout << "1. Add student" << std::endl;
std::cout << "2. Display all" << std::endl;
std::cout << "3. Show statistics" << std::endl;
std::cout << "4. Exit" << std::endl;
std::cout << "Choice: ";
std::cin >> choice;
switch (choice) {
case 1:
count = addStudent(names, scores, count);
break;
case 2:
displayAll(names, scores, count);
break;
case 3:
displayStats(scores, count);
break;
}
} while (choice != 4);
std::cout << "Goodbye!" << std::endl;
return 0;
}
▶ サンプル 1: practice functionsデモ (難易度 ⭐)
CPP
#include <iostream>
int main() {
// practice functionsの
std::cout << "practice functionsをびましょう!" << std::endl;
return 0;
}
❓ よくある質問
Q 何を関数にするべきか、どのように判断すればよいですか?
A 以下のいずれかに該当するコードブロックです:① 1つの明確なタスクを実行するもの、② 複数の場所で繰り返し使用されるもの、または③ メイン関数の可読性を高めるもの。優れた関数は、たった1つのことをしっかりとこなすものです。
Q プログラムにはいくつの関数があるべきですか?
A 決まった数はありません。目安としては、関数の行数が30~50行を超える場合は、より小さな関数に分割することを検討しましょう。各関数は1画面に収まる長さであるべきです。
Q 関数のプロトタイプは常に使用すべきですか?
A はい、複数の関数を含むプログラムでは常に使用すべきです。ファイルの先頭に記述されたプロトタイプは目次のような役割を果たし、コードを読む人は誰でも利用可能なすべての関数を一目で把握できます。
📖 まとめ
- 関数を使うことで、プログラムはモジュール化され、再利用可能になり、デバッグしやすくなる
- 各関数は1つのことを行い、それをしっかりとこなすべきである
- コードを整理するために関数のプロトタイプを活用しましょう
- 複雑なプログラムを、目的が明確な小さな関数に分割する
- 「学生成績管理システム」は、さまざまな実用的な用途に合わせて拡張できるテンプレートです
📝 練習問題
-
初心者(難易度 ⭐): 成績管理画面に、生徒の名前で検索してその生徒の得点を表示する
findStudentByName機能を追加してください。 -
中級(難易度 ⭐⭐): 「合格基準」機能を追加する。これは、所定の基準(例:60点)を上回った生徒の人数をカウントする機能である。
-
上級(難易度 ⭐⭐⭐): 成績評価機能の追加:数値のスコアが与えられた場合、'A'(90以上)、'B'(80以上)、'C'(70以上)、'D'(60以上)、または'F'を返す。学生リストでは、数値のスコアと併せて成績評価を表示する。
5. 🚀 次は
関数モジュールを無事に修了しましたね!次はフェーズ3:配列、文字列、構造体(第16課)に進み、データの集合を扱う方法を学びます。



