6日でできる 新C言語入門|関数の基本と作り方

処理に名前をつければ、プログラムはもっと読みやすくなる。
関数を使って、くり返し使う処理を小さな部品として整理しよう。

C言語でプログラムを書いていると、同じような処理を何度も書く場面があります。たとえば、複数の商品価格から税込価格を求めたい場合や、いくつかの数値について同じ計算を行いたい場合です。

そのたびに同じ計算式を書くこともできますが、同じ処理が増えるほどプログラムは長くなり、読みづらくなります。また、あとから計算方法を変えたいときに、複数の場所を修正しなければならず、修正漏れの原因にもなります。

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

関数とは、ひとまとまりの処理に名前をつけて、必要なときに呼び出せるようにしたものです。C言語では、printfやscanfのように標準で用意されている関数を使うだけでなく、自分で関数を作ることもできます。

自分で作った関数は、自作関数と呼ばれます。自作関数を使うと、よく使う処理を1か所にまとめられます。処理をまとめることで、プログラムの見通しが良くなり、再利用もしやすくなります。

この記事では、関数とは何か、関数を使わない場合と使う場合の違い、関数の基本構文、引数と戻り値の考え方、関数の代表的なパターンまで、サンプルプログラムを使ってやさしく解説していきます。

関数は処理をまとめるための仕組み

関数は、処理に名前をつけて、あとから呼び出せるようにする仕組みです。

たとえば、税込価格を求める処理が何度も必要になる場合、その計算を関数にしておくと、必要な場所で関数名を書くだけで同じ処理を使えます。

関数を使うと、次のようなメリットがあります。

メリット内容
同じ処理をまとめられる何度も同じコードを書かなくてよい
読みやすくなる関数名を見るだけで処理の目的が分かりやすい
修正しやすくなる処理内容を1か所で管理できる
再利用しやすい別の場所でも同じ関数を呼び出せる
プログラムを分割できる大きな処理を小さな部品に分けられる

関数は、プログラムを部品化するための大切な考え方です。処理を小さな単位に分けることで、全体の流れがつかみやすくなります。

関数を使わない場合の例

まずは、関数を使わずに同じような計算を複数回書く例を見てみましょう。

次のプログラムでは、3つの商品価格について、税込価格をそれぞれ計算しています。

プロジェクト/ファイル名: Lesson37_1/main.c

#include <stdio.h>

int main(void) {
    int price1 = 1200;
    int price2 = 2500;
    int price3 = 3600;

    int taxPrice1;
    int taxPrice2;
    int taxPrice3;

    // それぞれの商品価格に10%の消費税を加える
    taxPrice1 = price1 + price1 * 10 / 100;
    taxPrice2 = price2 + price2 * 10 / 100;
    taxPrice3 = price3 + price3 * 10 / 100;

    printf("商品1の税込価格: %d円\n", taxPrice1);
    printf("商品2の税込価格: %d円\n", taxPrice2);
    printf("商品3の税込価格: %d円\n", taxPrice3);

    return 0;
}

実行結果

商品1の税込価格: 1320円
商品2の税込価格: 2750円
商品3の税込価格: 3960円

このプログラムでは、税込価格を求める計算が3回出てきます。

price + price * 10 / 100

今は3回だけなので大きな問題には見えないかもしれません。しかし、商品が10個、20個と増えた場合、同じような計算を何度も書くことになります。

また、消費税率を変更したい場合は、すべての計算式を修正する必要があります。こうした重複した処理は、関数としてまとめると扱いやすくなります。

図:関数を使うと同じ処理を1つにまとめられる

この図から分かること

この図から分かるのは、関数を使うと同じ処理を何度も書かずに済むということです。

同じ計算式を複数の場所に書くと、プログラムが長くなり、修正も大変になります。関数にまとめておけば、処理内容は1か所に集まり、呼び出す側は関数名を使って簡単に処理を実行できます。

関数で処理をまとめる

次に、税込価格を計算する処理を関数としてまとめてみましょう。

プロジェクト/ファイル名: Lesson37_2/main.c

#include <stdio.h>

// 商品価格に10%の消費税を加えた金額を返す関数
int calcTaxPrice(int price) {
    int result;

    result = price + price * 10 / 100;

    return result;
}

