今回は上級者の方にアドバイスを求める立場からC言語をやり始めたばかりの初心者にアドバイスをする立場で記事を書きます。

今回紹介するのは剰余演算子。ただ余りを出すだけのこの演算子ですが実際のプログラミングでは頻繁にその姿を表します。実際にプログラムの例を挙げながら剰余演算子を使う上でのテクニックをご紹介します。なお、C言語以外の言語を使っている方でもこの使い方は参考になると思いますのでぜひご覧ください。

まず、連続する数字を割った余りはどうなるのかその特徴をつかんで下さい。

0~15の数字 : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
7で割った余り : 0 1 2 3 4 5 6 0 1 2   3  4   5   6   0  1

どうでしょうか。特徴はつかめましたか。
ある連続する整数を7で割った余りは0~6の順に周期的な値をとっています。この特徴を利用するとこんなことができます。

// 剰余演算子

#include <stdio.h>

int main(void)
{
  int i, j;
  int ar[7];

  for (i = 0; i <= 15; i++) {
    j = i % 7;
    ar[j] = i * i;
    printf("%2d ar[%d] = %3d¥n", i, j, ar[j]);
  }

  return (0);
}

int ar[7]; と宣言するとメモリにはint型の大きさ※01(おそらく 2Byte または 4Byte 、環境により異なります)の領域が ar[0] ~ ar[6] の七つ分用意されます。もし、プログラムの中で配列の要素を八つ以上使う可能性がある場合には上のようにして添え字が6を超えないように i % 7 とするべきです。もしくは、始めから配列の要素を多めに宣言しておくか。

2010y10m11d_091214657

気付いた方もいらっしゃると思いますがこの方法には欠点があります。右の実行結果の0番目と七番目を見比べてください。0番目の ar[0] の値は0だったのに七番目の ar[0] の値が49になっています。つまり ar[0] の値が上書きされたということです。したがって、剰余演算子を使って配列の添え字を制御する方法では古い情報は捨てられ、常に新しい七つの情報が保たれるということです。

一体このテクニックがなんの役に立つのかと思うかもしれません。だって配列の要素が足りなくなるかもしれないのなら配列の宣言時に要素の数を20でも30でも100でも宣言すればいいのですから。

しかし、こういう場合はどうでしょう。何かのゲームでスコアを配列に記録するとしましょう。この時プレイヤーがそのゲームを何回プレイするかわからないので配列の要素を多めに1000個分宣言するとします。しかしプレイヤーが1001回ゲームをプレイするかもしれませんし、3回で飽きてしまうかもしれません。1000回以上プレイされるとそれ以降の情報は捨てられることになります。また、3回しかプレイされなかったら残りの997個分のメモリが無駄になってしまいます。

こういう時こそ剰余演算子の出番です。ゲームのスコアというのはたいていスコアの高いものを10個も記録しておけば十分です。例えプレイヤーが1000回プレイたとしてもハイスコアは10個です。この場合は10で割った余りを添え字に適用すればいいということはもう分りますね。

欠点もある剰余演算子による添え字の制御ですが使いどころによってはとてもいい仕事をしてくれます。rand関数との相性も良く、有名なアルゴリズムとしてはユークリッドの互除法(これには余りを使った巧いテクニックがあるわけではありませんが)にも使われています。ぜひ初心者の皆さんも余りの性質を使ったプログラミングをしてみてください。

おまけ


※01(おそらく 2Byte または 4Byte 、環境により異なります)
これについて自分の環境でint型が何Byteで扱われているのかを調べる方法を御紹介します。
// int型の大きさ(Byte)

#include <stdio.h>

int main(void)
{
  printf("sizeof(short int):%d Byte¥n", sizeof(short int));
  printf("sizeof(      int):%d Byte¥n", sizeof(      int));
  printf("sizeof(long  int):%d Byte¥n", sizeof(long  int));
  
  return (0);
}