C言語基礎|return文と返却値

関数の“おみやげ”を受け取る仕組み

関数呼出しの仕組みが分かってきたところで、次に押さえたいのが return文 です。
return文は、関数を終わらせるだけじゃなくて、呼び出し元へ値(返却値)を持ち帰る役目を持っています。

イメージとしてはこんな感じです。

  • 呼び出し元:お願い、計算して結果ちょうだい!
  • 関数:了解!…できたよ、これ返すね(return)

この「返すね」がまさに return文です。

return文の基本ルール:返せるのは1つだけ

return文は次の形をしています。

return文の書式

書式意味使える関数
return 式;関数を終了し、式の値を返す返却値型が void 以外
return;関数を終了する(値は返さない)返却値型が void

ポイントはここです。

  • return の後ろに置ける式は 0個か1個
  • だから関数は 2個以上の値を同時に返却できない

return文の構造(イメージ)

部品内容
return関数を終える合図
式(あれば)持ち帰る値(返却値)
;文の終わり

「返却値=returnの後ろの式の値」
これが return文の一番コアな考え方です。

サンプルプログラム

3つの整数の中央値(真ん中の値)を返す関数 median3 を例に解説をします。
返却値が1つであること、returnで戻ること、仮引数とローカル変数の独立性などをまとめて確認できます。

プログラム例:median3で「真ん中の値」を返す

プロジェクト名:chap6-3-1 ソースファイル名:chap6-3-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

// 3つの整数の中央値(真ん中の値)を返す
int median3(int a, int b, int c)
{
    int mid;

    if (a > b) { int t = a; a = b; b = t; }  // a <= b にする
    if (b > c) { int t = b; b = c; c = t; }  // b <= c にする
    if (a > b) { int t = a; a = b; b = t; }  // もう一度 a <= b にする

    mid = b;          // この時点で b が中央値
    return mid;       // 返却値として mid を返す
}

int main(void)
{
    int x, y, z;

    puts("3つの整数を入れてください。真ん中の値を表示します。");
    printf("1つ目:");
    scanf("%d", &x);
    printf("2つ目:");
    scanf("%d", &y);
    printf("3つ目:");
    scanf("%d", &z);

    printf("真ん中の値は %d です。\n", median3(x, y, z));

    return 0;
}

実行例

3つの整数を入れてください。真ん中の値を表示します。
1つ目:5
2つ目:3
3つ目:4
真ん中の値は 4 です。

return文が「関数呼出し式の値」になる

ここ、めちゃ大事です。
median3(x, y, z) は 関数呼出し式なので、評価すると値になります。

そしてその値は、関数内の return が返した値です。

呼び出し~返却(イメージ)

呼び出し元(main)呼び出される関数(median3)
median3(x, y, z) を評価仮引数 a,b,c が用意される。
x,y,z の値が渡るa,b,c に値が代入される。
… main は一時停止処理して mid を決める。
戻ってきて printf に渡るreturn mid; で値を返す。

つまり、main側では次のような流れになります。

  • median3(x, y, z) を評価
  • その評価結果が printf の %d に入る。
  • 画面に表示される。

returnを1つにまとめる考え方:出口を一本化すると読みやすい

関数の入口は基本的に1つです。
出口(return)がたくさんあると、途中でどこから抜けるか追いかけにくくなります。

だから、学習初期は特に returnを1つにまとめる書き方がオススメです。

returnを一本化するメリット

メリットうれしい理由
流れが追いやすいどこで終わるか迷わない。
デバッグしやすいreturn直前に確認ポイントを置ける。
変更に強い後で処理を追加しても崩れにくい。

ただし、早期returnが悪いわけではなく、状況によっては可読性が上がることもあります。
まずは「基本は一本化」→慣れたら使い分け、が安心です。

関数内の変数は関数ごとに独立している

median3 の仮引数 a,b,c と main の x,y,z は別物です。

  • 名前が似ていても、記憶域(入れ物)が別
  • 関数ごとに「自分専用の変数」が作られる

変数が独立であることの整理

場所変数意味
mainx, y, z入力として受け取った値
median3a, b, c関数内で使う受け取り用の値(仮引数)
median3mid関数内だけで使う作業用変数

この独立性のおかげで、関数を部品として安心して使えます。

この記事で使った表・図は何のため?

  • return文の書式表:return 式; と return; の使い分けを迷わないため
  • 呼び出し~返却の図:returnの値が「呼出し式の評価結果」になる流れを目で追うため
  • return一本化の表:読みやすさの理由を言語化するため
  • 変数独立の表:同名でも別物、という不安を消すため

演習問題

演習6-1:2つの整数の小さいほうを返す

2つのint型整数の小さいほうを返す関数を作成し、mainで動作確認せよ。
関数プロトタイプ:
int min2(int a, int b);

解答例

プロジェクト名:chap6-3-2 ソースファイル名:chap6-3-2.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

int min2(int a, int b)
{
    int min = a;
    if (b < min)
        min = b;
    return min;
}

int main(void)
{
    int n1, n2;

    puts("2つの整数を入力してください。小さいほうを表示します。");
    printf("1つ目:");
    scanf("%d", &n1);
    printf("2つ目:");
    scanf("%d", &n2);

    printf("小さいほうは %d です。\n", min2(n1, n2));
    return 0;
}

解説

  • return min; の min が返却値
  • 呼出し式 min2(n1, n2) を評価すると、その返却値が得られる
  • returnは1個なので出口が分かりやすい

演習6-2:3つの整数の最小値を返す

3つのint型整数の最小値を返す関数を作成し、mainで動作確認せよ。
関数プロトタイプ:
int min3(int a, int b, int c);

解答例

プロジェクト名:chap6-3-3 ソースファイル名:chap6-3-3.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>

int min3(int a, int b, int c)
{
    int min = a;
    if (b < min) min = b;
    if (c < min) min = c;
    return min;
}

int main(void)
{
    int a, b, c;

    puts("3つの整数を入力してください。最小値を表示します。");
    printf("a:");
    scanf("%d", &a);
    printf("b:");
    scanf("%d", &b);
    printf("c:");
    scanf("%d", &c);

    printf("最小値は %d です。\n", min3(a, b, c));
    return 0;
}

解説

  • min を作業用に使い、最後に return min; で返す
  • if を並べると、比較の流れが読みやすい
  • return が 1 つなので、関数の終わりが明確