連載
» 2019年09月11日 10時00分 公開

山浦恒央の“くみこみ”な話(121):バグ検出ドリル(21)「三角形判定」のテスト項目を設計できますか【解答編】 (3/4)

[山浦恒央 東海大学 大学院 組込み技術研究科 非常勤講師(工学博士),MONOist]

5.バグの原因と修正方法

 見つかったバグを以下に示します。

  1. 全角、半角のどちらを入力するべきか
  2. 0、空白入力がエラーにならない
  3. 三角形の成立条件が機能しない
  4. 「2等辺三角形」のメッセージが間違っている
  5. コメントのバグ

5.1 全角、半角のどちらを入力するべきか

 テスト項目で見つかるバグではありませんが、テスト項目を作成している際、半角と全角のどちらを入力するべきか悩んだ方がいるでしょう。仕様には、「整数値をそれぞれ順番に入力する」と書いてあるだけで、半角・全角のどちらを入力すべきか、定義してありません。一瞬でも、半角と全角が頭によぎった方は正解です。これは、仕様が曖昧であるためで、テスト項目を作る前にどちらが正解か確かめておきたいバグです。プログラムを読むと、全角は入力できないことが分かりますが、仕様書に明記すべきです。

5.2 0、空白がエラーにならない

 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);
リスト1 三角形判定プログラムの一部を抜粋

 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

 リスト2は、コンソール入力後のエラー処理です。文字列の末尾を'\0'で入れ替える前に、1字目に「0」か、「\n(改行)」がないかチェックし、ある場合はエラーとします。これによって、空白や0をエラーとして処理できます。

5.3 三角形の成立条件が機能しない

 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 三角形判定プログラムの一部を抜粋

 上記は、三角形の成立条件の判定式です。よく見ると、仕様には「より大きい」と記載してあるはずですが、「>=」となっています。その結果、(3、2、1)を入力すると、if文の条件が成立してしまうことが分かります。正しくは、「>」です。

Copyright © ITmedia, Inc. All Rights Reserved.