C言語基礎|引数を受け取らない関数

入力を“お願いする係”を部品にしよう

Cのプログラムって、入力チェックを入れはじめると、main 関数が一気にゴチャつきがちです。
そこで便利なのが 「引数を受け取らない関数」

たとえば、

  • 「条件を満たすまで入力を繰り返す」
  • 「入力に失敗したら、もう一度うながす」

みたいな処理は、呼び出し側から見ると
「とにかく、条件OKの値を1つ返して!」ってお願いしたいだけですよね。

そういう“お願い”を引き受けるのが、引数なし関数です。

引数を受け取らない関数ってどういうもの?

引数を受け取らない関数は、呼び出し側から情報を受け取らずに動きます。
じゃあ何を頼りに動くの?というと、だいたいは次のどれかです。

引数なし関数が動ける理由

依存先具体例何ができる?
キーボード入力scanfユーザーに入力させる。
乱数・時刻rand, time実行のたびに変化する値を作る。
グローバル変数外部の状態状態を共有して処理する。
固定の規則ルール化一定の処理を毎回実行する。

今回の主役は「入力を読む」タイプです。

サンプルプログラム

ここでは、1〜12の月を読み込んで季節名を表示するプログラムに解説をします。

ポイントはここ:

  • read_month は引数なし(void)で、入力チェック付きで月を返す。
  • season_of は月から季節文字列を返す(引数ありの関数)

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

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

#include <stdio.h>

// 1〜12の月を読み込んで返す(引数なし)
int read_month(void)
{
    int m;

    do {
        printf("月を入力してください(1〜12):");
        scanf("%d", &m);
        if (m < 1 || m > 12)
            puts("範囲外です。1〜12で入力してください。");
    } while (m < 1 || m > 12);

    return m;
}

// 月から季節名を返す
const char *season_of(int month)
{
    if (month == 12 || month == 1 || month == 2) return "冬";
    if (month >= 3 && month <= 5) return "春";
    if (month >= 6 && month <= 8) return "夏";
    return "秋"; // 9〜11
}

int main(void)
{
    int month = read_month();

    printf("%d月は%sです。\n", month, season_of(month));

    return 0;
}

実行例

月を入力してください(1〜12):0
範囲外です。1〜12で入力してください。
月を入力してください(1〜12):13
範囲外です。1〜12で入力してください。
月を入力してください(1〜12):4
4月は春です。

引数なし関数は「値を作って返す係」

引数なし関数は、呼び出し側から材料(引数)をもらわない代わりに、
自分で入力を読んで、条件を満たした値を“作って”返します。

read_month の流れ

ステップ動き結果
1表示して入力を促す例:月を入力してください
2scanfで読むm に入る
3範囲チェック1〜12ならOK
4OKなら return呼び出し元へ月を返す
5NGなら繰り返すもう一度入力へ

この表は「関数の中で何が起きているか」を段階的に見せるための図解です。
順番が見えると、do-while の役割もスッと入ってきます。

表の説明(この記事で使ったもの)

  • 「引数なし関数が動ける理由」表
    引数がなくても関数が処理できる理由(入力・乱数・外部状態など)を整理しました。
    「引数がない=何もできない」ではなく、「材料の入手経路が違う」だけです。
  • 「read_month の流れ」図(表)
    入力→チェック→繰り返し→返却、という処理の流れを“手順の列”で表しました。
    コードだけだと見落としやすい制御の順番がはっきりします。

登場する命令の書式と「何をする命令か」

ここでは、記事中で出てきた主要なものをまとめます。
(命令や引数は囲みません、という指定に合わせています)

関数定義(引数なし)の書式

  • 返却値型 関数名(void) { 処理 }

  • int read_month(void) { ... }

意味:引数を受け取らないことを明示している、という宣言です。
古いCだと 関数名() でも書けましたが、引数なしを明確にするなら void が安全です。

関数呼び出し(引数なし)の書式

  • 関数名()

  • month = read_month();

意味:実引数を渡さずに関数を実行し、返却値を受け取ります。

do-while の書式

  • do { 文 } while (条件);

意味:必ず1回は処理してから条件判定し、真なら繰り返します。
入力チェックと相性がよく、「最低1回は入力してもらう」構造にピッタリです。

scanf の書式

  • scanf(書式文字列, 変数のアドレス)

  • scanf("%d", &m);

意味:キーボードから読んだ値を変数に入れる(入力)ための関数です。
& は「その変数の場所(アドレス)」を渡すために必要になります。

if の書式

  • if (条件) 文
  • if (条件) 文 else 文

意味:条件によって処理を分岐します。
今回だと「範囲外なら注意してループ継続」に使っています。

return の書式

  • return 式;
  • return;

意味:関数を終了し、呼び出し元へ戻ります。
read_month は int を返すので return m; の形になります。
(void関数なら return; だけでもOKです)

引数なし関数の“おいしい使い方”:返却値でそのまま初期化

main の先頭でこう書きました。

  • int month = read_month();

この形が気持ちいい理由は、「読み込み+チェック」を1行に押し込めて、
main をスッキリさせられるからです。

表:よくある書き方の比較

書き方mainの見通し入力処理の場所
month を宣言してから read_month を呼ぶふつうmain と関数に分散
int month = read_month();スッキリ入力の責務が関数側に集約

補足:main の int main(void) の意味

int main(void) は、「main は引数を受け取らない」という意味でもあります。
(コマンドライン引数を扱うなら main の形は変わりますが、今はまず void でOKです)

まとめ:引数なし関数は“入力と検証を肩代わりする部品”

  • 呼び出し側は「値を1つ返して」とお願いするだけ
  • 関数側で入力チェックや繰り返しを全部引き受ける。
  • main が読みやすくなる(これ大事)