C言語入門|仮引数と実引数のしくみ

引数を使った関数呼び出し、
だいぶ慣れてきましたね。

でも、ここで一度、
ちょっと立ち止まって考えてみましょう。

「関数を定義するときの引数」と
「関数を呼び出すときの引数」
— 見た目はそっくりですが、
実は役割がまったく違う のです。

この違いを理解できるかどうかで、
今後の関数理解が一段深くなります。

同じカッコでも中身は別モノ

まずは、関数定義と関数呼び出しを並べて見てみましょう。

void showMessage(int level)
{
    printf("レベル %d の処理です\n", level);
}

int main(void)
{
    showMessage(3);
    return 0;
}

どちらも関数名の後ろにカッコがありますね。

でも実は、

  • 定義側の引数
  • 呼び出し側の引数

は、役割も意味も違います。

仮引数とは何か

関数定義に書く引数は、
仮引数(かりひきすう) と呼ばれます。

void showMessage(int level)

この1行は、
関数がこんな自己紹介をしているイメージです。

私を呼び出すときは、
int 型の情報を1つ持ってきてください。
関数の中では level という名前で使います。

仮引数は、

  • データ型
  • 関数内で使う変数名

を決めているだけで、
実際の値はまだ決まっていません。

関数が呼び出されるその瞬間まで、
中身は空っぽの箱なのです。

実引数とは何か

一方、関数を呼び出す側で書く引数は、
実引数(じつひきすう) と呼ばれます。

showMessage(3);

ここで指定している 3 は、

  • 実際に使ってほしい具体的な値
  • 関数に仕事を依頼するための材料

です。

実引数は、

この値を使って処理してください

という、
具体的な指示そのもの になります。

仮引数と実引数の対応関係

仮引数と実引数は、
関数が呼び出された瞬間に
次のように結びつきます。

種類書かれる場所役割
仮引数関数定義受け取る箱を用意する
実引数関数呼び出し実際の値を渡す

今回の例では、

  • 実引数 3
  • 仮引数 level

が対応し、
関数内では level に 3 が代入された状態で
処理が始まります。

流れで考える仮引数と実引数

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

  1. main関数が値を準備する
  2. 関数を呼び出す
  3. 実引数の値が仮引数の箱に入る
  4. 関数内で処理が行われる

仮引数は「受け取り口」、
実引数は「渡される荷物」
と考えると、とてもわかりやすくなります。

仮引数がない関数では void を書く

引数を受け取らない関数もあります。

その場合、
仮引数がないことを明確に示すために
void を書く必要があります。

void greet(void)
{
    printf("おはようございます\n");
}

この void は、

  • 引数は1つも受け取りません

という意思表示です。

void を省略してはいけない理由

うっかり次のように書いてしまうことがあります。

void greet()
{
    printf("おはようございます\n");
}

このコードは、

  • コンパイルできる
  • 実行もできる

ため、一見問題なさそうに見えます。

しかし、実はかなり危険です。

void を省略するリスク

void を省略すると、
次のような問題が起こる可能性があります。

問題点内容
規格差Cの仕様によってはエラーや警告になる。
意味の曖昧さ任意個数の引数を許す意図と解釈される。
型チェック不能引数の誤りをコンパイル時に検出できない。

特に、
プロトタイプ宣言で void を省略すると、

  • 引数チェックが行われない。
  • バグが静かに紛れ込む。

という、
非常にリスクの高いコード になります。

仮引数と実引数を意識する意味

仮引数と実引数を
しっかり区別して考えられるようになると、

  • 関数の設計が明確になる。
  • 引数ミスの原因がすぐわかる。
  • 他人のコードも読みやすくなる。

といったメリットがあります。

関数を書くときは、

  • 定義する立場
  • 呼び出す立場

この2つを常に意識してみてください。

まとめ:名前は似ているが役割は別

最後にポイントを整理します。

用語役割
仮引数関数が受け取るための箱
実引数呼び出し側が渡す具体的な値
void引数がないことの明示

このしくみを理解できると、
次に学ぶ 値の受け渡し
ポインタ引数 への理解も
ぐっと楽になります。