線形リストにおける自己再編成に関して

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
amehirune
記事: 181
登録日時: 11年前
住所: どっか
連絡を取る:

線形リストにおける自己再編成に関して

#1

投稿記事 by amehirune » 9年前

お久しぶりでございます。アメヒルネです。
今回は、テスト勉強を兼ねて制作した単語帳にてバグが見つかったので、
その解決方法をおたずねしたく投稿させていただきます。

まず、この単語帳のソースコードを以下に示します。

コード:

#define ONCE
#include "origin.h"

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 );

}
origin.hはオリジナルのヘッダファイルです。
ここでは、stdioだとかstdlibだとか、そういった基本的な標準ライブラリがまとまっているものとして考えてもらえればOKです。

問題のエラーなのですが、この単語帳は「間違えた問題を自己再編成し先頭に持ってくる」という仕様をしておりまして、
最後に間違えた単語のみを反復練習、さらに次回以降は「間違えやすい問題から」出題されるようにしていました。
しかし、この単語帳において3度以上間違えると、反復練習時に3度目の出題が必ず(null)と表示されてしまうのです。
試しにブレークポイントを108行目に設定し、出題用ポインタpのアドレスを見張ってみたのですが、
3問目で必ずp=NULLになっています。
恐らく再編成を行う84~96行目に何らかの不備(というかミス)が存在していると考えましたが、
恥ずかしながら、私ではそれが何なのかを見つけることができませんでした。

どうか、この問題の解決方法、考え方をご教授ください。よろしくお願いします。

開発環境:VC++2008EE
使用言語:C
ほら、来いよ!! 誤字や矛盾を指摘したい奴から、前に出てこいよぉおおおおおおおッ!!!
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 線形リストにおける自己再編成に関して

#2

投稿記事 by usao » 9年前

コード眺めただけなので全く違うかもですが
87行目の old = p; が要らない…ような気がする……かな?

アバター
amehirune
記事: 181
登録日時: 11年前
住所: どっか
連絡を取る:

Re: 線形リストにおける自己再編成に関して

#3

投稿記事 by amehirune » 9年前

なりました。usaoさんありがとうございます!
オフトピック
コード眺めるだけで原因が分かるってすげぇっす
ほら、来いよ!! 誤字や矛盾を指摘したい奴から、前に出てこいよぉおおおおおおおッ!!!
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 線形リストにおける自己再編成に関して

#4

投稿記事 by usao » 9年前

あ,同じようなコードの塊が2か所あるんですね.
そっちも同様に直さなきゃいけないかもですね.

閉鎖

“C言語何でも質問掲示板” へ戻る