トラック7・🧩関数とスコープ

プロトタイプ宣言

読む目安 約10分・ゴール:プロトタイプ宣言の役割を理解し、関数を好きな順番で書けるようになる

アプリでこのトピックを学ぶ(無料・登録不要)

このトピックの要点

Cのコンパイラは、ソースコードを上から順に一度だけ読みます。まだ見たことのない関数がいきなり呼ばれると、「そんな名前は知りません」と怒って止まります。そこで先に名刺だけ渡しておくのがプロトタイプ宣言です。

#include <stdio.h>

int add(int a, int b);   // ← プロトタイプ宣言(名刺)

int main(void)
{
    printf("%d\n", add(2, 3));
    return 0;
}

int add(int a, int b)    // ← 定義(中身)
{
    return a + b;
}

プロトタイプ宣言は、関数の名前・戻り値の型・引数の型だけを伝えて、セミコロンで終わります。中身({ })は書きません。これがあるおかげで、main を先頭に置いて「まず全体の流れ、細部は後ろ」という読みやすい順番でファイルを書けます。

引数の名前は省略できます。int add(int, int); でも同じ意味です。ただし int max(int width, int height); のように名前を残しておくと、それ自体が説明になります。

宣言がいらない書き方

呼び出しより上に定義そのものを置けば、宣言は要りません。定義は宣言を兼ねるからです。

#include <stdio.h>

int add(int a, int b)   // 先に定義してしまう
{
    return a + b;
}

int main(void)
{
    printf("%d\n", add(2, 3));
    return 0;
}

小さなプログラムならこれで十分です。ただしこの書き方だと、関数が増えるほど main がファイルのいちばん下へ押しやられ、全体の流れを追うのに最後までスクロールする羽目になります。また、2つの関数が互いを呼び合う場合は、どちらを上に置いても片方が「知らない関数」になるため、宣言なしでは解決できません。関数が5個を超えたあたりから、先頭にプロトタイプ宣言を並べる書き方のほうが快適になります。

実は毎回お世話になっている

printf が使えるのはなぜでしょう。答えは #include <stdio.h> です。あの1行は、printf などのプロトタイプ宣言がずらりと書かれたファイルを、その場に貼り付けています。つまり皆さんは1日目から、プロトタイプ宣言の恩恵を受けていたわけです。scanf も同じです。

罠・注意

師範宣言は「約束」、定義は「実物」じゃ。約束が先にあるから、実物が後から来ても話が通る

まとめ: プロトタイプ宣言=関数の名刺。戻り値の型 名前(引数の型); を呼び出しより上に置けば、定義はどこに書いてもかまいません。

アプリでこのトピックを学ぶ(無料・登録不要)

確認問題

確認問題 1

プロトタイプ宣言を書く目的として正しいものはどれですか。

  1. 関数の処理を高速化するため
  2. 呼び出しより下に定義された関数を、コンパイラに前もって知らせるため
  3. 関数のローカル変数を初期化するため
  4. 関数を何度も呼べるようにするため
答えを見る

正解:B(呼び出しより下に定義された関数を、コンパイラに前もって知らせるため)

コンパイラはソースを上から順に読むため、まだ知らない関数を呼ぶとエラーになります。プロトタイプ宣言は「戻り値の型・名前・引数の型」だけを先に伝える名刺です。速度も初期化も呼び出し回数も関係ありません。

確認問題 2

コンパイルエラーになります。原因の行はどれですか。

1#include <stdio.h>
2
3void show_sum(int a, int b)
4{
5    return a + b;
6}
7
8int main(void)
9{
10    show_sum(2, 3);
11    return 0;
12}
答えを見る

バグのある行:5行目

戻り値の型が void の関数は値を返せません。表示したいなら 5行目を printf("%d\n", a + b); に、値を返したいなら 3行目の void を int に変えます。void の関数でも、値なしの return; で途中終了することはできます。

void は「返す値はない」という宣言です。その関数の中で return 値; と書くとコンパイルエラーになります。宣言した戻り値の型と return の内容は必ず一致させます。

「関数とスコープ」の目次

  1. 関数とは——処理に名前を付ける
  2. 引数と戻り値
  3. プロトタイプ宣言
  4. 変数のスコープ——見える範囲
  5. 変数の寿命とstatic
  6. コールスタック——関数呼び出しの舞台裏
  7. 値渡しの本質
  8. グローバル変数との付き合い方
  9. 関数分割の設計センス
  10. 再帰の入口——自分を呼ぶ関数

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版の販売ページは準備中です。

ほかのトラック

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版