関数

概要

関数とは固有の処理を実行するための命令群のことです。
関数にある値を与えると固有の処理を実行し、その結果を返してくれます。
関数に与える値を引数、処理の結果として返ってくる値を戻り値といいます。

関数を定義する

関数の機能を実装することを関数を定義するといいます。
まず関数の基本的な形について説明したいと思います。

書式

書式例

戻り値の型 関数名(引数) { return 戻り値; // 戻り値の型が設定されていれば必要 } C_0014

具体例

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 C_0039

注意点

関数を呼び出し時の「関数名と()内の値の型と値の数」は呼び出し側の関数と 一致している必要があります。

関数仕様

関数名: 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言語が提供している標準ライブラリ関数となります。
ユーザー関数はプログラマーが独自で作成した関数で、
戻り値の型や処理内容は全て自分で決めれます。
ユーザー関数はユーザー定義関数とも呼ばれています。