C言語のきほん|値を返す関数

値を返す関数がわかると、関数の便利さがぐっと広がる

C言語の関数を学んでいると、まずは「決まった処理を行う関数」や「引数を受け取って表示する関数」に触れることが多いです。
でも、関数の本当の便利さが見えてくるのは、処理した結果を呼び出し元へ返すという考え方を理解してからです。

たとえば、

  • 計算した結果を受け取りたい
  • 入力した値をあとで使いたい
  • 関数の中で求めた答えを main 関数側で利用したい

このような場面では、ただ表示するだけでは足りません。
そこで活躍するのが、値を返す関数です。

値を返す関数を使えるようになると、関数は単なる表示のための部品ではなく、結果を作って渡してくれる便利な道具になります。
この考え方は、これから先に学ぶ計算、判定、メニュー選択、データ処理など、さまざまな場面でとても大切になります。

ここでは、返却値だけを持つ関数に注目しながら、
「どのように値を返すのか」
「呼び出し元ではどう受け取るのか」
「void の関数と何が違うのか」
といった点を、やさしく整理しながら見ていきましょう。

値を返す関数とは

値を返す関数とは、関数の中で得られた結果を、呼び出し元へ返す関数のことです。

今回扱うのは、引数は持たず、返却値だけを持つ関数です。
宣言の形は次のようになります。

返却値の型 関数名(void);

たとえば、整数を返す関数なら次のように書きます。

int get_number(void);

この1行の意味を分けて見ると、次のようになります。

要素意味
返却値の型int関数が呼び出し元へ返す値の型
関数名get_number関数の名前
引数void引数を持たない

ここで大事なのは、引数はないけれど、返却値はあるという点です。
つまり、外から値を受け取らなくても、関数の中で作った結果を呼び出し元へ渡せるということです。

なぜ値を返す関数が必要なのか

関数の中で結果を表示するだけなら、呼び出し元ではその値を使えません。
でも、値を返してくれれば、その結果を変数に入れたり、計算に使ったり、条件分岐に使ったりできます。

たとえば、次のようなことができるようになります。

  • 入力された番号を受け取ってあとで表示する
  • 関数が作った数値を別の計算に使う
  • 判定結果を受け取って if 文で使う
  • 複数の関数を組み合わせて処理を進める

つまり、値を返す関数は、関数の中で得た結果をほかの場所でも使えるようにする仕組みです。

サンプルプログラム

ここでは別のシンプルな例として、ユーザーが選んだ曜日番号を返す関数を作成します。

このプログラムでは、関数の中で曜日番号を入力し、その値を呼び出し元へ返します。

ファイル名:13_8_1.c

// 返却値だけ持つ関数の例
#include <stdio.h>

int select_day_number(void);

int main(void)
{
    int day_no;

    day_no = select_day_number();

    printf("\n選択された曜日番号は%dです。\n", day_no);

    return 0;
}

// ユーザーが指定した曜日番号を返す関数
int select_day_number(void)
{
    int no;

    do {
        printf("曜日番号を選択してください。\n");
        printf("*** 曜日メニュー ***\n");
        printf("1. 月曜日\n");
        printf("2. 火曜日\n");
        printf("3. 水曜日\n");
        printf("1〜3? > ");
        scanf("%d", &no);
    } while (no < 1 || no > 3);

    return no;
}

実行結果例

曜日番号を選択してください。
*** 曜日メニュー ***
1. 月曜日
2. 火曜日
3. 水曜日
1〜3? > 2

選択された曜日番号は2です。

このプログラムの流れ

このプログラムで大切なのは、関数の中で得た値が main 関数へ戻ってくることです。

流れを順番に見ると、次のようになります。

順番内容
1main 関数で select_day_number() を呼び出す
2select_day_number 関数の処理が始まる
3関数の中でユーザーに番号を入力してもらう
4入力値を no に入れる
5return no; で no の値を返す
6返された値が main 関数の day_no に入る
7main 関数で day_no の値を表示する

