<C++>引数と戻り値
今回の記事でわかること
- 関数に値を渡す「引数」の使い方が分かる
- 関数から値を返す「戻り値」の使い方が分かる
- 引数と戻り値を組み合わせて便利な関数が作れる
引数と戻り値とは
- 引数 関数に「値を渡す」ためのもの。呼び出し時に必要な情報を持たせる
- 戻り値 関数が「処理した結果を返す」ためのもの。関数呼び出しの後で受け取って利用できる
簡単に言うと「入力(引数)」と「出力(戻り値)」みたいなイメージ
基本のおさらい
関数は「入力(引数)を受け取る → 処理 → 結果(戻り値)を返す」箱みたいなものです
C++ の基本構文はこんな感じ
戻り値の型 関数名(引数リスト) {
// 処理
return 戻り値; // 戻り値がある場合
}
戻り値がないときは void を使います。引数がないときは空の括弧 () を書きます
関数を用いた実例
引数あり・戻り値なし
例:名前を受け取って挨拶を表示する関数
#include <iostream>
#include <string>
using namespace std;
void greet(string name) {
cout << "こんにちは、" << name << "さん!" << endl;
}
int main() {
greet("○○");
greet("××");
return 0;
}
/* 出力結果
こんにちは、○○さん!
こんにちは、××さん!
*/
- greet は値を受け取って表示するだけ(返り値なし)
- 注意:string を値渡しすると中身がコピーされるから大きなデータだとコストがかかる(後で参照渡しで最適化する方法を説明します)
引数なし・戻り値あり
例:乱数や定数を返す関数
#include <iostream>
using namespace std;
int getAnswer() {
return 42;
}
int main() {
int x = getAnswer();
cout << "答えは " << x << " です" << endl;
return 0;
}
/* 出力結果
答えは 42 です
*/
引数が不要でも、関数で処理を隠して結果だけ受け取れるのが便利
引数あり・戻り値あり(もっとも一般的)
例:2つの値を受け取って合計を返す
#include <iostream>
using namespace std;
int add(int a, int b) {
return a + b;
}
int main() {
cout << "5 + 7 = " << add(5, 7) << endl;
return 0;
}
/* 出力結果
5 + 7 = 12
*/
呼び出し側は戻り値を変数で受け取ったり、そのまま式の中で使えます
複数の引数
例:3教科の平均値を返す関数
#include <iostream>
using namespace std;
double average(int a, int b, int c) {
return (a + b + c) / 3.0;
}
int main() {
cout << "平均点: " << average(70, 85, 90) << endl;
return 0;
}
/* 出力結果
平均点: 81.6667
*/
引数はカンマで区切って複数渡せる。順番と型に注意
関数の応用
早期 return
無駄なネストを減らすテクニック。条件チェックして早く抜けると読みやすくなります
#include <iostream>
using namespace std;
int safeDivide(int a, int b) {
if (b == 0) return 0; // エラー時は 0 を返す(簡易的)
return a / b;
}
int main() {
cout << safeDivide(10, 2) << endl;
cout << safeDivide(10, 0) << endl; // 0 を返す
return 0;
}
/* 出力結果
5
0
*/
注意:実務ではエラーを sentinel 値で返すか、例外を投げるか、std::optional を使うか設計を考える必要があります
引数の数が可変
可変長引数は C++ できるけど、初心者向けには std::vector や initializer_list を使う方法が分かりやすいです
#include <iostream>
#include <vector>
using namespace std;
double avgVec(const vector<int>& v) {
if (v.empty()) return 0.0;
int sum = 0;
for (int x : v) sum += x;
return (double)sum / v.size();
}
int main() {
vector<int> v = {1,2,3,4};
cout << avgVec(v) << endl;
return 0;
}
/* 出力結果
2.5
*/
※ count や参照(&)は中級の話だけど、ここでは「可変長のデータを渡すなら vector を使う」で覚えておけばOK
複数の戻り値を返す方法
関数は基本1つの値を返しますが、std::pair / std::tuple / 構造体を使えば複数値を返せます。
例:配列の最小値と最大値を返す
#include <iostream>
#include <vector>
#include <utility> // pair
using namespace std;
pair<int,int> minMax(const vector<int>& v) {
if (v.empty()) return {0,0};
int mn = v[0], mx = v[0];
for (int x : v) {
if (x < mn) mn = x;
if (x > mx) mx = x;
}
return {mn, mx};
}
int main() {
vector<int> a = {4,9,1,7};
auto res = minMax(a);
cout << "min=" << res.first << ", max=" << res.second << endl;
return 0;
}
/* 出力結果
min=1, max=9
*/
pair や struct に入れて返すと、戻り値をまとめて返せるので便利
配列を関数に渡すとき
C言語の配列と同じく、組み込み配列は関数に渡す問いにサイズ情報が消えやすいです。必ず長さを一緒に渡すか、std::vector を使うのが安全
include <iostream>
using namespace std;
void printArr(int arr[], int len) {
for (int i = 0; i < len; ++i) cout << arr[i] << " ";
cout << endl;
}
int main() {
int a[] = {1,2,3};
printArr(a, 3);
return 0;
}
/* 出力結果
1 2 3
*/
なぜ関数を使うのか
初心者がよく言う「コード短いし main に全部書けば?」って思うのもわかりますが、関数を使う理由はちゃんとあります!
利点
- 再利用性:同じ処理を何度も呼べる → コピペが減る
- 保守性:処理を一か所直せば全体に反映される
- 可読性:main が短くなって流れが読みやすくなる
- テストしやすさ:小さな関数は単体テストしやすい
- 抽象化:実装の詳細を隠して高レベルの処理に集中できる
わかりやすさの比較
// 間違いやすい:同じ処理を何度もコピペ
cout << "合計: " << (a + b + c) << endl;
cout << "合計: " << (x + y + z) << endl;
// 関数にまとめると分かりやすい
int sum3(int p, int q, int r) { return p + q + r; }
cout << "合計: " << sum3(a,b,c) << endl;
cout << "合計: " << sum3(x,y,z) << endl;
途中で引き算を入れたいとか、関数であれば1か所、コピペであればすべて修正する必要があるため、なるべく分けらる処理は関数で書くことをおすすめします