見つかったバグを以下に示します。
テスト項目で見つかるバグではありませんが、テスト項目を作成している際、半角と全角のどちらを入力するべきか悩んだ方がいるでしょう。仕様には、「整数値をそれぞれ順番に入力する」と書いてあるだけで、半角・全角のどちらを入力すべきか、定義してありません。一瞬でも、半角と全角が頭によぎった方は正解です。これは、仕様が曖昧であるためで、テスト項目を作る前にどちらが正解か確かめておきたいバグです。プログラムを読むと、全角は入力できないことが分かりますが、仕様書に明記すべきです。
No.3、No.4、No.14のテスト項目をご覧ください。「0」、「012」、「空白」がエラーとならずに三角形の判定を実行しています。この原因を以下に示します。
//辺を入力 fgets(str, sizeof(str), stdin); //文字列の長さを取得 len = strlen(str) - 1; //文字列の末尾の改行を'\0'に置き換える if (str[len] == '\n') { str[len] = '\0'; } else { //入力桁数が多い場合は、プログラム終了する while (getchar() != '\n') { printf("入力エラー\n"); exit(1); } } for (i = 0; i < len; i++) { if (!(str[i] >= '0' && str[i] <= '9')) { printf("入力エラー\n"); exit(1); } } //文字列を整数型に変換する *val = atoi(str);
fgetsは、コンソールからキー入力を取ってくる関数で、入力した文字数を取得し、末尾を\0で埋めます。読み込める文字数は、ヌルを入れて4文字としており、桁数がそれ以上の場合は、else以下で入力エラーとしています。その後、文字列を検索し、0〜9以外の文字が無いか探します。見つからなければ、文字列を整数型に変換し、関数を抜ける仕組みです。
「0」を入力した場合
上記のプログラムに、「0」を入力した場合はどうなるでしょうか。先頭が0の場合のエラー処理が記載されていないことが分かります。
また、「012」のように、前ゼロがある数値入力があった場合の処理も正常に処理します。これは、文字列strに「012」という文字列をいれ、atoi関数で先頭の0を省き、「12」に変換してしまうためです。結果として、12という値になってしまい、No4のケースでは正三角形となってしまいました。前ゼロをどうするかは、仕様には書いておらず、仕様の抜けのバグとなります。なお、今回のテスト項目で前ゼロの場合は、入力エラーとしてテスト項目を記述しています。
「空白」を入力した場合
コンソールから、何も入力しないでエンターを押すと、fgetsは、末尾を'\n'で埋めます。末尾を'\0'に置き換えてしまうと、異常値とみなさず、すり抜けてしまいます。
上記のバグを防ぐには、例えば、以下のような記述が考えられます(リスト2)。
if (str[0] == '0' || str[0] == '\n') { printf("入力エラー\n"); exit(1); }
リスト2は、コンソール入力後のエラー処理です。文字列の末尾を'\0'で入れ替える前に、1字目に「0」か、「\n(改行)」がないかチェックし、ある場合はエラーとします。これによって、空白や0をエラーとして処理できます。
No.9とNo.10の三角形の成立条件のテスト項目をご覧ください。例えば、「3、2、1」などの2辺を足すと、もう一辺と同じになる入力の場合、三角形が成立しないはずが、「不等辺三角形」と出力する原因は何でしょうか。以下のリスト3をご覧ください。
void triangle_handler(int side1, int side2, int side3) { //正三角形、二等辺三角形、不等辺三角形を判定する if ((side1 + side2 >= side3) && (side2 + side3 >= side1) && (side3 + side1 >= side2)) {
上記は、三角形の成立条件の判定式です。よく見ると、仕様には「より大きい」と記載してあるはずですが、「>=」となっています。その結果、(3、2、1)を入力すると、if文の条件が成立してしまうことが分かります。正しくは、「>」です。
Copyright © ITmedia, Inc. All Rights Reserved.