C言語のきほん|引数を受け取る関数

引数を渡せるようになると、関数はもっと便利な部品になる

C言語の関数を学び始めると、まずは決まった処理をそのまま行う関数を作ることが多いです。
でも、実際のプログラムでは「毎回少しずつ違う処理をしたい」という場面がたくさんあります。

そんなときに役立つのが、引数を受け取る関数です。
引数を使うと、関数の外から値を渡して、その値に応じて処理の内容を変えられるようになります。

たとえば、

  • 回数を渡して、その回数だけ表示する
  • 点数を渡して、評価メッセージを表示する
  • 温度を渡して、コメントを変える

といったように、1つの関数をいろいろな場面で使い回せるようになります。

つまり、引数を受け取る関数は、固定の動きしかしない関数を、より柔軟に使える関数へ進化させる仕組みです。
ここでは、引数だけを持つ関数の書き方と考え方を、サンプルプログラムとともにやさしく整理していきます。

引数だけ持つ関数とは

引数だけ持つ関数とは、呼び出し元から値を受け取って処理を行うが、結果は返さない関数のことです。

宣言の形は次のようになります。

void 関数名(型 仮引数名);

たとえば、整数を1つ受け取る関数なら次のように書きます。

void show_message(int level);

この形には、大事な意味が2つあります。

要素意味
返却値の型void値を返さない
引数int level整数値を1つ受け取る

ここでのポイントは、値は受け取るけれど、呼び出し元へ結果は返さないことです。
そのため、表示処理や案内処理などに向いています。

なぜ引数が必要なのか

引数がない関数は、呼び出しても毎回同じ動きをします。
それはそれで便利ですが、もう少し柔軟にしたいことがあります。

たとえば、次のような場面を考えてみてください。

  • 1回だけではなく、指定した回数だけ表示したい
  • 数字によってメッセージを変えたい
  • 状況に応じて違う内容を表示したい

こうしたとき、関数の中に値を固定してしまうと使い回しがしにくくなります。
そこで、必要な値を引数として外から渡すようにすると、同じ関数をさまざまな場面で使えるようになります。

つまり引数は、関数に外から材料を渡すための仕組みです。

サンプルプログラム

点数に応じてメッセージを表示する関数を考えてみます。

この例では、score という引数を受け取り、その値に応じて異なるコメントを表示します。

ファイル名:13_7_1.c

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

void show_comment(int score);

int main(void)
{
    show_comment(85);  // 関数を呼び出す(85点を渡す)
    return 0;
}

// 点数に応じたコメントを表示する関数
void show_comment(int score)
{
    if (score >= 80) {
        printf("とてもよくできました!\n");
    }
    else if (score >= 60) {
        printf("よくがんばりました!\n");
    }
    else {
        printf("次もいっしょにがんばろう!\n");
    }
}

実行結果例

とてもよくできました!

このプログラムの流れ

このプログラムでは、main 関数から次のように関数を呼び出しています。

show_comment(85);

この 85 が、関数へ渡される実引数です。
そして、関数定義側では次のように受け取っています。

void show_comment(int score)

この score が仮引数です。

つまり、呼び出し側で渡した 85 が、関数の中では score という名前で使われています。

流れを表にすると次のようになります。

順番内容
1main 関数で show_comment(85); を実行する
285 が関数へ渡される
3仮引数 score が 85 を受け取る
4if 文で score の値を判定する
5条件に合ったメッセージを表示する
6関数が終了し、main 関数へ戻る

このように、引数を使うことで、関数の動きが渡された値によって変わります。

実引数と仮引数の違い

引数を学ぶときに、とても大事なのが実引数仮引数の違いです。

用語書かれる場所意味
実引数関数呼び出し側show_comment(85);実際に渡す値
仮引数関数定義側void show_comment(int score)受け取るための変数

今回の例なら、

  • 実引数 → 85
  • 仮引数 → score

です。

この区別があいまいだと、関数の流れが分かりにくくなります。
まずは、呼び出す側が実引数、受け取る側が仮引数と覚えておくとよいです。

返却値がないので受け取らない

この関数は引数を受け取りますが、返却値はありません。
そのため、呼び出すときに結果を変数へ代入することはしません。

たとえば、今回の呼び出しはこうです。

show_comment(85);

返却値がないので、次のような書き方はしません。

int result = show_comment(85);

なぜなら、show_comment は void 型、つまり何も返さない関数だからです。

この点はとても大切です。
引数があることと、返却値があることは別です。
値を受け取る関数でも、結果を返すとは限りません。

return 文は必要か

返却値がない関数では、最後に return 文を書かなくても大丈夫です。
関数の終わりの } まで処理が進めば、その時点で自動的に呼び出し元へ戻ります。

今回の関数も、最後は return を書いていません。

void show_comment(int score)
{
    if (score >= 80) {
        printf("とてもよくできました!\n");
    }
    else if (score >= 60) {
        printf("よくがんばりました!\n");
    }
    else {
        printf("次もいっしょにがんばろう!\n");
    }
}

ただし、途中で関数を終わらせたい場合には、

return;

と書くことがあります。

たとえば次のような例です。

void show_comment(int score)
{
    if (score < 0) {
        return;
    }

    if (score >= 80) {
        printf("とてもよくできました!\n");
    }
    else if (score >= 60) {
        printf("よくがんばりました!\n");
    }
    else {
        printf("次もいっしょにがんばろう!\n");
    }
}