int main(void) {
    int price1 = 1200;
    int price2 = 2500;
    int price3 = 3600;

    int taxPrice1;
    int taxPrice2;
    int taxPrice3;

    // 関数を呼び出して税込価格を計算する
    taxPrice1 = calcTaxPrice(price1);
    taxPrice2 = calcTaxPrice(price2);
    taxPrice3 = calcTaxPrice(price3);

    printf("商品1の税込価格: %d円\n", taxPrice1);
    printf("商品2の税込価格: %d円\n", taxPrice2);
    printf("商品3の税込価格: %d円\n", taxPrice3);

    return 0;
}

実行結果

商品1の税込価格: 1320円
商品2の税込価格: 2750円
商品3の税込価格: 3960円

このプログラムでは、税込価格を計算する処理をcalcTaxPriceという関数にまとめています。

int calcTaxPrice(int price) {
    int result;

    result = price + price * 10 / 100;

    return result;
}

この関数は、priceという整数を受け取り、10%の消費税を加えた金額を返します。

main関数では、次のように関数を呼び出しています。

taxPrice1 = calcTaxPrice(price1);

この1行で、price1を関数へ渡し、計算結果をtaxPrice1に代入しています。

関数を使うことで、税込価格の計算式を何度も書かなくてよくなりました。もし計算方法を変更したい場合も、calcTaxPriceの中だけを修正すれば済みます。

関数の基本構文

C言語で関数を定義するときは、基本的に次の形で書きます。

戻り値の型 関数名(引数の型 引数名) {
    処理内容
    return 戻り値;
}

たとえば、2つの整数を足して結果を返す関数は次のように書けます。

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

関数の構成要素を整理すると、次のようになります。

項目内容
戻り値の型関数が返す値の型。例としてint、double、voidなど
関数名関数を呼び出すときに使う名前
引数関数へ渡す値。複数ある場合はカンマで区切る
処理内容関数の中で行う計算や表示など
return文呼び出し元へ値を返すために使う

戻り値がある関数では、returnを使って結果を返します。戻り値がない関数では、戻り値の型にvoidを使います。

引数は関数へ渡す値

引数とは、関数に渡す値のことです。

たとえば、次の関数を見てみましょう。

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

この関数には、aとbという2つの引数があります。関数を呼び出すときに、次のように値を渡します。

result = add(7, 11);

この場合、aには7、bには11が渡されます。そして、関数の中でa + bを計算し、その結果を返します。

用語役割
引数関数へ渡す値
仮引数関数定義側で受け取る変数
実引数関数呼び出し側で渡す値

学習段階では、関数の中で使う材料が引数だと考えると分かりやすいです。

戻り値は関数から返ってくる結果

戻り値とは、関数の処理結果として呼び出し元へ返す値のことです。

たとえば、合計を計算する関数では、計算結果を戻り値として返します。

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

この関数を呼び出すと、戻り値を変数に代入できます。

total = add(7, 11);

ここでは、add関数の戻り値がtotalに代入されます。

戻り値がある関数では、関数名の前に戻り値の型を書きます。戻り値が整数ならint、小数ならdoubleのように指定します。戻り値がない場合はvoidを指定します。

図:引数と戻り値の流れ

この図から分かること

この図から分かるのは、関数には外から値を渡し、処理結果を受け取る流れがあるということです。

引数は、関数へ渡す材料のようなものです。関数はその値を使って計算や処理を行い、必要であれば戻り値として結果を返します。この流れを理解すると、自作関数の作り方が分かりやすくなります。

引数と戻り値を使った関数

次のプログラムでは、2つの整数の合計を求める関数を作ります。

プロジェクト/ファイル名: Lesson37_3/main.c

#include <stdio.h>

// 2つの整数を足した結果を返す関数
int add(int x, int y) {
    int total;

    total = x + y;

    return total;
}

int main(void) {
    int result;

    // add関数に2つの値を渡し、戻り値を受け取る
    result = add(9, 14);

    printf("合計値は %d です。\n", result);

    return 0;
}

実行結果

合計値は 23 です。

このプログラムでは、add関数を定義しています。

int add(int x, int y)

この部分を見ると、関数の特徴が分かります。

部分意味
int戻り値の型
add関数名
int x, int y2つの引数
return total;合計値を返す

main関数では、次のように呼び出しています。

result = add(9, 14);

9と14がadd関数へ渡され、関数の中で合計が計算されます。その戻り値がresultに代入されます。

