C言語のきほん|関数の基礎と引数の受け渡し

同じ処理は、何度でも呼べる部品にしよう。関数を使うと、C言語のプログラムはもっと読みやすく、もっと強くなる

これまでの学習では、printf や scanf、strlen、rand など、C言語に用意されている標準ライブラリ関数を使ってきました。
関数は「用意された便利なものを呼び出して使うもの」という印象があるかもしれませんが、C言語では自分で関数を作ることもできます。

これはとても大切な考え方です。
なぜなら、プログラムを書いていると、同じような処理を何度も書きたくなる場面がたくさん出てくるからです。

たとえば、

  • 税込み金額を計算する
  • 合計を求める
  • 平均を計算する
  • 入力値をチェックする
  • 特定の条件で値を加工する

といった処理は、1回だけではなく、何度も使いたくなることがあります。
そんなとき、毎回同じ計算式や処理の流れをそのまま書いていると、プログラムは長くなり、読みにくくなり、修正もしづらくなります。

そこで役立つのが関数です。

関数とは、ひとまとまりの処理に名前を付けて、必要なときに呼び出せるようにしたものです。
これによって、複雑な処理でも「この関数を呼べばよい」と考えられるようになります。
つまり、処理の中身を毎回意識しなくても使えるようにする、いわば部品化の仕組みです。

このように、関数を作ることには大きな意味があります。

  • 処理を整理しやすくなる
  • 同じ処理を何度も再利用できる
  • 修正箇所を減らせる
  • プログラムの見通しがよくなる

さらに、関数を学ぶときに大切なのが、引数の受け渡しの考え方です。
関数は、呼び出し元から値を受け取って処理を行い、必要なら結果を返します。
この「値を渡す」「結果を受け取る」という流れを理解することで、関数を本当に使いこなせるようになります。

この章では、まず関数とは何か、なぜ使うのかという基本から入り、関数を使うことでプログラムがどう整理されるのかをやさしく見ていきます。
関数はC言語の学習の中でも特に重要なテーマのひとつです。ここでしっかり土台を作っていきましょう。

関数とは何か

関数とは、ひとまとまりの処理に名前を付けて、必要なときに呼び出せるようにしたものです。

たとえば、「税込み金額を求める」「2つの数の大きい方を返す」「文字列の長さを数える」といった処理を、関数として定義できます。

関数を使わずにすべて main の中へ直接書くこともできます。
でも、そうするとプログラムが長くなりやすく、同じような処理が何度も登場したときにとても不便です。

関数にすると、その処理に名前を付けて呼び出せるので、プログラム全体が整理しやすくなります。

関数のイメージ

関数は、よく「機械」や「箱」にたとえられます。

  • 入力として値を渡す
  • 中で決められた処理を行う
  • 結果を返す

という流れになるからです。

たとえば、税込み金額を求める関数なら、

  • 金額を渡す
  • 税率を使って税込み額を計算する
  • 税込み金額を返す

というイメージになります。

なぜ関数を使うのか

関数を使う理由はいくつもありますが、特に大切なのは次の4つです。

理由内容
処理をまとめられる同じ目的の処理をひとつの単位にできる
再利用しやすい一度作れば何度でも呼び出せる
読みやすくなるmain の流れがすっきりする
修正しやすい関数の中身だけ直せば済むことが多い

この4つは、どれも実際にプログラムを書き始めると強く実感する利点です。

毎回計算を書くとどうなるか

たとえば、商品の税込み金額を求める処理を考えてみましょう。
消費税率を 10% とすると、金額に 1.1 を掛ければ税込み金額が求められます。

その処理を main の中へ直接書くと、たとえば次のような形になります。

ファイル名:13_1_1.c

#include <stdio.h>

int main(void)
{
    const double TAX_RATE = 0.10;
    int price = 10000;

    int total = price * (1.0 + TAX_RATE);

    printf("税込み金額は %d 円です。\n", total);

    return 0;
}

このコード自体は間違いではありません。
でも、税込み金額を求めたい場所がプログラムの中に何回も出てきたらどうでしょうか。

そのたびに、

price * (1.0 + TAX_RATE)

のような式を書くことになります。
しかも、税率や条件が変わると、あちこちを修正しなければいけなくなるかもしれません。

現実の条件はもっと複雑になる

実際には、税率はいつも一律とは限りません。
飲食料品は 8%、酒類や外食は 10% など、条件によって変わる場合があります。

そのような場合、単純に 1.1 を掛けるだけでは済まず、

  • この商品は軽減税率か
  • 酒類か
  • 外食か
  • ケータリングか

といった細かな判定が必要になることもあります。

こうした処理を毎回 main に書いていると、コードはどんどん複雑になります。

関数にすると何がよいのか

そこで、「税込み金額を求める処理」を関数にしてしまうと、とても整理しやすくなります。

たとえば、

int total_with_tax(int amount);

という関数を用意しておけば、呼び出す側は

int total = total_with_tax(price);

と書くだけで済みます。

このようにすると、呼び出す側は「どう計算しているか」を細かく気にしなくてもよくなります。
必要なのは、「金額を渡したら税込み金額が返ってくる」という約束だけです。

これがブラックボックス化の考え方です。

ブラックボックス化とは

ブラックボックス化とは、内部の詳しい仕組みを意識しなくても、入力と出力だけを見て使えるようにする考え方です。

たとえば、電卓を使うとき、内部の回路や計算の仕組みを知らなくても、

  • 数字を押す
  • 演算子を押す
  • 結果が出る

という使い方ができます。

関数もこれと似ています。

たとえば total_with_tax という関数があれば、

  • 金額を渡す
  • 税込み金額が返ってくる

という使い方ができます。
中でどんな条件分岐や計算をしているかは、呼び出す側が毎回意識しなくてよいのです。

