本日は、線形リスト構造に関する質問をさせていただきます。
C言語を用いて、リストを用いた英単語帳を作ろうと思い立ち、
実際に作ったモノがこちらです。
struct word_t{
char ques[64];
char ans[64];
struct word_t *next;
}*head;
// 領域確保
struct word_t *talloc(){
return ( struct word_t * )malloc( sizeof( struct word_t ) );
}
// 領域開放
void word_free( struct word_t *p ){
struct word_t *q;
if( p != NULL ){
q = p->next;
free( p );
word_free( q );
}
}
int main(int argv,char *argc[]){
int num, right, wrong;
char filename[256], answer[64];
struct word_t *p, *old, *pd, *oldd;
FILE *fp;
if( argv<2 ){
printf( "実行ファイル名を入力してください ≫" );
scanf( "%s", filename );
}
else{
strcpy( filename, argc[1] );
}
if( ( fp = fopen( filename, "r" ) ) == NULL ){
printf( "実行ファイルが見つかりませんでした\n" );
printf( "ファイルの確認をしてください\n" );
exit( EXIT_FAILURE );
}
head = ( struct word_t * )realloc( head, sizeof( struct word_t ) );
fscanf( fp, "%s %s", head->ques, head->ans );
head->next = NULL;
num = 1;
old = head;
while( p = talloc(), fscanf( fp, "%s %s", p->ques, p->ans ) != EOF ){
old->next = p;
p->next = NULL;
old = p;
num++;
}
fclose( fp );
p = old = head;
right = wrong = 0;
for(int i=0;p!=NULL;i++){
system( "cls" );
printf( "意味:%s\n" ,p->ques );
printf( "解答:" );
scanf( "%s", answer );
getchar();
system( "cls" );
printf( "意味:%s\n", p->ques );
printf( "解答:%s\n", answer );
printf( "正解:%s ", p->ans );
if( strcmp( p->ans, answer )==0 ){
printf( "○\n" );
right++;
old = p;
p = p->next;
}
else{
printf( "×\n" );
wrong++;
if( p!=head ){
oldd = old;
pd = p;
//old = p;
p = p->next;
oldd->next = pd->next;
pd->next = head;
head = pd;
}
else{
old = p;
p = p->next;
}
}
printf( "\t\t\t正解数 %d/総問題数 %d\n", right, i+1 );
getchar();
}
if( wrong==0 ){
printf( "パーフェクトです!\n" );
printf( "この調子で頑張ってください!\n" );
}
while( wrong>0 ){
system( "cls" );
printf( "間違えた部分の復習プログラムを開始します\n" ); getchar();
p = head;
num = wrong;
right = wrong = 0;
for(int i=0;i<num;i++){
system( "cls" );
printf( "意味:%s\n" ,p->ques );
printf( "解答:" );
scanf( "%s", answer );
getchar();
system( "cls" );
printf( "意味:%s\n", p->ques );
printf( "解答:%s\n", answer );
printf( "正解:%s ", p->ans );
if( strcmp( p->ans, answer )==0 ){
printf( "○\n" );
right++;
old = p;
p = p->next;
}
else{
printf( "×\n" );
wrong++;
if( p!=head ){
oldd = old;
pd = p;
//old = p;
p = p->next;
oldd->next = pd->next;
pd->next = head;
head = pd;
}
else{
old = p;
p = p->next;
}
}
printf( "\t\t\t正解数 %d/総問題数 %d\n", right, i+1 );
getchar();
}
}
fp = fopen( filename, "w" );
p = head;
while( p!=NULL ){
fprintf( fp, "%s %s\n", p->ques, p->ans );
p = p->next;
}
fclose( fp );
word_free( head );
}
私はこの英単語帳に、
①A面に記載されている内容が表示される
②B面に記載されていると考えられる単語を入力する
③正誤判定(正解ならば⑤は飛ばす)
④カーソルを次に回す
⑤間違えた単語(1つ前のカード)を先頭へ移動する(再編成?)
⑥上記内容を、カードがなくなるまで繰り返す
⑦間違えた単語のみで①~⑥を行う
⑧間違えた単語がなくなるまで⑦を行う
という動作を期待して作りました。
しかし、動作⑦において、3問以上不正解だった場合、
再テスト3枚目のカードがNULLとなるバグが発見されました。
恐らく再編成する過程でどこかミスを犯しているのだろうとは思いますが、
私にはそれ以上のことが分かりません。
しかも、もっと厄介なことに、3問以上間違えたというバグの起こる状況であるにも拘らず、
期待通りに動作する場合もあるのです。
この、状況は全く同じなのに「起こったり起こらなかったりする」バグというのがどうにも不安で、質問させていただきました。
どうかよろしくお願いします。
開発環境はVC++2008EEです。