関数を呼び出す側は、計算の中身を毎回書く必要がありません。関数名を使って、何をしたいのかを表現できます。

関数を作る位置

C言語では、関数を呼び出す前に、その関数の情報が分かっている必要があります。

今回のサンプルでは、add関数をmain関数より前に書いています。

int add(int x, int y) {
    return x + y;
}

int main(void) {
    int result = add(9, 14);
    return 0;
}

このように、main関数より前に自作関数を書いておくと、main関数の中でその関数を呼び出せます。

別の書き方として、関数プロトタイプ宣言を使う方法もあります。

int add(int x, int y);

int main(void) {
    int result = add(9, 14);
    return 0;
}

int add(int x, int y) {
    return x + y;
}

関数プロトタイプ宣言は、このような関数がありますよと先に知らせるための宣言です。学習の最初は、自作関数をmain関数より前に書くと理解しやすいです。

引数なし・戻り値なしの関数

関数には、引数も戻り値もない形があります。

この形は、決まったメッセージを表示する、画面の見出しを表示する、初期案内を出すといった処理に向いています。

プロジェクト/ファイル名: Lesson37_4/main.c

#include <stdio.h>

// 学習開始のメッセージを表示する関数
void showStartMessage(void) {
    printf("関数の学習を始めましょう。\n");
    printf("よく使う処理をまとめると、プログラムが読みやすくなります。\n");
}

int main(void) {
    // 引数なし、戻り値なしの関数を呼び出す
    showStartMessage();

    return 0;
}

実行結果

関数の学習を始めましょう。
よく使う処理をまとめると、プログラムが読みやすくなります。

この関数は、外から値を受け取りません。そのため、引数の部分にvoidを書いています。

void showStartMessage(void)

また、値を返さないため、戻り値の型もvoidです。

このような関数は、表示処理や決まった処理をまとめるときに使いやすいです。

引数あり・戻り値なしの関数

次に、引数はあるけれど戻り値はない関数を見てみましょう。

この形は、値を受け取って、その値を使って表示するような処理に向いています。

プロジェクト/ファイル名: Lesson37_5/main.c

#include <stdio.h>

// 受け取った点数に応じてメッセージを表示する関数
void showScoreMessage(int score) {
    printf("点数は %d 点です。\n", score);

    if (score >= 80) {
        printf("よくできました。\n");
    } else {
        printf("復習して次につなげましょう。\n");
    }
}

int main(void) {
    // 点数を関数へ渡してメッセージを表示する
    showScoreMessage(86);

    return 0;
}

実行結果

点数は 86 点です。
よくできました。

この関数は、scoreという引数を受け取ります。

void showScoreMessage(int score)

戻り値の型はvoidなので、計算結果を呼び出し元へ返すわけではありません。関数の中でprintfを使い、受け取った点数に応じたメッセージを表示しています。

引数あり・戻り値なしの関数は、受け取った値をもとに画面表示や処理を行いたい場合に便利です。

引数なし・戻り値ありの関数

引数を受け取らず、戻り値だけを返す関数もあります。

この形は、決まった値を返す、現在の設定値を返す、初期値を返すといった処理で使えます。

プロジェクト/ファイル名: Lesson37_6/main.c

#include <stdio.h>

// 基準点を返す関数
int getPassScore(void) {
    return 60;
}

int main(void) {
    int passScore;

    // 関数から基準点を受け取る
    passScore = getPassScore();

    printf("合格の基準点は %d 点です。\n", passScore);

    return 0;
}

実行結果

合格の基準点は 60 点です。

この関数は、引数を受け取りません。

int getPassScore(void)

しかし、戻り値として60を返します。

return 60;

main関数では、その戻り値をpassScoreに代入しています。

passScore = getPassScore();

引数なし・戻り値ありの関数は、外から値を受け取らなくても、決まった結果や設定値を返したいときに使えます。

関数のパターンを整理する

関数は、引数の有無と戻り値の有無によって、いくつかのパターンに分けられます。

パターン向いている処理
引数あり・戻り値ありint add(int x, int y)計算結果を返す処理
引数なし・戻り値なしvoid showStartMessage(void)決まった表示を行う処理
引数あり・戻り値なしvoid showScoreMessage(int score)値を受け取って表示する処理
引数なし・戻り値ありint getPassScore(void)決まった値を返す処理

関数を作るときは、まず次の2つを考えると整理しやすくなります。