この図では、関数が「入力を受け取り、内部で処理し、結果を返す箱」のような役割を持つことを表しています。
呼び出す側は関数の中身を毎回細かく意識しなくても、必要な値を渡して結果を受け取るだけで使えます。
これが、関数を使う大きな利点のひとつです。

関数化のメリットをもう少し具体的に見る

関数化の利点は、ただ見た目がすっきりするだけではありません。
実際には、プログラムの保守や拡張にも大きく関わってきます。

再利用しやすい

同じ処理を何度も呼び出せます。
税込み金額を求める処理が 5回必要なら、関数を 5回呼べばよいだけです。

修正しやすい

税率や計算方法が変わっても、関数の中だけを直せば対応できることが多いです。
毎回同じ式をあちこちに書いていると、全部修正しなければいけません。

読みやすい

main の中に細かい計算式が並ぶよりも、

total = total_with_tax(price);

のように書かれていたほうが、何をしているのかが一目で伝わります。

分担しやすい

大きなプログラムでは、処理ごとに関数へ分けておくことで、考える範囲を小さくできます。
「この関数は何をするか」に集中しやすくなるのです。

関数の基本的な形

関数は、一般に次のような形で書きます。

返却値の型 関数名(引数)
{
    処理
}

たとえば、税込み金額を返す関数なら、

int total_with_tax(int amount)
{
    /* 処理 */
}

のような形になります。

この形には、重要な要素がいくつかあります。

要素意味
返却値の型関数が最後に返す値の型
関数名関数の名前
引数呼び出し元から受け取る値
処理本体関数の中で行う処理

この章では、特に「引数の受け渡し」が大事なテーマになります。
関数は、ただ呼び出すだけではなく、必要な値を渡して、その値をもとに処理を行うことが多いからです。

呼び出す側と定義する側

関数を学ぶときは、「呼び出す側」と「定義する側」を分けて考えると理解しやすくなります。

呼び出す側

関数を使う側です。
たとえば main の中で

int total = total_with_tax(price);

と書く部分です。

定義する側

関数そのものを作る側です。
たとえば、

int total_with_tax(int amount)
{
    return amount * 110 / 100;
}

のように書く部分です。

この2つがつながることで、

  • 呼び出す側が値を渡す
  • 関数側が受け取る
  • 処理する
  • 結果を返す

という流れができあがります。

サンプルプログラム

商品価格を受け取り、税込み価格を返す関数を作る例です。

ファイル名:13_1_2.c

#include <stdio.h>

int add_tax(int price);

int main(void)
{
    int item_price = 1200;
    int total_price;

    /* 税込み価格を計算する */
    total_price = add_tax(item_price);

    printf("商品価格は %d 円です。\n", item_price);
    printf("税込み価格は %d 円です。\n", total_price);

    return 0;
}

/* 税込み価格を返す関数 */
int add_tax(int price)
{
    const double TAX_RATE = 0.10;

    return (int)(price * (1.0 + TAX_RATE));
}

このプログラムの読み方

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

total_price = add_tax(item_price);

と書いています。
ここでは、item_price の値を add_tax に渡し、その結果を total_price に受け取っています。

関数側では、

int add_tax(int price)

となっているので、呼び出し元から渡された値を price という名前で受け取っています。

そして最後に、

return (int)(price * (1.0 + TAX_RATE));

で計算結果を返しています。

この一連の流れが、関数の基本です。

関数を使うと何が見やすくなるのか

もし関数を使わずに main の中へ全部書いていたら、税込み価格の計算式が毎回見えてしまいます。
でも、関数を使うと

add_tax(item_price)

という形だけで「税込み価格を求める」という意味が伝わります。

これは、コードの意図が見やすくなるということです。
関数名が適切なら、その1行だけで何をしているかがかなりわかります。

関数の名前はとても大切

関数の名前は、できるだけ「何をする関数なのか」がわかるように付けることが大切です。

たとえば、

関数名印象
func1何をするか分かりにくい
calc少し広すぎる
add_tax税込み価格を計算するとわかりやすい
total_with_taxより具体的でわかりやすい

関数はブラックボックスとして使うからこそ、名前が説明の役割を持ちます。
中身を見なくても使えるようにするには、名前の付け方も大切なのです。

関数を学ぶときの最初のポイント

関数を学び始めた段階では、まず次の点を押さえると理解しやすいです。

ポイント内容
関数は処理のまとまりひとまとまりの処理を名前で呼べる
関数は自分でも作れる標準ライブラリ関数だけではない
値を渡せる引数として受け渡しできる
結果を返せるreturn で呼び出し元へ返せる
処理を部品化できる再利用しやすく、修正しやすい

この基本を押さえると、関数を「ただの文法」ではなく、プログラムを組み立てるための部品として理解できるようになります。

関数の基礎を学ぶ意味

関数は、C言語の中でもとても重要なテーマです。
なぜなら、関数を理解すると、プログラムを「1本の長い流れ」として書くのではなく、「役割ごとに分けて組み立てる」考え方が身につくからです。

この考え方が身につくと、

  • 小さな処理ごとに整理できる
  • 読みやすいコードを書ける
  • 修正しやすいコードを書ける
  • 再利用しやすいコードを書ける

ようになります。

特にこれから学ぶ「引数の受け渡し」は、関数を本当に使いこなすための土台になります。
呼び出し元からどのように値が渡され、関数の中でどう扱われるのかがわかると、関数の動きが一気にはっきり見えてきます。

関数は、C言語の学習を次の段階へ進めてくれる大切な仕組みです。
標準ライブラリ関数を使う段階から、自分で関数を作って使う段階へ進むことで、プログラム作りの自由度は大きく広がっていきます。