C言語のきほん|関数の呼び出し方

作った関数は、呼び出してこそ力を発揮する。関数呼び出しの流れを理解して、プログラムを部品として使いこなそう

前の内容では、関数を自分で定義する方法を学びました。
でも、関数は定義しただけではまだ動きません。
実際にその処理を使うためには、どこかで関数を呼び出す必要があります。

これはとても大切な考え方です。
関数は、作っただけでは「使える部品が用意された状態」にすぎません。
その部品を本当に働かせるには、必要な場所で名前を指定して呼び出し、値を渡し、返ってきた結果を受け取る必要があります。

たとえば、税込み金額を計算する関数を作ったとしても、main 関数の中でその関数を呼び出さなければ、税込み金額は計算されません。
つまり、関数定義は部品を作る作業、関数呼び出しはその部品を使う作業だと言えます。

関数を呼び出すときには、次のことを意識する必要があります。

  • どの関数を呼ぶのか
  • どんな値を渡すのか
  • 関数の中で何が起こるのか
  • 呼び出し元へどう戻ってくるのか
  • 返ってきた値をどう使うのか

この流れが見えるようになると、関数は単なる文法ではなく、処理の流れを整理するための仕組みとして理解できるようになります。

この記事では、関数の呼び出し方の基本構文を確認しながら、

  • 実引数とは何か
  • 仮引数との違い
  • 呼び出し時に処理の流れがどう移るのか
  • 戻り値をどう受け取るのか

を、順番にやさしく見ていきます。

関数の定義と呼び出しはセットで理解することが大切です。
ここで「作った関数をどう使うのか」をしっかり押さえていきましょう。

関数は呼び出して初めて動く

関数は、定義しただけでは処理されません。
プログラムのどこかで名前を書いて呼び出して初めて、その関数の中の処理が実行されます。

たとえば、次のような関数があったとします。

int add_tax(int price)
{
    return (int)(price * 1.1);
}

この関数を定義しただけでは、まだ何も表示されませんし、何の計算も行われません。
この関数を実際に使うには、たとえば main の中で

int total = add_tax(price);

のように呼び出す必要があります。

関数の呼び出し方

関数の呼び出しは、基本的に次の形で書きます。

関数名(実引数の並び);

この形を分けて見ると、次のようになります。

要素内容
関数名呼び出したい関数の名前
実引数の並び実際に関数へ渡す値

たとえば、

add_tax(price);

なら、

  • 関数名は add_tax
  • 実引数は price

です。

実引数とは何か

実引数とは、関数を呼び出すときに、実際に渡す値のことです。

たとえば、

int total = add_tax(price);

と書いた場合、price が実引数です。

この実引数は、関数定義側の仮引数に渡されます。
つまり、呼び出し側と定義側では、次のような対応になります。

int total = add_tax(price);

int add_tax(int amount)

このとき、

  • 実引数は price
  • 仮引数は amount

です。

種類意味
実引数price呼び出し側が渡す値
仮引数amount関数側が受け取るための変数

この2つはとても大切な対応関係です。

型は呼び出し側には書かない

関数定義では仮引数に型を書きますが、関数呼び出しでは型を書く必要はありません。

たとえば、定義側では

int add_tax(int amount)

のように型が必要です。

でも呼び出し側では、

add_tax(price);

と書けばよく、

add_tax(int price);

のようには書きません。

ここは初心者が混乱しやすい点ですが、呼び出し側では値だけを書くと覚えておくとわかりやすいです。

シンプルな呼び出し例

ここでは、税込み金額に「送料を加えた合計を返す関数」を使って説明します。

ファイル名:13_3_1.c

#include <stdio.h>

int total_with_shipping(int price);

int main(void)
{
    int item_price = 2000;
    int total;

    /* 関数を呼び出して合計金額を求める */
    total = total_with_shipping(item_price);

    printf("商品価格は %d 円です。\n", item_price);
    printf("送料込みの合計は %d 円です。\n", total);

    return 0;
}

int total_with_shipping(int price)
{
    const int SHIPPING_FEE = 500;
    return price + SHIPPING_FEE;
}

このプログラムでは、main の中で

total = total_with_shipping(item_price);

と書くことで関数を呼び出しています。

この呼び出しで何が起きるのか

この1行で起きていることを順番に整理すると、次のようになります。

順番内容
1main 関数の処理が進む
2total_with_shipping(item_price) に出会う
3item_price の値が関数側へ渡される
4関数内の処理が実行される
5return で結果が返される
6main に戻り、その値が total に代入される

つまり、関数呼び出しとは、単に「別の処理を呼ぶ」だけではなく、一時的に処理の流れが関数側へ移って、終わったら元に戻るという動きをしています。

関数呼び出しの流れを図で理解しよう