この流れが理解できると、「値を返す」という意味がかなりはっきり見えてきます。

返却値はどこへ戻るのか

ここはとても大事なポイントです。
関数が return で返した値は、その関数が呼び出された場所へ戻ります

今回の例では、呼び出しは次のように書かれています。

day_no = select_day_number();

この式の右辺に関数呼び出しがあります。
つまり、select_day_number が return no; で返した値は、この右辺の場所へ戻ってきます。
そして、その値が左辺の day_no に代入されます。

イメージとしては、次のような流れです。

day_no = 2;

のように、関数呼び出しの部分が返却値に置き換わる感じです。

関数呼び出しと返却値の関係

値を返す関数の呼び出し方には、引数だけの関数とは違う特徴があります。
それは、返ってきた値を受け取ることが多いという点です。

今回の例では、

day_no = select_day_number();

と書いています。

このように、値を返す関数は次のような形で使われます。

使い方意味
変数に代入するx = get_value();返却値を保存する
表示に使うprintf("%d\n", get_value());返却値をそのまま使う
計算に使うtotal = get_value() + 10;返却値を計算に使う
条件に使うif (get_value() == 1)返却値で条件分岐する

つまり、値を返す関数は式の中で使えるという特徴があります。

関数定義の return 文の役割

値を返す関数では、return 文がとても重要です。
return は、単に「関数を終わらせる」だけではなく、値を呼び出し元へ返す役割を持っています。

今回の例では、最後にこう書かれています。

return no;

これは、

  • no の値を呼び出し元へ返す
  • その場で関数の処理を終える

という2つの意味を持っています。

つまり return は、値を返すこと関数を終了することを同時に行います。

引数がないのに値を返せる理由

今回の関数は引数を持っていません。
つまり、呼び出し元から値をもらっていません。
それでも値を返せるのは、関数の中で値を作ったり取得したりしているからです。

今回の例では、関数の中で scanf によって入力を受け取り、その値を no に入れています。
その no を return で返しているわけです。

このように、返却値だけを持つ関数は、

  • 自分の中で値を作る
  • 入力を受け取る
  • 内部で計算する
  • 固定値を返す

といった使い方ができます。

仮引数の型が void とはどういう意味か

今回の関数宣言は次のようになっています。

int select_day_number(void);

ここで丸かっこの中の void は、引数がありませんという意味です。

これは先頭の int とは意味が違います。

書かれている場所内容
先頭の int返却値は int 型
丸かっこの中の void引数はない

つまりこの関数は、

  • 引数は受け取らない
  • int 型の値を返す

という形です。

この2つを混同しないことが大切です。

値を返さない関数との違い

値を返す関数と、値を返さない関数を比べると違いが見えやすくなります。

比較項目値を返さない関数値を返す関数
返却値の型voidint や double など
呼び出し結果を代入できるかできないできる
主な用途表示や処理だけ行う結果を呼び出し元で使う
return 文省略できる基本的に必要

たとえば、

void show_message(void);

は結果を返しません。
一方で、

int select_day_number(void);

は整数を返します。

この違いをしっかり意識すると、どんな関数を作るべきか判断しやすくなります。

図で流れを見ると理解しやすい

値を返す関数は、関数の中で作られた値が呼び出し元へ戻る流れを図で見ると、とても理解しやすいです。

この図では、main 関数から select_day_number 関数を呼び出し、関数の中で得られた no の値が return によって main 関数へ戻る様子を表しています。

矢印の向きが大切で、今回は関数から呼び出し元へ値が戻る流れを示しています。
引数を渡す図とは逆向きの矢印になるので、この違いを意識すると理解しやすいです。

  • 引数 → 呼び出し元から関数へ渡す
  • 返却値 → 関数から呼び出し元へ戻す

この2つの向きを見分けられるようになると、関数の仕組みがかなり整理できます。

do while を使っている理由

このサンプルでは、入力部分に do while 文が使われています。

