プログラム中で値が変わらない時に使用すべきである定数と、スコープが外れたあとでも値を保持することができる静的変数について説明します。
定数
定数とは、一度定めた値のことで、一度定めたら値を変えることはできませんし、もし変えられたとしても変えるべきではない値です。
C言語で定数を扱う場合、2つの方法があります。
#define
ひとつは、#define を使う方法です。
#include <stdio.h>
#define N 9
#define M 9
int main(void)
{
int i;
int j;
int a[N][M];
for (i = 1; i <= N; i++) {
for (j = 1; j <= M; j++) {
a[i - 1][j - 1] = i * j;
}
}
for (i = 0; i < N; i++) {
for (j = 0; j < M; j++) {
printf("%3d", a[i][j]);
}
printf("\n");
}
return 0;
}
このソースコードは、配列を使って九九を求めるものです。
定数は「#define N 9」と「#define M 9」で定義しています。
定数の定義は、「#define」から始まり、ひとつ空白を置いて、定数の名前を書き、さらにひとつ空白を置いて、定数として利用する数字などを書きます。
このように定義した場合、N と M それぞれが 9 を表す文字として扱うことができるので、配列の要素数を「int a[N][M]」として指定することができます。
さらに、for 文の条件式にも「i <= N」や「j <= M」のように、定数を用いています。
こちらの定数は、コンパイラ時に #define で指定した文字でソースコードの中身が置き換えられると考えるのが分かりやすいです。
const
もうひとつは、const を使う方法です。
#include <stdio.h>
int main(void)
{
int i;
int j;
const int N = 9;
const int M = 9;
int a[N][M];
for (i = 1; i <= N; i++) {
for (j = 1; j <= M; j++) {
a[i - 1][j - 1] = i * j;
}
}
for (i = 0; i < N; i++) {
for (j = 0; j < M; j++) {
printf("%3d", a[i][j]);
}
printf("\n");
}
return 0;
}
このソースコードも、配列を使って九九を求めるものです。
定数は、「const int N = 9;」と「const int M = 9;」で定義しています。
定数の定義は、普段変数を定義するときと同じように書いた後に、先頭に「const」を書くことでできます。定数への値の代入は必ず「const int M = 9;」のように、定義と一緒にする必要があります。
後は普段の変数と同じように使用するだけです。
こちらの定数は、#define と違い、既存の変数の値を変えられないようにするための仕組みであると言えます。
違いと用途
既に少し説明しましたが、#define はコンパイル時にソースコードを #define で定義したものに置き換えてコンパイルします。
そして、const は、一度値を設定したら値を変えることができない変数を定義します。
定数は、配列の要素数のような、今後変わるかもしれない値を数字ではなく、定数として表しておき、もしその数字を変更する際に、ひとつひとつの数字を書き換えるのではなく、定数の定義を書き換え、値を変更するなどして使います。
ちなみに、ソースコード中に書かれた定数とは別の、意味の分かりないもしくは分かりにくい数字のことを「マジックナンバー」と呼び、プログラマーの中では嫌われています。
そのため、マジックナンバーをなくすために、定数を使って、適切な定数の名前をつけて、分かりやすくしておくべきです。
静的変数
通常の変数はスコープを抜けると、変数が破棄され、使うことができなくなります。
そこで、繰り返しや複数回呼び出す関数などで、破棄されずに変数を残すことができる静的変数というものがあります。
#include <stdio.h>
void func(void)
{
static int a = 3;
printf("%d\n", a);
a += 1;
}
int main(void)
{
int i;
for (i = 0; i < 5; i++) {
func();
}
return 0;
}
実行すると、3から7の5つの数字が順に表示されます。
表示は func関数で行なっており、変数a の値を表示しています。
普通であれば、func関数が呼び出されるたびに、変数a の値は3で初期化され、呼び出されるたびに3が表示されるはずですが、実行結果はそのようになりませんでした。
それは、「static int a = 3;」のように、変数の定義の先頭に「static」をつけてこの変数を静的変数にしているのが理由です。
静的変数は、スコープは変化しませんが、変数の定義が一度しか実行されないので、毎回の関数の呼び出し時に「int a = 3;」が実行されず、最初の呼び出し時に「int a = 3;」が実行されて、その後の関数では、最初に作成した変数a を使い回しています。
スコープは変わらないので、変数を使える範囲は変わりませんが、繰り返しや関数の状態を保存しておくなどの場合に使うことができます。
まとめ
定数と静的変数について説明しました。
静的変数は、使いどころが難しいですが、定数は色々なところで使うことができるはずです。
なるべく、配列の要素数など、値が変化するような場所や、数字だけではその数字の意味が理解できないような場所では定数を使うようにしましょう。