考えること内容
関数に渡す値はあるかあるなら引数を使う
関数から返したい結果はあるかあるなら戻り値を使う

この2つを考えることで、どの形の関数にすればよいか判断しやすくなります。

図:関数の4つの基本パターン

この図から分かること

この図から分かるのは、関数には引数と戻り値の有無によって複数の形があるということです。

引数は関数へ渡す入力、戻り値は関数から返ってくる出力として考えると整理しやすくなります。計算結果を返したい場合は戻り値を使い、表示だけでよい場合は戻り値なしの関数にするなど、目的に合わせて関数の形を選びます。

関数名は処理内容が分かる名前にする

関数を作るときは、関数名も大切です。関数名を見るだけで、何をする関数なのか分かるようにすると、プログラムが読みやすくなります。

たとえば、次のような名前は処理内容が伝わりやすいです。

関数名意味
calcTaxPrice税込価格を計算する
add加算する
showScoreMessage点数に応じたメッセージを表示する
getPassScore合格基準点を取得する

反対に、func1やtestのような名前だけでは、何をする関数なのか分かりにくい場合があります。

関数名は、できるだけ動作や目的が分かる名前にしましょう。

return文の役割

returnは、関数から呼び出し元へ値を返すために使います。

int add(int x, int y) {
    return x + y;
}

この場合、x + yの結果が呼び出し元へ返されます。

また、returnが実行されると、その関数の処理はそこで終了します。

int checkScore(int score) {
    if (score < 0) {
        return 0;
    }

    return 1;
}

この例では、scoreが0未満なら0を返して関数を終了します。そうでなければ1を返します。

戻り値がvoidの関数でも、処理を途中で終わらせたい場合にreturnを使うことがあります。

void showMessage(int count) {
    if (count <= 0) {
        return;
    }

    printf("メッセージを表示します。\n");
}

この場合、returnの後ろに値は書きません。戻り値がない関数だからです。

関数を使うとプログラムの見通しがよくなる

関数を使うと、main関数の中がすっきりします。

すべての処理をmain関数の中に書くと、プログラムが長くなり、どこで何をしているのか分かりにくくなります。

処理を関数に分けると、main関数では全体の流れを読みやすくできます。

showStartMessage();
taxPrice = calcTaxPrice(price);
showScoreMessage(score);

このように関数名が並ぶと、プログラムが何をしているのかが読み取りやすくなります。

関数の中身を詳しく見たいときは、その関数の定義を確認すればよいので、全体の流れと細かい処理を分けて考えられます。

関数を作るときの注意点

関数を作るときは、次の点に注意しましょう。

戻り値の型とreturnの値を合わせる

戻り値の型がintなら、returnで返す値も整数にします。戻り値の型がdoubleなら、小数を返せます。

引数の型を正しく指定する

関数に渡す値の型に合わせて、引数の型を決めます。整数を受け取るならint、小数を受け取るならdoubleを使います。

関数名は分かりやすくする

関数名を見るだけで、何をする関数か分かるようにしましょう。

1つの関数に多くの役割を詰め込みすぎない

関数は、1つの目的に絞ると使いやすくなります。計算する関数、表示する関数、値を取得する関数のように役割を分けると読みやすくなります。

関数を呼び出す前に定義または宣言しておく

C言語では、関数を呼び出す前に、その関数の戻り値の型や引数が分かっている必要があります。main関数より前に定義するか、関数プロトタイプ宣言を使いましょう。

関数を使いこなすとプログラムを部品化できる

関数は、処理をひとまとまりの部品として扱うための仕組みです。よく使う処理に名前をつけておけば、必要な場所で何度でも呼び出せます。

関数を作るときは、戻り値の型、関数名、引数、処理内容、return文を意識します。引数は関数へ渡す値であり、戻り値は関数から返ってくる結果です。

また、関数にはいくつかの形があります。引数あり・戻り値ありの関数は計算処理に向いています。引数なし・戻り値なしの関数は決まった表示に向いています。引数あり・戻り値なしの関数は受け取った値をもとに処理したいときに便利です。引数なし・戻り値ありの関数は決まった値を返したい場合に使えます。

関数を使えるようになると、プログラムを小さな部品に分けて考えられるようになります。これにより、同じ処理の重複を減らし、読みやすく、修正しやすいプログラムを書けるようになります。