本物のC

デバッグ:printfデバッグ


コードのどこが実行され、メモリの状態がどうなっているかを検証する最も素朴な方法はprintfをコードに挟んでみる事でしょう。

printfによる実験

例えば次のコードはint配列の和を求めるsum関数により 1 ~ 5 の和を求める事を意図していますが、

#include <stdio.h>
int sum(int data[])
{
int i,
n = sizeof(data) / sizeof(data[0]),
s = 0;
for (i = 0; i < n; i++)
{
s += data[i];
}
return s;
}
int main(void)
{
int data[] = { 1, 2, 3, 4, 5 };
printf("%d\n", sum(data));
return 0;
}

これを実行すると期待に反して

1

と出力されます。一体どこが問題なのでしょうか?

和の計算をしているのは 9 ~ 12 行目ですから、一番怪しいのはこの部分です。例えば 11 行目の前に

printf("#%d %d %d\n", i, data[i], s);

と書いて実行し、何が起きているのか確かめてみましょう。

その結果は

#0 1 0 1

となって、ループが実は一回しか実行されていない事が判ります。つまりndataの要素数になっていないのです。

ネタをばらすと、このバグの核心はdataの要素数をsizeof(data) / sizeof(data[0])で求めようとしている点です。配列型というのはコンパイル時にはサイズが分かりませんので、引数として書いてもポインタ型に変換して渡される事になっています6.9.1#10nは呼び出し側から与えられなければならないのです。紛らわしいので不定サイズの配列型として引数を書くのは止めた方が良いかも知れません。

int sum(int n, int *data)
{
int i,
s = 0;
for (i = 0; i < n; i++)
{
s += data[i];
}
return s;
}

この様に簡単なデバッグならば、小回りの利くprintfデバッグは非常に有効な手段となります。