対象 | C言語初心者 |
記事概要 | C言語の関数について記載しています。 |
筆者 | Zuu [ ] C言語歴20年以上。 大手電機メーカーでの製品開発およびマネジメント経験がある現役エンジニアです。 プロジェクトマネージャ、システムアーキテクトなどの資格を保有しています。 |
はじめに
第1回の「最小のプログラム」で紹介したmain関数も含めて、C言語によるプログラムは関数を使って作り上げていくといっても過言ではありません。
ゆえに、関数はC言語における最重要機能と言えるでしょう。しっかりマスターしましょう。
※最難関は次回説明する「ポインタ」となります。
関数とは?
関数とは、コンピュータプログラム上で定義されるサブルーチンの一種で、数学の関数のように与えられた値(引数)を元に何らかの計算や処理を行い、結果を呼び出し元に返すもののこと。
理解しておきたいポイントは以下の2点です。
- 与えられた値を元に何らかの計算や処理を行う。
- 結果を呼び出し元に返す。
サブルーチンの定義は以下の通りです。
サブルーチン(英: subroutine)は、コンピュータプログラミングにおいて、プログラム中で意味や内容がまとまっている作業をひとつの手続きとしたものである。繰り返し利用されるルーチン作業をモジュールとしてまとめたもので、呼び出す側の「主」となるもの(メインルーチン)と対比して「サブルーチン」と呼ばれる。サブプログラム (subprogram) と呼ばれることもある。また、「サブ」をつけずに「ルーチン」と呼ぶこともある。
「意味や内容がまとまっている作業をひとつの手続きとしたもの」という箇所が重要です。なるべく1つの関数に1つの意味だけ持たせるように関数を作っていくと良いプログラムになります。
C言語での関数の扱い方
関数の形
関数は、以下のような形を取ります。
「戻り値、半角スペース、名前、左括弧、引数、右括弧」
main関数を例に見てみましょう。
1 2 3 |
int main(void) { return 0; } |
- 戻り値:int
- 名前:main
- 引数:void
戻り値とは関数が返す結果のこと、引数とは関数に与える値のことです。詳細については後述します。
名前については、mainやprintfなどあらかじめ定義されているものを除き、自由につけることが出来ます。関数内の処理の意味や内容に合わせて適切な名前をつけるように心がけましょう。変数と同じですね。
基本的な使い方
関数は、main関数の前後どちらに定義するかによって、少しだけお作法が違います。
まずは、main関数の前に定義する場合の例です。
1 2 3 4 5 6 7 8 9 10 11 |
#include <stdio.h> void func(void) { printf("func() is called\n"); } int main(void) { printf("Hello, World!\n"); func(); return 0; } |
続いて、main関数の後に定義する場合の例です。
関数の名前などを予め宣言しておく「プロトタイプ宣言」が必要となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <stdio.h> /* プロトタイプ宣言 */ void func(void); int main(void) { printf("Hello, World!\n"); func(); return 0; } void func(void) { printf("func() is called\n"); } |
関数の処理結果を呼び出し元に返す方法
関数の処理結果を呼び出し元に返すには、「return 文」を使用します。
return文で返す値は、戻り値の型と一致している必要があります。もちろん、変数の値を返すこともできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <stdio.h> /* プロトタイプ宣言 */ int func(void); int main(void) { int result; /* 処理結果を受け取る */ result = func(); printf("result = %d\n", result); /* if文内でも使用可能 */ if (func() == 123) { printf("func() is called\n"); } /* 代入と分岐を一緒に記述可能 */ if ((result = func()) == 123) { printf("func() is called\n"); printf("result = %d\n", result); } return 0; } int func(void) { return 123; } |
関数に値を与える方法(引数)
関数の括弧内に値を記述することで、関数に対して値を与えることができます。
引数の個数や型は、関数の定義と合っていなければなりません。
関数の定義と違う使い方をしてしまうと、コンパイルエラーになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <stdio.h> /* プロトタイプ宣言 */ int func(int a, int b); int main(void) { int result; /* 処理結果を受け取る */ result = func(10, 5); printf("result = %d\n", result); /* if文内でも使用可能 */ if (func(10, 5) == 15) { printf("func() is called\n"); } /* 代入と分岐を一緒に記述可能 */ if ((result = func(10, 5)) == 15) { printf("func() is called\n"); printf("result = %d\n", result); } return 0; } int func(int a, int b) { return (a + b); } |
補足情報になりますが、func関数内で使用している「a、b」のことを仮引数、func関数に与えている「10、5」のことを実引数と言います。
その他に覚えておきたいこと
※次回説明する「ポインタ」に関連するので、最初は読み飛ばしてもらって、また後で読むというのでも構いません。
戻り値以外で結果を返す方法
関数が結果を返す方法として戻り値について説明してきましたが、結果を返す方法は戻り値以外にもあります。
それは、次回説明する「ポインタ」を使用する方法です。ポインタを使用すると、引数を入力から出力に変更することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <stdio.h> /* プロトタイプ宣言 */ void func(int a, int b, int *r); int main(void) { int result; /* 処理結果を出力引数で受け取る */ func(10, 5, &result); printf("result = %d\n", result); return 0; } void func(int a, int b, int *r) { *r = (a + b); /* 出力引数に処理結果を記憶 */ } |
関数ポインタ
ポインタは変数のみでなく、関数に対しても使うことができます。
関数ポインタを使うと、呼び出す関数を動的に変更することが可能となります。関数ポインタは、関数の型(戻り値と引数)が同じ関数に対して利用可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include <stdio.h> /* プロトタイプ宣言 */ int func(int a, int b, int (*f)(int, int)); int add(int a, int b); int sub(int a, int b); int mul(int a, int b); int main(void) { int result; /* 関数ポインタを使用して足し算 */ result = func(10, 5, add); printf("result = %d\n", result); /* 関数ポインタを使用して引き算 */ result = func(10, 5, sub); printf("result = %d\n", result); /* 関数ポインタを使用して掛け算 */ result = func(10, 5, mul); printf("result = %d\n", result); return 0; } int func(int a, int b, int (*f)(int, int)) { if (f != NULL) { return f(a, b); /* 関数ポインタを使って関数呼び出し */ } } int add(int a, int b) { return (a + b); } int sub(int a, int b) { return (a - b); } int mul(int a, int b) { return (a * b); } |
正直、上の例だけでは何が便利なの?と思うかもしれませんね。実際のソフトウェア開発では、主に以下の2点で使用されます。
- 別のモジュールの関数を呼び出したい場合
- テストなどで、大量の関数を呼び出したい場合
詳細については、別の記事で紹介します。しばらくお待ちください。
まとめ
- 意味や内容がまとまっている作業をひとつの手続きとしたもの。
- 繰り返し利用されるルーチン作業を関数にすると良い。
- 値を与えることができ、値を返すことができる(引数と戻り値)。
- ポインタを使って出力引数にすると、戻り値以外でも処理結果を受け取れる。
- 関数ポインタを使うと、呼び出す関数を動的に変更することができる。
コメント