関数

■関数とは

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

■関数を定義する

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

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

		具体例:
			int addSum(int a, int b)
			{
				return (a + b);
			}
	
	上の具体例の関数は2つの引数の値の合計を返す関数を定義しており、
	この関数を各パーツ毎に分解すると以下のようになります。
		戻り値の型:int
		関数名:addSum
		引数:int a, int b
		戻り値:(a + b)

■戻り値なし、引数なし

	関数の定義は戻り値や引数がなくても行うことが可能です。
	printfも戻り値がない関数になります。
	戻り値、引数がない場合はvoidを使用します。
	voidというのは「空の」という意味で「何もない」型として使用されています。
		具体例:
			// 名前を表示する関数
			void printPlayerName(void)
			{
				printf("Nakati");
			}
	
	voidは戻り値がないので、return文を書く必要はありません。
	また、引数に記述しているvoidは省略可能です。
	省略した場合は「void printPlayerName();」となります。
	戻り値の型は省略できないので、気をつけてください。

■関数の呼び出し

	定義した関数はソースコード内で使用することで価値を発揮します。
	関数を使用することを「関数呼び出し」と呼びます。

	●書式
		・書式例
			関数名(値);

		・具体例
			#include <sdtio.h>

			int addSum(int a, int b)
			{
				int ret = a + b;
				return ret;
			}

			void main(void)
			{
				int sum = 0;
				sum = addSum(2, 3);
				printf("戻り値は%d\n", sum);
			}

			実行結果:
				戻り値は5

		C_0039

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

	●例
		・関数仕様
			関数名:
				AddSum

			戻り値の型
				int

			引数:
				int val1
				int val2

			内容:
				val1とval2の足し算の結果を返す

		・具体例
			// 定義
			int AddSum(int val1, int val2)
			{
				return (val1 + val2);
			}

			void main(void)
			{
				int x = 1;
				int y = 10;
				int z = 100;

				// 問題なし
				int sum01 = AddSum(x, y);

				// 問題あり
				int sum02 = AddSum(x, y, z);
			}

		・問題点
			AddSum関数の引数は以下の通りです。
				int val1
				int val2

				引数の数 => 2
					第1引数の型 => int
					第2引数の型 => int

			具体例のコードでは2回AddSumを呼び出しています。
				1度目:
					指定している値の数 => 2
						1つ目の値の型 => int
						2つ目の値の型 => int

				2度目:
					指定している値 => 3
						1つ目の値の型 => int
						2つ目の値の型 => int
						3つ目の値の型 => int

			関数の引数と呼び出し側の値をすり合わせてみます。
				1度目と引数の数
					引数の数 => 2
						第1引数の型 => int
						第2引数の型 => int
					1度目:
						指定している値の数 => 2
							1つ目の値の型 => int
							2つ目の値の型 => int

				2度目と引数の数
					引数の数 => 2
						第1引数の型 => int
						第2引数の型 => int
					2度目:
						指定している値の数 => 3
							1つ目の値の型 => int
							2つ目の値の型 => int
							3つ目の値の型 => int

			2度目の呼び出しは引数の数が1つ多く関数と一致していないので、
			エラーになります。
			関数呼び出しは引数と呼び出し側の情報を必ずあわせてください。
			
	

■プロトタイプ宣言

	プロトタイプ宣言は関数の戻り値の型、関数名、引数を定義の前に宣言することです。
	なぜ宣言をする必要があるかというと宣言を行っていない場合、
	関数を定義した場所と呼び出した場所の関係次第でエラーが発生することがあります。

	●エラーが発生する理由
		ソースコードをオブジェクトファイルに変換する時は
		コンパイラはソースの上から下へ変換していきます。
		その変換途中にユーザー関数の呼び出し命令文があった場合
		その関数がどういった内容(戻り値の型、関数名、引数)か分かっていないと
		翻訳不能な文字列として扱われエラーになります。

		エラーが出るケース:
			#include <stdio.h>

			void main(void)
			{
				int num = addSum(10, 20);
				printf("戻り値は%d\n", num);
			}

			int addSum(int a, int b)
			{
				int ret = a + b;
				return ret;
			}

		エラーが出ないケース:
			#include <stdio.h>

			int addSum(int a, int b)
			{
				int ret = a + b;
				return ret;
			}

			void main(void)
			{
				int num = addSum(10, 20);
				printf("戻り値は%d\n", num);
			}

		上の具体例の違いはユーザー関数(addSum)の呼び出し箇所が
		定義の前か後ろかという所だけです。
		ソースコードを上から変換していく中でコンパイラは
		main関数内でaddSumという関数があることを認識します。
		この時にaddSumの定義または宣言を確認しているかどうかを判断します。
		エラーが出るソースはaddSumの後ろに定義がありますので、
		addSumの呼び出しを確認した時はこの関数を認識していません。
		逆にエラーが出ないソースはaddSumの前に定義がありますので、
		呼び出しの際はこの関数を認識できています。
		この違いがエラーという形になって現れています。

		全ての関数を使用箇所の前に定義することで問題は解決しますが、
		それを実行するのは現実的ではありません。
		なので、先に関数の基本情報を宣言してコンパイラに関数を
		認識させてエラーを回避します。

	●プロトタイプ宣言の書式
		プロトタイプ宣言には戻り値の型、関数名、引数情報が必要です。

		書式例:
			戻り値の型 関数名(引数情報);

		具体例:
			int addSum(int, int);

		※プロトタイプ宣言の引数情報は型情報だけで問題ありません。

	●プロトタイプ宣言の注意点
		プロトタイプ宣言の内容と定義する関数の内容は
		完全に一致させる必要があります。
		例えばプロトタイプ宣言でint addnum(int, int)と宣言した場合は
		定義でもint addnum(int a, int b)とコーディングする必要があります。
		戻り値の型、関数名、引数情報のひとつでも違いがあった場合は
		別の関数として認識されますので、エラーの原因となります。

■標準ライブラリ関数とユーザー関数

	関数の種類には標準ライブラリ関数ユーザー関数があります。
	標準ライブラリ関数は各言語が開発サポートのために用意している関数です。
	printfはC言語が提供している標準ライブラリ関数となります。
	ユーザー関数はプログラマーが独自で作成した関数で、
	戻り値の型や処理内容は全て自分で決めれます。
	ユーザー関数はユーザー定義関数とも呼ばれています。