答え
![](/wp-content/include/images/avatar/teacher/14.png)
モジュール内でのみ使用する変数がグローバルになっている!
double sumOfValues = 0;
int numberOfValues = 0;
![](/wp-content/include/images/avatar/teacher/13.png)
グローバルにする必要のない変数はスコープを限定したほうがベター!
static double sumOfValues = 0;
static int numberOfValues = 0;
解説
今回のプログラム(ソースファイル「average.c」)は、2つの関数をインターフェースとするモジュールでした。つまり、以下のような2つの宣言(プロトタイプ宣言)にもとづいて、ほかのモジュールから呼び出されるということです。
void AddValue(double n);
void PrintAverage(void);
「average.c」にある、これらの宣言以外のすべてのものは、モジュールの内部的な実装です。具体的にどのような実装になっているかは、呼び出す側が知る必要はありません。
![](/wp-content/include/images/avatar/teacher/3.png)
標準関数が使える理由も、これと同じなのよ。
![](/wp-content/include/images/avatar/student/11.png)
え?どういうことですか?
![](/wp-content/include/images/avatar/teacher/2.png)
標準関数を呼び出すには、宣言が必要よね?
![](/wp-content/include/images/avatar/student/2.png)
はい。使いたい関数の宣言をインクルードする必要があるってことですね。
![](/wp-content/include/images/avatar/teacher/6.png)
でも、関数の中身がどうなっているかは気にしないでしょう?
![](/wp-content/include/images/avatar/student/3.png)
たしかに!実装を知る必要がないって、そういうことなんですね。
呼び出し側が知る必要のない実装は、呼び出し側から見えないようにしておくほうがベターです。これは、設計をするうえでの基本となる、「情報隠蔽」という考え方です。
ところが、問題のプログラムでは、以下の変数のスコープがグローバルになっていました。
double sumOfValues = 0;
int numberOfValues = 0;
これら2つの変数は「average.c」のファイル内でしか使わないものですが、グローバルのままではどこからでもアクセスできてしまいます。static
を付けて、「ファイルスコープ」にしてしまいましょう。
static double sumOfValues = 0;
static int numberOfValues = 0;
こうしておけば、モジュールの外部からこれら2つの変数に直接アクセスすることはできなくなります。
![](/wp-content/include/images/avatar/student/2.png)
外部からアクセスできなくなると、何が嬉しいんですか?
![](/wp-content/include/images/avatar/teacher/3.png)
いい質問ね!それはね、あとで実装を変えたくなったときのことを考えてみて。
![](/wp-content/include/images/avatar/student/7.png)
もっといい実装方法を思い付いたときとかですか?
![](/wp-content/include/images/avatar/teacher/9.png)
そうそう。そのときに、余計なものがグローバルになっていると……
![](/wp-content/include/images/avatar/student/10.png)
うーん、なんだか手を出しにくい感じがしますね。
![](/wp-content/include/images/avatar/teacher/6.png)
ほかのモジュールがアクセスしている可能性があるからね。
![](/wp-content/include/images/avatar/student/8.png)
なるほど!中身を改良したいだけなのに、外部に影響が出てしまうってことですね。
![](/wp-content/include/images/avatar/teacher/4.png)
そういうこと!ソースファイルが2つ以上になったら気を配りたいポイントね。
![](/wp-content/include/images/avatar/student/4.png)
はーい。分かりました!
グローバル変数やグローバル関数は、そのモジュールのインターフェースとなるものだけにしましょう。そうすれば、あとからモジュール内部の実装を改良したくなったとき、その影響を最小限に抑えられます。プログラムの規模が大きくなってモジュールの数が増えていくほど、このようにスコープに気を配ることが重要になっていきます。
ここがポイント!
![](/wp-content/include/images/avatar/teacher/6.png)
変数や関数をグローバルにするのは、モジュールの外部から使うときだけにしよう!
修正後のプログラム
average.c
#include <stdio.h>
static double sumOfValues = 0;
static int numberOfValues = 0;
void AddValue(double n) {
sumOfValues += n;
numberOfValues += 1;
}
void PrintAverage(void) {
if (numberOfValues > 0) {
printf("Average = %f\n", sumOfValues / numberOfValues);
} else {
printf("No data.\n");
}
}