関数
概要
関数とは固有の処理を実行するための命令群のことです。 関数にある値を与えると固有の処理を実行し、その結果を返してくれます。 関数に与える値を引数、処理の結果として返ってくる値を戻り値といいます。
関数を定義する
関数の機能を実装することを関数を定義するといいます。 まず関数の基本的な形について説明したいと思います。書式
書式例
戻り値の型 関数名(引数) { return 戻り値; // 戻り値の型が設定されていれば必要 }![]()
具体例
int Add(int a, int b) { return (a + b); } 上の具体例の関数は2つの引数の値の合計を返す関数を定義しており、 この関数を各パーツ毎に分解すると以下のようになります。 戻り値の型:int 関数名:Add 引数:int a, int b 戻り値:(a + b)
戻り値なし、引数なし
関数の定義は戻り値や引数がなくても行うことが可能です。 printfも戻り値がない関数になります。 戻り値、引数がない場合はvoidを使用します。 voidというのは「空の」という意味で「何もない」型として使用されています。具体例
// 名前を表示する関数 void PrintPlayerName(void) { printf("Nakachi"); } voidは戻り値がないので、return文を書く必要はありません。 また、引数に記述しているvoidは省略可能です。 省略した場合は「void PrintPlayerName();」となります。 戻り値の型は省略できないので、気をつけてください。
関数の呼び出し
定義した関数はソースコード内で使用することで価値を発揮します。 関数を使用することを「関数呼び出し」と呼びます。書式
書式例
関数名(値);具体例
#include <stdio.h> int Add(int a, int b) { int ret = a + b; return ret; } int main(void) { int sum = 0; sum = Add(2, 3); printf("戻り値は%d\n", sum); return 0; } 実行結果: 戻り値は5![]()
注意点
関数を呼び出し時の「関数名と()内の値の型と値の数」は呼び出し側の関数と 一致している必要があります。例
関数仕様
関数名: Add 戻り値の型: int 引数: int val1 int val2 内容: val1とval2の足し算の結果を返す具体例
// 定義 int Add(int val1, int val2) { return (val1 + val2); } int main(void) { int x = 1; int y = 10; int z = 100; // 問題なし int sum01 = Add(x, y); // 問題あり int sum02 = Add(x, y, z); return 0; }問題点
Add関数の引数は以下の通りです。 int val1 int val2 引数の数 => 2 第1引数の型 => int 第2引数の型 => int 具体例のコードでは2回Addを呼び出しています。 1度目: 指定している値の数 => 2 1つ目の値の型 => int 2つ目の値の型 => int 2度目: 指定している値の数 => 3 1つ目の値の型 => int 2つ目の値の型 => int 3つ目の値の型 => int 関数の引数と呼び出し側の値をすり合わせてみます。 1度目と引数の数: 引数の数 => 2 第1引数の型 => int 第2引数の型 => int 指定している値の数 => 2 1つ目の値の型 => int 2つ目の値の型 => int 2度目と引数の数 引数の数 => 2 第1引数の型 => int 第2引数の型 => int 指定している値の数 => 3 1つ目の値の型 => int 2つ目の値の型 => int 3つ目の値の型 => int 1度目の呼び出しは引数の数としている値の数が一致しており、 2度目の呼び出しは引数の数が1つ多く関数と一致していないので エラーとなります。 関数呼び出しは引数と呼び出し側の情報を必ずあわせてください。
プロトタイプ宣言
プロトタイプ宣言は関数の戻り値の型、関数名、引数を定義の前に宣言することです。 なぜ宣言をする必要があるかというと宣言を行っていない場合、 関数を定義した場所と呼び出した場所の関係次第でエラーが発生することがあります。エラーが発生する理由
ソースコードをオブジェクトファイルに変換する時は コンパイラはソースの上から下へ変換していきます。 その変換途中にユーザー関数の呼び出し命令文があった場合 その関数がどういった内容(戻り値の型、関数名、引数)か分かっていないと 翻訳不能な文字列として扱われエラーになります。エラーが出るケース
#include <stdio.h> int main(void) { int num = Add(10, 20); printf("戻り値は%d\n", num); return 0; } int Add(int a, int b) { int ret = a + b; return ret; }エラーが出ないケース
#include <stdio.h> int Add(int a, int b) { int ret = a + b; return ret; } int main(void) { int num = Add(10, 20); printf("戻り値は%d\n", num); return 0; } 上の具体例の違いはユーザー関数(Add)の呼び出し箇所が 定義の前か後ろかという所だけです。 ソースコードを上から変換していく中でコンパイラは main関数内でAddという関数があることを認識します。 この時にAddの定義または宣言を確認しているかどうかを判断します。 エラーが出るソースはAddの後ろに定義がありますので、 Addの呼び出しを確認した時はこの関数を認識していません。 逆にエラーが出ないソースはAddの前に定義がありますので、 呼び出しの際はこの関数を認識できています。 この違いがエラーという形になって現れています。 全ての関数を使用箇所の前に定義することで問題は解決しますが、 それを実行するのは現実的ではありません。 なので、先に関数の基本情報を宣言してコンパイラに関数を 認識させてエラーを回避します。プロトタイプ宣言の書式
プロトタイプ宣言には戻り値の型、関数名、引数情報が必要です。書式例
戻り値の型 関数名(引数情報);具体例
int Add(int, int); ※プロトタイプ宣言の引数情報は型情報だけで問題ありません。プロトタイプ宣言の注意点
プロトタイプ宣言の内容と定義する関数の内容は 完全に一致させる必要があります。 例えばプロトタイプ宣言でint Add(int, int)と宣言した場合は 定義でもint Add(int a, int b)とコーディングする必要があります。 戻り値の型、関数名、引数情報のひとつでも違いがあった場合は 別の関数として認識されますので、エラーの原因となります。
標準ライブラリ関数とユーザー関数
関数の種類には標準ライブラリ関数とユーザー関数があります。 標準ライブラリ関数は各言語が開発サポートのために用意している関数です。 printfはC言語が提供している標準ライブラリ関数となります。 ユーザー関数はプログラマーが独自で作成した関数で、 戻り値の型や処理内容は全て自分で決めれます。 ユーザー関数はユーザー定義関数とも呼ばれています。