do {
    printf("曜日番号を選択してください。\n");
    printf("*** 曜日メニュー ***\n");
    printf("1. 月曜日\n");
    printf("2. 火曜日\n");
    printf("3. 水曜日\n");
    printf("1〜3? > ");
    scanf("%d", &no);
} while (no < 1 || no > 3);

これは、1〜3 の範囲に入るまで入力をやり直すためです。

つまり、

  • まず1回は必ず入力を受ける
  • 範囲外ならもう一度入力する
  • 正しい値ならループを終える

という流れになっています。

このようにしておくことで、関数は常に正しい番号を返しやすくなります。
main 関数側では、安心して返却値を使えるようになります。

値を返す関数の便利さ

値を返す関数の便利さは、関数の中で得た結果を、その後の処理に使えることです。

今回のプログラムでは、返ってきた値を表示するだけでした。
でも、本当はもっといろいろな使い方ができます。

たとえば、

  • 返ってきた番号によって別の処理をする
  • 返却値を if 文で判定する
  • 返却値を別の関数へ渡す
  • 返却値を計算に利用する

などです。

つまり、値を返す関数は、表示だけで終わらない処理の土台になります。

関数宣言・呼び出し・定義を対応させて見る

返却値だけを持つ関数でも、宣言・呼び出し・定義の対応を見ることが大切です。

役割コード意味
関数プロトタイプ宣言int select_day_number(void);int 型の値を返す、引数はない
関数呼び出しday_no = select_day_number();返却値を受け取る
関数定義int select_day_number(void)関数の実際の処理を書く
return 文return no;no の値を呼び出し元へ返す

このつながりを理解すると、関数全体の設計が見えやすくなります。

実践問題

次の仕様に従って関数を作成し、main 関数から呼び出して結果を確認してください。

関数宣言

int input_level(void);

機能
ユーザーにレベル番号を入力してもらい、1〜4 の範囲ならその番号を返す。

返却値
入力されたレベル番号

条件
1〜4 以外が入力された場合は、正しい番号が入力されるまで繰り返す。

実行結果例

レベル番号を選択してください。
*** レベル一覧 ***
1. 初級
2. 中級
3. 上級
4. 達人
1〜4? > 3

選択されたレベル番号は3です。

解答例

ファイル名:13_8_2.c

// 返却値だけ持つ関数の練習問題
#include <stdio.h>

int input_level(void);

int main(void)
{
    int level;

    level = input_level();

    printf("\n選択されたレベル番号は%dです。\n", level);

    return 0;
}

// ユーザーが指定したレベル番号を返す関数
int input_level(void)
{
    int no;

    do {
        printf("レベル番号を選択してください。\n");
        printf("*** レベル一覧 ***\n");
        printf("1. 初級\n");
        printf("2. 中級\n");
        printf("3. 上級\n");
        printf("4. 達人\n");
        printf("1〜4? > ");
        scanf("%d", &no);
    } while (no < 1 || no > 4);

    return no;
}

解答例の解説

この問題のポイントは、関数の中で入力した値を return で返していることです。

main 関数では、次のようにして関数の返却値を受け取っています。

level = input_level();

この input_level() の呼び出し結果が、return no; によって返された値です。
つまり、関数の中で入力された番号が、main 関数の level に入ります。

また、この関数は引数を持っていないので、呼び出すときの丸かっこの中には何も書きません。

input_level();

のように書くだけです。

一方で、返却値はあるので、その結果を変数へ代入して使っています。
この形が、返却値だけ持つ関数の基本形です。

学習のコツ

値を返す関数を学ぶときは、次の2つを意識すると分かりやすいです。

関数呼び出しが値になると考える

関数名を書いたからといって、ただ処理が実行されるだけではありません。
値を返す関数は、呼び出しそのものが1つの値として扱えます。

return は値を返して終わると考える

return は単なる終了命令ではなく、呼び出し元へ結果を渡す大切な役割を持っています。

この2つを意識すると、返却値を持つ関数の意味がかなりつかみやすくなります。