自動販売機を思い浮かべてください。お金を入れる(渡す)と、ジュースが出てくる(返る)。関数もこれと同じで、入口と出口を持てます。入口が引数、出口が戻り値です。
#include <stdio.h>
// 2つの整数を受け取り、その合計を返す
int add(int a, int b)
{
return a + b;
}
int main(void)
{
int x = add(2, 3);
printf("%d\n", x); // 5
printf("%d\n", add(x, 10)); // 15
return 0;
}int add(int a, int b) の読み方はこうです。先頭の int が「この関数は int を返す」、カッコの中が「int をふたつ受け取り、関数の中では a と b という名前で使う」。呼び出し側の add(2, 3) の 2 と 3 を実引数、受け取る側の a と b を仮引数と呼びます。仮引数は関数の中だけで使える変数です。
return は2つの仕事を同時にします。値を返すことと、その場で関数を終わらせることです。return の後ろに書いた処理は絶対に実行されません。
引数は何個でも書ける
引数はカンマで区切って何個でも並べられます。ただし型は1つずつ書く決まりで、int add(int a, b) のような省略はできません。引数が増えるほど呼び出し側は順番を間違えやすくなるので、3〜4個までを目安にすると読みやすさを保てます。
戻せる値は1つだけ
return で返せる値は1つだけです。「商と余りを両方返したい」という場面では足りません。この不便さを解決する道具が第2部のポインタと第3部の構造体ですが、いまは「1つしか返せない」と覚えておけば十分です。
戻り値をその場で使う
戻り値は変数に入れてもよいし、上の例のように printf の引数にそのまま渡してもかまいません。関数呼び出しは、実行が終わると「その値そのもの」に化けると考えると読みやすくなります。
#include <stdio.h>
double circle_area(double r)
{
return 3.14159 * r * r;
}
int main(void)
{
printf("%.2f\n", circle_area(2.0)); // 12.57
return 0;
}罠・注意
- 戻り値の型が
intなのにreturnを書き忘れると、呼び出し側はゴミの値を受け取ります。C23でもmain以外の関数は省略できません。 - 逆に
voidの関数でreturn 値;と書くとコンパイルエラーです。voidの関数でも、途中で抜けたいときは値なしのreturn;は書けます。 - 引数の型が違っても、変換できてしまう組み合わせは黙って変換されます。
add(2.9, 3)は 2 に切り捨てられて 5 になります。警告が出ていないか必ず確認しましょう。 - 引数の個数や順番の間違いは意味の間違いです。
div(a, b)とdiv(b, a)は別物で、コンパイラは気づいてくれません。 - 呼び出しのカッコの中に書いた式は、関数に入る前に計算されます。
add(1 + 1, 3)はadd(2, 3)と同じです。
引数と戻り値がはっきりしている関数は、あとから別のプログラムに持っていってもそのまま動きます。部品として再利用できるかどうかは、この入口と出口の設計で決まります。
まとめ: 引数は入口、戻り値は出口。return は「値を返して、即終了」。この2つが決まれば、関数の設計はほぼ終わりです。