このように書くと、score が 0 未満ならそこで関数を終了できます。

引数を受け取る関数のよさ

引数を受け取る関数には、いくつもよい点があります。

よさ内容
再利用しやすい渡す値を変えるだけで何度も使える
柔軟に動く状況ごとに違う処理ができる
コードを減らせる同じような処理を何度も書かなくてよい
役割がはっきりする何を受け取って何をする関数か分かりやすい

たとえば、show_comment 関数は 85 だけでなく、60 や 40 を渡しても使えます。

show_comment(85);
show_comment(60);
show_comment(40);

こうすると、同じ関数なのに、渡した値に応じて表示内容が変わります。
これが引数の大きな強みです。

引数がない関数との違い

引数を受け取る関数の特徴をはっきりさせるために、引数がない関数と比べてみましょう。

比較項目引数がない関数引数がある関数
呼び出すたびに動きが変わるか基本的に変わらない渡す値によって変わる
外から情報を渡せるか渡せない渡せる
柔軟性低め高い
向いている処理定型的な表示や固定処理条件に応じて変わる処理

たとえば、

void show_title(void);

なら毎回同じタイトルを表示するだけかもしれません。
一方で、

void show_comment(int score);

なら score の値によってメッセージが変わります。

図で見ると流れがつかみやすい

引数の流れは、図で見るとかなり理解しやすくなります。
特に、「呼び出し側から値が渡される」というイメージがつかみやすくなります。

この図では、main 関数から show_comment 関数へ 85 という値が渡される様子 を表しています。

main 側で書いた 85 は実引数です。
それが show_comment 関数に渡されると、関数定義側では仮引数 score として受け取られます。

そのあと、score の値を使って if 文で分岐し、適切なメッセージを表示します。
この関数は返却値を持たないので、結果をどこかへ返す矢印はありません。
この点が、返却値ありの関数との違いです。

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

引数を受け取る関数では、宣言・呼び出し・定義の対応を見ることが大切です。

今回の例を対応づけると、次のようになります。

役割コード意味
関数プロトタイプ宣言void show_comment(int score);この関数は int 型を1つ受け取る
関数呼び出しshow_comment(85);実引数として 85 を渡す
関数定義void show_comment(int score)仮引数 score で受け取る

この3つがつながっていることを意識すると、関数の全体像がかなり見やすくなります。

引数の型は一致させることが大切

引数を使うときは、渡す値の型受け取る側の型が合っていることが大切です。

今回の例では、

  • 実引数 85 は整数
  • 仮引数 score は int 型

なので一致しています。

もし関数宣言や関数定義の型がずれていると、正しく動かなかったり、警告の原因になったりします。

たとえば、宣言が

void show_comment(int score);

なのに、定義が

void show_comment(double score)

のようになっていると不一致です。

そのため、引数を使うときは次の点をそろえることが大事です。

確認したい点内容
宣言の型int か double か
呼び出し時の値渡している値の種類は何か
定義の型宣言と一致しているか

複数の値を受け取ることもできる

今回は引数を1つだけ受け取る例でしたが、関数は複数の引数を受け取ることもできます。

たとえば次のような形です。

void show_result(int score, int max_score);

このように、カンマで区切って複数の引数を書けます。
ただし、今の段階ではまず引数を1つ受け取る基本形をしっかり押さえることが大切です。

1つの引数の流れが分かれば、複数引数も考えやすくなります。

実践問題

pr13_2_2.c

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

関数宣言

void show_temperature_message(int temperature);

機能
温度 temperature の値に応じてメッセージを表示する。

表示ルール

  • 30以上なら 暑いですね! と表示
  • 15以上30未満なら 過ごしやすいですね! と表示
  • 15未満なら 少し寒いですね! と表示

実行結果例

気温を入力してください > 18

過ごしやすいですね!

解答例

ファイル名:13_7_2.c

// 気温に応じたメッセージを表示するプログラム
#include <stdio.h>

void show_temperature_message(int temperature);

int main(void)
{
    int temperature;

    printf("気温を入力してください > ");
    scanf("%d", &temperature);

    printf("\n");

    show_temperature_message(temperature);

    return 0;
}

// 気温に応じたメッセージを表示する関数
void show_temperature_message(int temperature)
{
    if (temperature >= 30) {
        printf("暑いですね!\n");
    }
    else if (temperature >= 15) {
        printf("過ごしやすいですね!\n");
    }
    else {
        printf("少し寒いですね!\n");
    }
}

解答例の解説

この問題では、main 関数で入力した temperature の値を、show_temperature_message 関数へ渡しています。

show_temperature_message(temperature);

この temperature が実引数です。
そして関数定義側では、

void show_temperature_message(int temperature)

のように、仮引数 temperature で受け取っています。

受け取った値を if 文で判定し、条件に応じたメッセージを表示しているので、まさに引数だけ持つ関数の基本形になっています。

この関数は表示することが役割なので、返却値は必要ありません。
そのため返却値の型は void になっています。

学習のコツ

引数を受け取る関数を学ぶときは、次の2つを意識すると理解しやすいです。

外から値を渡していることを意識する

関数の中に値が突然現れるのではなく、呼び出し元から渡されていると考えることが大切です。

受け取った値で処理が変わることを意識する

引数があることで、同じ関数でも渡す値に応じて違う動作ができます。
ここが、引数なしの関数との大きな違いです。

この2つを意識しながらコードを読むと、引数の意味がぐっとつかみやすくなります。