パート3:自分で関数を作り利用する
 先のパートで予告したように、コンピュータらしい事をやってみましょう。
3の階乗

 を計算してみます。
 階乗は、例えば3の階乗の場合なら
3 x 2 x 1

 というように、最初の値から一つ引いたものを掛け合わせる事を、値が1になるまで 繰り返す計算でしたね。
 C言語で、3の階乗の結果を画面に出力する処理を記述するなら以下のようになります。
int main (int argc, const char * argv[])
{
int result; ← 変数の確保。
result = 3 * 2 * 1; ← 変数への代入。
printf("factorial 3 =%d\n", result);
return 0;
}

サンプルプロジェクト:study-5-factorial3.zip

変数宣言
 まずは、3の階乗の結果を格納するメモリ区画を確保しています。
int result; ← ひとつの処理単位なので「;」(セミコロン)で区切ります。

 記述法は引数の時と同じです。このようにして確保したメモリ区画を変数、上記記述を変数宣言と呼びます。

テン*シー*シー-1

ローカル変数
 上述のサンプルプログラムのように関数内で変数宣言をした場合、メモリ区画はスタック領域の引数の上に積み重ねられ、関数(この場合main)から戻った時に取りはぶかれます。
 そのため、この場合の変数は、関数内でだけ有効という事になり、ローカル(局所)変数などと呼ばれます。関数から戻る時に自動的に消えるのでauto(自動)変数とも呼ばれます。

テン*シー*シー-2


 例えば以下のように、3の階乗計算のための関数factorialを用意し、こちらでもresultという変数を宣言した場合
int factorial(void)
{
int result; ← 変数宣言。factorial関数内のローカル変数となる。
result = 3 * 2 * 1;
return result;
}

int main (int argc, const char * argv[])
{
int result; ← 変数宣言。main関数内のローカル変数となる。
result = factorial();
printf("factorial 3 =%d\n", result);
return 0;
}

サンプルプロジェクト:study-6-factorial-f.zip

 2つのresultは、スタック領域にそれぞれ確保され、まったく別のものになります。

テン*シー*シー-3


 ところで、factorial関数を記述すると、ウィンドウの端には注意マークが表示される事に気づきましたか?
 これはコンパイラからの注意です。

テン*シー*シー-4

 注意マークをクリックすると、詳細が表示されます。

テン*シー*シー-5

 factorial関数の関数宣言(分割コンパイルのところで紹介)が無いという注意で「factorial関数の呼び出し方に対する情報(関数宣言)がないので、CPUが記述どうりに動いた時、正しく動作できるか保証できない。」と言うわけです。
 以下のようにfactorial関数の関数宣言をおこなう事で、コンパイラがfactorial関数の呼び出しに間違いがない事を確認でき、この注意は消えます。
int factorial(void); ← 関数宣言

int factorial(void)
{
int result;
result = 3 * 2 * 1;
return result;
}

サンプルプロジェクト:study-7-factorial-def.zip

static
 もし、factorial関数を別のソースコードファイル(分割コンパイル)で使う気がないのなら、関数にstaticを付ける事で、関数宣言をしなくてもコンパイラは注意してこなくなります。
static int factorial(void)
{
int result;
result = 3 * 2 * 1;
return result;
}

サンプルプロジェクト:study-8-factorial-static.zip

 staticの付いた関数は、関数の記述されたファイル内(今回ならmain.c)でしか利用できないという、C言語のルールがあり、そのため別のファイルで関数を利用する時に必要とされる関数宣言自体が不要になります。
 ただし、呼び出す前に関数を記述できない場合はやはり関数宣言が必要です。
テン*シー*シー-6


変数への代入処理
 factorial関数でresult変数宣言に続けておこなっている
result = 3 * 2 * 1;

 は、result変数に3の階乗結果を代入する処理です。C言語では、 = は等価記号ではなく
result ←3 x 2 x 1

 といったように、変数への代入を意味する事に気をつけてください。

四則演算の演算子
 四則演算には以下の記号(演算子といいます)を使います。
加 +
減 -
乗 *
除 /

 「*」(アスタリスク)はポインタ型でも使っていますが、こちらでは四則演算の積記号を意味します。
 もう一つ、割り算のあまりを演算する演算子もあります。
余り %

 例)5÷3なら、あまりは2
 このうちint型の割り算は注意が必要です。例えば3 / 2の結果は1.5ではなく1です。
3 / 2 → 1

 int型は小数点以下を持てません。四捨五入もされず、常に切り捨てになります。
 このため、int型での演算は(2*3)/2と2*(3/2)で結果が異なる事に注意してください。前者は2となり、後者は3となります。
(2*3)/2 → 3
2*(3/2) → 2

 小数点を扱いたい場合はfloat型を使います。

四則演算の優先順位
 int型、float型、どちらでも四則演算の優先順位は数学の規則に従い、左から順におこなわれ、 乗除が加減より優先します。ただし、上述したように()丸カッコで囲んで優先順位を付ける事ができるので、そちらを活用した方がいいでしょう。

戻り値の受け渡し
 その次の行で
return result;

 とすることで、計算結果を戻しています。呼び出したmain関数側では
result = factorial();

 としているので、ここで戻された値が、main関数側のresultに代入される事になります。

$テン*シー*シー-7

 そして次の
printf("factorial 3 =%d\n", result);

 という記述で、画面には3の階乗の計算結果が表示されます。

ヒープ領域
 変数を関数の外で宣言すると、スタック領域ではない領域にメモリ区画が確保されます。
 このスタック領域ではない領域をヒープ領域と呼びます。
 ヒープも結局、積み重ねるという意味なのですが、こちらは大量のという意味もあります。
一般的にヒープ領域はスタック領域の100倍くらいの大きさがあります。


グローバル変数
 ヒープ領域に確保された領域はアプリケーションが終了するまでメモリに存在し続けます。
 そのため、この場合の変数は、どの関数からも有効なメモリ区画という事になり、グローバル(大域)変数と呼ばれます。

$テン*シー*シー-8

 今回の場合なら、resultをグローバル変数にしてfactorial、main関数で共有すると、戻り値の受け渡しなど冗長な処理が無くなるわけですが、これは良い考えとは言えません。

 次回は、ちょっとだけ横道にそれて、変数についての話をしましょう。