連載
» 2018年12月25日 10時00分 公開

山浦恒央の“くみこみ”な話(113):バグ検出ドリル(13)のたうち回る地獄、煮詰まったバグを解決せよ (2/3)

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

3.今回の問題

問題文:中学校の教員であるAさんは、自分のクラスの生徒の英語、数学、理科の点数をテキストファイルから読み出し、名前と点数を表示するプログラムを作ることにし、プロトタイプとして、リスト1のソースコードを作成した。動作確認用として、3人分のデータ(リスト2)を作成し、実行したところ、以下のように入力データを正しく表示できなかった(実行結果はリスト3を参照)。

  1. 「YAMADA YUYA」の理科の点数(変数science)が「70」とならず、「79」となった
  2. 「YAMAMOTO AOI」の理科の点数(変数science)が「80」とならず、「0」となった

 理科のデータは正しく入力しているのに、なぜ正しく表示できないのか、上記の情報から、推察せよ。

 なお、本問題では以下の点を考慮して取り組むこと

  • マシンで確認せず、机上で取り組むこと
  • テキストファイルは、リスト2に示したデータ以外を使用しないこと
  • プログラムの可読性は、考慮しない
  • その他のエラー処理は考慮せず、3人分のデータを正しく表示することだけを考える
/*
	テスト データ表示プログラム
	TestDataPrint.c
	
概要:生徒の点数をカンマ区切りで記載したテキストファイルを読み出し、コンソールに表示する。
	
	仕様1: 生徒の点数を記載したテキストファイルを読み出す。
	仕様1-1: examdata.txtを1行ずつ最後まで読み出す。
	仕様1-2: 仕様1-1で取得した1行からカンマ区切りのトークンに区切る
	仕様1-3: 下記の変数に代入する
		math: 数学の点数(0〜100点)
		english: 英語の点数(0〜100点)
		science: 理科の点数(0〜100点)
		name: 生徒の名前(半角大文字アルファベット15文字)
	仕様2: 代入した生徒の点数をコンソールに改行区切りで表示する
*/
#define N 3		//生徒の数
#define LEN 256		//文字列の長さ
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
	int i;				//ループ変数
	unsigned char math[N];		//数学の点数
	unsigned char english[N];		//英語の点数
	unsigned char science[N];		//理科の点数
	char name[N][15];			//生徒の氏名
	FILE *fp;			//ファイルポインタ
	char fname[] = "examdata.txt";	//ファイル名
	char *token;			//トークン
	char *sep = ",\n";		//セパレータ
	int no = 0;			//データ数
	int index = 0;			//カンマ区切りの数
	char buf[LEN];			//1行分の文字列
	
	//各変数を初期化
	for (i = 0; i < N; i++) {
		memset(name[i], 0, sizeof(name[i]));
		math[i] = 0;
		english[i] = 0;
		science[i] = 0;
	}
	
	//examdata.txtの読み出し
	fp = fopen(fname, "r");
	if (fp == NULL) {
		printf("file not open\n");
		return -1;
	}
	
	//テキストファイルからデータを1行ずつ読み出す
	while(fgets(buf, LEN , fp) != NULL) {
		//読み出したデータから1つ目のカンマ区切りまでを取得する
		token = strtok(buf,sep);
		index = 0;
		//カンマ区切りのデータが取得できるまでループ
		while (token != NULL) {
			//分割した順番から各変数にデータを代入する
			if (index == 0) {
				strcpy(name[no],token);   //生徒の名前を取得する
			} else if (index == 1) {
				english[no] = atoi(token); //英語の点数を取得する
			} else if (index == 2) {
				math[no] = atoi(token);	//数学の点数を取得する
			} else if (index == 3) {
				science[no] = atoi(token); //理科の点数を取得する
			}
			//読み出したデータをカンマ区切りに分割する
			token = strtok(NULL, sep);
			index++;
			//データがこれ以上取得できない場合は、ループを抜ける
			if (token == NULL) {
				no++;
				break;
			}
		}
	}
	
	//各変数を表示する
	for (i = 0; i < N; i++) {
		printf("name = %s\n",name[i]);
		printf("english = %d\n",english[i]);
		printf("math = %d\n",math[i]);
		printf("science = %d\n",science[i]);
	}
	return 0;
}
リスト1 テストデータ表示プログラム(TestDataPrint.c)

YAMADA YUYA,80,50,70

YAMAMOTO AOI,91,32,80

WATANABE SHUICHIRO,66,40,100

リスト2 テストの点数データ(examdata.txt)

name = YAMADA YUYA

english = 80

math = 50

science = 79

name = YAMAMOTO AOI

english = 91

math = 32

science = 0

name = WATANABE SHUICHIRO

english = 66

math = 40

science = 100

リスト3 プログラムの実行結果

Copyright © ITmedia, Inc. All Rights Reserved.