第11問の答え

答え

値が同じで意味が異なる数値がややこしい!
  for (int i=0; i<10; i++) {
    if (values[i] % 10 == 0) {
      ……
意味が異なるものには別々の名前を付けるのがベター!
  for (int i=0; i<NUMBER_OF_VALUES; i++) {
    if (values[i] % BASE_VALUE == 0) {
      ……

解説

これは、マジックナンバーに関する出題でした。マジックナンバーとは、プログラム中に突然現れる数字のことです。

あ、できるとかっこいいやつですか!
いえいえ、マジックナンバーは「悪役」なのよ。
なんと!

マジックナンバーは、プログラムを書いた本人にしか意図が分からない数字です。ほかの人からは、なんだか分からないけれどプログラムは正しく動いているように見えます。「まるで魔法だね!」という皮肉が込められた言い方なので、決してかっこいいものではありません。

今回のプログラムには、2種類の「10」が書かれていました。

  • 1つ目は、配列の要素数を表す「10」
  • 2つ目は、10の倍数かどうかを判定するための「10」

今回のような小さなプログラムならある程度は解読できますが、もっと大きなプログラムでマジックナンバーがたくさん出てくると困ったことになります。例えば、配列の要素数を「15」に変更したくなったときのことを考えてみましょう。どの「10」を「15」にして、どの「10」をそのままにしておくべきなのか、簡単には分かりません。

つまり、どの数字がどういう意味なのかが分かりづらいのが問題なんですね。
そういうことよ。
えっと、数字の意味が分かるようにするには……

プログラム中で数字を使うときは、それぞれの意味に応じて名前を付けましょう。そのためには、マクロを使うのが簡単です。

今回のプログラムに出てきた2種類の「10」には、例えば次のような名前を付ければいいですね。

#define NUMBER_OF_VALUES 10
#define BASE_VALUE 10

そして、直接「10」としていたところを、対応するマクロに置き換えます。

  int values[NUMBER_OF_VALUES] = { 5, 3, 14, -6, 20, 372, 1000, 18 };

  for (int i=0; i<NUMBER_OF_VALUES; i++) {
    if (values[i] % BASE_VALUE == 0) {
      printf("values[%d] is a multiple of %d.\n", i, BASE_VALUE);
    }
  }

これで、配列の要素数を変更しやすくなりました。また、「10の倍数か」という判定を「8の倍数」に変えたくなったときも、簡単に対応できそうですね。

ここがポイント!
意味のある数字には名前を付けておこう!

修正後のプログラム

main.c
#include <stdio.h>
#include <stdlib.h>

#define NUMBER_OF_VALUES 10
#define BASE_VALUE 10

int main(void) {
  int values[NUMBER_OF_VALUES] = { 5, 3, 14, -6, 20, 372, 1000, 18 };

  for (int i=0; i<NUMBER_OF_VALUES; i++) {
    if (values[i] % BASE_VALUE == 0) {
      printf("values[%d] is a multiple of %d.\n", i, BASE_VALUE);
    }
  }

  return EXIT_SUCCESS;
}
実行結果
values[4] is a multiple of 10.
values[6] is a multiple of 10.
values[8] is a multiple of 10.
values[9] is a multiple of 10.