この図では、main 関数から total_with_shipping 関数を呼び出し、実引数の値を渡して、計算結果を受け取る流れを表しています。
呼び出しが行われると、処理はいったん関数側へ移り、return で値が返されたあとに main 側へ戻ります。
この「流れの移動」が見えるようになると、関数呼び出しの仕組みが理解しやすくなります。

戻り値を受け取る呼び出し方

関数呼び出しは、式の一部として使えることが多いです。
特に、値を返す関数は、その戻り値を変数に代入して使うことがよくあります。

たとえば、

int total = total_with_shipping(item_price);

では、関数が返した値を total に代入しています。

このように、関数呼び出しは「結果を生み出す式」として扱えます。

戻り値を直接使うこともできる

返ってきた値を、変数へ入れずにそのまま使うこともできます。

printf("%d\n", total_with_shipping(item_price));

このように書けば、関数の結果を直接表示できます。

ただし、学習の初期では、いったん変数へ代入する書き方のほうが流れを追いやすいです。

実引数が複数ある場合

引数が1つだけとは限りません。
複数ある場合は、カンマで区切って並べます。

たとえば、2つの数の合計を返す関数なら、

int add_numbers(int a, int b)
{
    return a + b;
}

呼び出しは次のようになります。

int result = add_numbers(10, 20);

この場合、

  • 実引数 10 → 仮引数 a
  • 実引数 20 → 仮引数 b

という対応になります。

実引数には変数以外も使える

実引数には、変数だけでなく、定数や式を書くこともできます。

たとえば、次のような呼び出しも可能です。

add_numbers(10, 20);
add_numbers(x, y);
add_numbers(a + 1, b * 2);

つまり、実引数には「評価した結果として値になるもの」を書けると考えるとわかりやすいです。

値を返さない関数の呼び出し

返り値のある関数だけでなく、値を返さない関数もあります。
その場合は、単に文として呼び出します。

たとえば、

void show_message(void)
{
    printf("ようこそ。\n");
}

という関数なら、呼び出しは

show_message();

です。

この場合は戻り値がないので、代入はしません。

シンプルなサンプルプログラム

ここでは、元の「税込み金額を求める関数を呼び出す」例を、別のシンプルな題材に置き換えます。
商品の値引き後の価格を求める関数を呼び出す例です。表示するメッセージやコメントも変えています。

ファイル名:13_3_2.c

#include <stdio.h>

int price_after_discount(int price);

int main(void)
{
    int original_price = 5000;
    int final_price;

    /* 値引き後の価格を求める */
    final_price = price_after_discount(original_price);

    printf("元の価格は %d 円です。\n", original_price);
    printf("値引き後の価格は %d 円です。\n", final_price);

    return 0;
}

/* 10%引き後の価格を返す関数 */
int price_after_discount(int price)
{
    return (int)(price * 0.9);
}

このプログラムの読み方

このプログラムでは、main の中で

final_price = price_after_discount(original_price);

と書いて関数を呼び出しています。

ここでの流れは次の通りです。

項目内容
実引数original_price
仮引数price
関数の仕事10%引きの価格を計算する
戻り値値引き後の価格
受け取る変数final_price

このように、呼び出し側と関数側の対応が見えると、関数呼び出しの仕組みがかなりはっきりしてきます。

main から別の関数へ処理が移る感覚をつかもう

関数呼び出しを理解するときに大切なのは、「処理の流れがいったん関数へ移る」という感覚です。

たとえば main の中で

final_price = price_after_discount(original_price);

に出会うと、そこで main の流れはいったん止まります。
その代わり、price_after_discount の中へ入り、処理を実行します。
そして return に達すると、計算結果を持って main へ戻ってきます。

この「一時的に別の場所へ行って戻る」というイメージは、関数を理解するうえでとても大切です。

関数の呼び出し方を学ぶときのポイント

関数呼び出しを学ぶときは、次の点を意識すると整理しやすいです。

ポイント内容
関数名を見るどの関数を呼んでいるか確認する
実引数を見る何を渡しているか確認する
仮引数と対応させる関数側でどの名前で受け取るかを見る
戻り値を見る何が返ってくるか確認する
代入先を見る返ってきた値をどう使うかを見る

この順番で見ていくと、関数呼び出しの意味がかなり追いやすくなります。

関数の呼び出しを学ぶ意味

関数は定義するだけでは不十分で、実際に呼び出してこそ使えるようになります。
そして、呼び出しの流れを理解すると、プログラムを「処理の部品の組み合わせ」として見られるようになります。

その結果、

  • main には大まかな流れを書く
  • 細かな処理は関数へ分ける
  • 必要な値を渡す
  • 結果を受け取る

という、整理されたプログラムの書き方ができるようになります。

関数を呼び出す仕組みがわかると、関数定義の意味もより深く理解できるようになります。
「作った関数をどう使うのか」が見えることで、関数はただの文法ではなく、プログラムを組み立てるための大事な道具だと実感できるようになります。