データベースの作成

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たかし
記事: 48
登録日時: 12年前

データベースの作成

#1

投稿記事 by たかし » 12年前

大学の課題でデータベースを作るというものが出されました。
以下が課題の要約です。
実装する機能は、登録、訂正、削除、検索。
テキストファイルへの保存、読み込みの機能を実装する。
テキストファイルの形式は
<検索キー>,<検索対象データ>
のように半角カンマで区切り、読み込みファイルに形式エラーはないとしてよい。

以下が私の作ったプログラムです。

コード:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct lst {
  struct lst *next;
  char name[20];
	char score[20];
}LIST;


LIST *newList(LIST *start, char *string1, char *string2){
  LIST *p=start;
  LIST *new;
  while(p->next!=NULL){
    p=p->next;
  }
  if((new = (LIST *)malloc(sizeof(LIST)))==NULL){
    fprintf(stderr,"Can't allocate memory!\n");
    exit(-1);
  }
  p->next = new;
  strcpy(new->name, string1);
	strcpy(new->score, string2);
  new->next = NULL;
  return new;
}

  

void printregister(LIST *init){
  LIST *p=init;
    if(p==NULL){
      printf("LIST IS EMPTY\n");
      exit(1);
    }
  printf("名前%s得点\n%s\nで登録しました。\n",p->name,p->score);
}

void writefile(LIST *p)
{
	FILE *fp;
	
	if((fp = fopen("text.txt", "w")) == NULL){
		printf("file open error!!\n");
		exit(1);
	}
	while(p->next!=NULL){
    fputs(p->name, fp);
	  putc(',', fp);
	  fputs(p->score,fp);
	  putc('\n',fp);
	  p=p->next;
  }
}



void inputdate(LIST *init){
	
		LIST *p=init;
		int i=0;
		int j=0;
		char n[20];
		char s[20];
		printf("名前をを入力してください。\n");
		while( ( n[i++] = getchar() ) != EOF) ;			
  	n[i-1] = '\0';
		printf("得点を入力してください。\n");
	  while( ( s[j++] = getchar() ) != EOF) ;
  	s[j-1] = '\0';
		if(p->name[0]=='\0'){
			strcpy(p->name,n);
			strcpy(p->score,s);
		}
		else{
			newList(p,n,s);
		}
		writefile(p);
		printregister(p);
}

void readfile(FILE *fp, LIST *init)
{
	LIST *p = init;
	
	while((fscanf(fp,"%s%d",p->name,p->score))!=EOF){
		p=p->next;
	}
}
	

int main (int argc, char *argv[])
{
  LIST *init;
	FILE *fp;
	int num;
	
	if((init = (LIST*)malloc(sizeof(LIST)))==NULL){
    fprintf(stderr,"Can't allocate memory!\n");
    exit(-1);
  }
	
	if(argc >1){
		
		if((fp = fopen(argv[1], "r")) == NULL){
			printf("file open error!!\n");
			exit(1);
		}
	}
	readfile(fp,init);
	fclose (fp);

	

	
	printf("何を実行しますか?\n");
	printf("1.登録\n");
	printf("2.訂正\n");
	printf("3.削除\n");
	printf("4.検索\n");
	
	printf("番号を入力してください。\n");

	scanf("%d",&num);

	switch(num){
		case 1:
				
			inputdate(init);
	}

	
	
}
私の考えていた動作は、
最初にテキストファイルを読み込んで、テキストファイルの中にあるデータをリストに書きこんでいく。
データを登録する場合、先ほど書きこんだリストの続きに新たなリストを作りそこへ新しいデータを入れる。
テキストファイルが空の場合は先頭のリストに直接名前と得点を入れる。
最後にリストのデータをすべてテキストファイルに上書きする。


しかしわたしのプログラムを実行すると以下のようになりました。

text.txtに何も文字が入っていない場合。

$ ./a.exe text.txt
何を実行しますか?
1.登録
2.訂正
3.削除
4.検索
番号を入力してください。
1
名前をを入力してください。
A
得点を入力してください。
50
名前
A
得点
50

で登録しました。

と出力されたのですが、text.txtには何も書きこまれておらず、空のままでした。

text.txt
A,30
という文字が入っていた場合

$ ./a.exe text.txt
何を実行しますか?
1.登録
2.訂正
3.削除
4.検索
番号を入力してください。
1
名前をを入力してください。
B
得点を入力してください。
40
名前A,30得点

で登録しました。

としゅつりょくされ、text.txtの中身は
A,30,
とカンマが1つ増えていました。

なぜ思い通りに動かないのかがわかりません。
プログラムのおかしな場所を教えてほしいです。
よろしくお願いします。

トントン
記事: 100
登録日時: 14年前

Re: データベースの作成

#2

投稿記事 by トントン » 12年前

アドバイスとしては、
1.インデントをそろえる
2.好みにもよると思いますがポインタをずらっと並べるのであればグローバル変数を用意する。
3.テキストに書きこむ前から順繰りブレークポイントを張っていけば原因がわかるかもしれません。

te

Re: データベースの作成

#3

投稿記事 by te » 12年前

再現性が得られなかったため完全な解答が出来ませんが考えられる問題とこれから起こるであろうバグについて説明します
writefile関数内で

コード:

while(p->next!=NULL){
//処理
}
となっていますがpの指す内容を書き込みたいので

コード:

while(p!=NULL){
//処理
}
となるのではないかと
p->nextがNULLの時は最後の要素であり、それも書き込む必要があります
何も書かれていないtext.txtにA,50が書かれなかったのはこのためです

また、変数の初期化を行わずにアクセスしています
例:newListのwhile条件でp->nextがNULLになる時が不定である
メモリを確保したら値を入れないとアクセスした際にエラーが発生すると思っていましたが処理が進んでいるので申し訳ないですがこれは私には分かりません
本来ならばmalloc時にnextだけでもNULLにすべきです

readfileにおいてもmallocをその前に1度しかしていないため複数個のデータが存在する場合確保していない不定の領域に書き込んでしまいます

non
記事: 1097
登録日時: 14年前

Re: データベースの作成

#4

投稿記事 by non » 12年前

現在、その症状が出ている動くプログラムを載せてください。
non

たかし
記事: 48
登録日時: 12年前

Re: データベースの作成

#5

投稿記事 by たかし » 12年前

みなさんありがとうございます。
とりあえず、ご指摘いただいた箇所と、自分でおかしいと思ったところを書き替えて作りなおしてみました。

コード:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct lst {
  struct lst *next;
  char name[20];
	char score[20];
}LIST;


LIST *newList(LIST *start, char *string1, char *string2){
  LIST *p=start;
  LIST *new;
  while(p->next!=NULL){
    p=p->next;
  }
  if((new = (LIST *)malloc(sizeof(LIST)))==NULL){
    fprintf(stderr,"Can't allocate memory!\n");
    exit(-1);
  }
  p->next = new;
  strcpy(new->name, string1);
	strcpy(new->score, string2);
  new->next = NULL;
  return new;
}

  

void printregister(LIST *init){
		LIST *p=init;
	  if(p==NULL){
    printf("LIST IS EMPTY\n");
    exit(1);
  }
	printf("名前%s得点\n%s\nで登録しました。\n",p->name,p->score);
}

void writefile(LIST *p)
{
	FILE *fp;
	
	if((fp = fopen("text.txt", "w")) == NULL){
		printf("file open error!!\n");
		exit(1);
	}
	while(p!=NULL){
  fputs(p->name, fp);
	putc(',', fp);
	fputs(p->score,fp);
	putc('\n',fp);
	p=p->next;
  }
}



void inputdate(LIST *init){
	
		LIST *p=init;
		int i=0;
		int j=0;
		char n[20];
		char s[20];
		printf("名前をを入力してください。\n");
		while( ( n[i++] = getchar() ) != EOF) ;			
  	n[i-1] = '\0';
		printf("得点を入力してください。\n");
	  while( ( s[j++] = getchar() ) != EOF) ;
  	s[j-1] = '\0';
		if(p->name[0]=='\0'){
			strcpy(p->name,n);
			strcpy(p->score,s);
		}
		else{
			newList(p,n,s);
		}
		writefile(p);
		printregister(p);
}

void readfile(FILE *fp, LIST *init)
{
	LIST *p = init;
	char t[20];
	char n[20];
	char s[20];
	int i=0;
	int j=0;
	
	if(fgets(t,sizeof(t),fp)!=NULL){
		while(t[i]!=','){
			p->name[i]=t[i];
			i++;
		}
		i++;
		while(t[i]!='\0'){
			p->score[j]=t[i];
			i++;
			j++;
		}
		i=0;
		j=0;
		char t[20]={'\0'};
		while(fgets(t,sizeof(t),fp)!=NULL){
			char n[20]={'\0'};
			char s[20]={'\0'};
			
			while(t[i]!=','){
			n[i]=t[i];
			i++;
			}
			i++;
			while(t[i]!='\0'){
				s[j]=t[i];
				i++;
				j++;
			}
	  	t[20]='\0';
		  newList(p,n,s);
		}
	}
}

int main (int argc, char *argv[])
{
  LIST *init;
	FILE *fp;
	int num;
	
	if((init = (LIST*)malloc(sizeof(LIST)))==NULL){
    fprintf(stderr,"Can't allocate memory!\n");
    exit(-1);
  }
	init->next=NULL;
	
	if(argc >1){
		
		if((fp = fopen(argv[1], "r")) == NULL){
			printf("file open error!!\n");
			exit(1);
		}
	}
	readfile(fp,init);
	fclose (fp);

	

	
	printf("何を実行しますか?\n");
	printf("1.登録\n");
	printf("2.訂正\n");
	printf("3.削除\n");
	printf("4.検索\n");
	
	printf("番号を入力してください。\n");

	scanf("%d",&num);

	switch(num){
		case 1:
				
			inputdate(init);
	}

	
	
}
しかしこのプログラムを実行すると
$ ./a.exe text.txt
何を実行しますか?
1.登録
2.訂正
3.削除
4.検索
番号を入力してください。

と出力されたあと強制終了されてしまいます。
何故でしょうか?
出力の直後にscanfで入力をするようになっているので、原因が全く分かりません。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: データベースの作成

#6

投稿記事 by みけCAT » 12年前

t[20]という範囲外の添字にアクセスしていますが、大丈夫ですか?
また、コマンドライン引数が無い場合に初期化されていないfpにアクセスしてしまいます。

強制終了の直接の原因ではないと思いますが…
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

non
記事: 1097
登録日時: 14年前

Re: データベースの作成

#7

投稿記事 by non » 12年前

コード:

void inputdate(LIST *init){
    
        LIST *p=init;
        int i=0;
        int j=0;
        char n[20];
        char s[20];
        printf("名前をを入力してください。\n");
        while( ( n[i++] = getchar() ) != EOF) ;         
    n[i-1] = '\0';
        printf("得点を入力してください。\n");
      while( ( s[j++] = getchar() ) != EOF) ;
    s[j-1] = '\0';
        if(p->name[0]=='\0'){
            strcpy(p->name,n);
            strcpy(p->score,s);
        }
        else{
            newList(p,n,s);
        }
        writefile(p);
        printregister(p);
}
上の関数の中の

コード:

       printf("名前をを入力してください。\n");
        while( ( n[i++] = getchar() ) != EOF) ;         
    n[i-1] = '\0';
これって、なんでこんなやり方なんですか?CTRL-Zを入れるの?

コード:

        if(p->name[0]=='\0'){
いつ、p->nameを初期化しましたっけ?

readfileの関数は、まだ見る気がしない。
non

たかし
記事: 48
登録日時: 12年前

Re: データベースの作成

#8

投稿記事 by たかし » 12年前

みなさんご指摘ありがとうございました。
また、ここのところ忙しく返信が遅くなってしまいすみませんでした。
ご指摘していただいたことを直してプログラムを完成させました。
一応完成したプログラムを載せておきます。

コード:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFSIZE 1000

typedef struct lst {
	struct lst *next;
	char name[BUFSIZE];
	char score[BUFSIZE];
}LIST;


LIST *newList(LIST *start, char *string1, char *string2){
	LIST *p=start;
	LIST *new;
	while(p->next!=NULL){
		p=p->next;
	}
	if((new = (LIST *)malloc(sizeof(LIST)))==NULL){
		fprintf(stderr,"Can't allocate memory!\n");
		exit(-1);
	}
	p->next = new;
	strcpy(new->name, string1);
	strcpy(new->score, string2);
	new->next = NULL;
	return new;
}

LIST *delList(LIST *start, char *target){
	LIST *p=start;
	LIST *tmp;

	if(!strcmp(p->name, target)){
		tmp=p;
		p=p->next;
		free(tmp);
	}else{
		while(p->next!=NULL){
			if(!strcmp((p->next)->name, target)){
				tmp=p->next;
				p->next = p->next->next;
				free(tmp);
				break;
			}else{
				p=p->next;
			}
		}
		p=start;
	}
	return p;
}

LIST *searchList(LIST *start, char *target)
{
	LIST *p=start;

	while(p!=NULL){
		if(!strcmp(p->name, target)){
			return p;
		}
		else{
			p=p->next;
		}
	}
	return NULL;
}

LIST *listfree(LIST *start)
{
	LIST *tmp;
	while(start!=NULL){
		tmp=start;
		start=start->next;
		free(tmp);
	}
	return start;
}



void printList(LIST *init)
{
	LIST *p=init;

	while(p->next!=NULL){
		printf("%s\n",p->name);
		printf("%s\n",p->score);
		p=p->next;
	}
	printf("%s\n",p->name);
	printf("%s\n",p->score);
}

void correction(LIST *t)
{
	LIST *p=t;
	char cor[BUFSIZE];

	printf("何点に訂正しますか?\n");
	scanf("%s",cor);
	strcpy(p->score,cor);
}

void printregister(LIST *init){
	LIST *p=init;
	if(p==NULL){
		printf("LIST IS EMPTY\n");
		exit(1);
	}
	while(p->next!=NULL){
		p=p->next;
	}

	printf("名前\n");
	printf("%s\n",p->name);
	printf("点数\n");
	printf("%s\n",p->score);
	printf("で登録しました。\n");
}

void writefile(FILE *fp, LIST *init)
{
	LIST *p=init;


	while(p!=NULL){
		fputs(p->name, fp);
		fputs(" ", fp);
		putc(',', fp);
		fputs(" ", fp);
		fputs(p->score, fp);
		putc('\n',fp);
		p=p->next;
	}
}



void inputdate(LIST *init){

	LIST *p=init;
	char n[BUFSIZE];
	char s[BUFSIZE];

	printf("名前をを入力してください。\n");
	scanf("%s", n);

	if(searchList(p,n)!=NULL){
		printf("すでに登録されている名前です。\n");
		exit(1);
	}
	printf("得点を入力してください。\n");
	scanf("%s", s);	
	if(p->name[0]=='\0'){
		strcpy(p->name,n);
		strcpy(p->score,s);
	}
	else{
		newList(p,n,s);
	}
	printregister(p);
}

void readfile(FILE *fp, LIST *init)
{
	LIST *p = init;

	char n[BUFSIZE]={'\0'};
	char s[BUFSIZE]={'\0'};
	char c[BUFSIZE]={'\0'};

	fscanf( fp , "%s%s%s" , n , c, s);


	strcpy(p->name, n);
	strcpy(p->score,s);

	while((fscanf( fp , "%s%s%s" , n, c, s))!= EOF ) {

		newList(p,n,s);

	}

}
LIST *scoresort(LIST *start)
{
	LIST *ssort;
	LIST *a=start;
	LIST *b=start;
	LIST *min;
	int i;
	int count=1;
	char s1[BUFSIZE]={'\0'};
	char s2[BUFSIZE]={'\0'};

	if(start==NULL || start->next==NULL){
		printf("整列する必要がありません。\n");
		exit(1);
	}

	if((ssort = (LIST*)malloc(sizeof(LIST)))==NULL){
		fprintf(stderr,"Can't allocate memory!\n");
		exit(-1);
	}

	ssort->next=NULL;

	while(a->next!=NULL){
		count++;
		a=a->next;
	}

	for(i=0;i<count;i++){
		min=b;
		while(searchList(ssort,min->name)!=NULL){
			b=b->next;
			min=b;
		}
		while(b->next!=NULL){
			strcpy(s1,min->score);
			strcpy(s2,b->next->score);
			if(atoi(s1)>atoi(s2)){
				if(searchList(ssort,(b->next)->name)==NULL){
					min=b->next;
				}
			}
			b=b->next;
		}
		if(i==0){
			strcpy(ssort->name,min->name);
			strcpy(ssort->score,min->score);
		}
		else{
			newList(ssort,min->name,min->score);
		}
		b=start;


	}

	return ssort;
}



LIST *namesort(LIST *start)
{
	LIST *nsort;
	LIST *a=start;
	LIST *b=start;
	LIST *min;
	int i;
	int j=1;
	int count=1;



	if(start==NULL || start->next==NULL){
		printf("整列する必要がありません。\n");
		exit(1);
	}

	if((nsort = (LIST*)malloc(sizeof(LIST)))==NULL){
		fprintf(stderr,"Can't allocate memory!\n");
		exit(-1);
	}

	nsort->next=NULL;

	while(a->next!=NULL){
		count++;
		a=a->next;
	}


	for(i=0;i<count;i++){
		min=b;
		while(searchList(nsort,min->name)!=NULL){
			b=b->next;
			min=b;
		}
		while(b->next!=NULL){
			if(min->name[0]==(b->next)->name[0]){
				while(min->name[j]!='\0' && (b->next)->name!='\0'){
					if(min->name[j]>(b->next)->name[j]){
						if(searchList(nsort,(b->next)->name)==NULL){
							min=b->next;
						}
						break;
					}
					j++;
				}
			}
			else if(min->name[0] > (b->next)->name[0]){
				if(searchList(nsort,(b->next)->name)==NULL){
					min=b->next;
				}
			}
			b=b->next;
			j=1;
		}
		if(i==0){
			strcpy(nsort->name,min->name);
			strcpy(nsort->score,min->score);
		}
		else{
			newList(nsort,min->name,min->score);
		}
		b=start;

	}

	return nsort;
}


int main (int argc, char *argv[])
{
	LIST *init;
	LIST *s;
	LIST *nsort;
	LIST *ssort;
	FILE *fp;
	int num;
	int ss;
	char target[BUFSIZE];

	if((init = (LIST*)malloc(sizeof(LIST)))==NULL){
		fprintf(stderr,"Can't allocate memory!\n");
		exit(-1);
	}

	init->next=NULL;

	if(argc >1){

		if((fp = fopen(argv[1], "r")) == NULL){
			printf("file open error!!\n");
			exit(1);
		}
	}
	readfile(fp,init);
	fclose (fp);
	printf("データベース\n");
	printList(init);

	printf("何を実行しますか?\n");
	printf("1.登録\n");
	printf("2.訂正\n");
	printf("3.削除\n");
	printf("4.検索\n");
	printf("5.整列\n");

	printf("番号を入力してください。\n");

	scanf("%d",&num);

	while(num<1 || num>5){
		printf("1~5の数字を入力してください。\n");
		scanf("%d",&num);
	}
	switch(num){
	case 1:

		inputdate(init);

		if((fp = fopen(argv[1], "w")) == NULL){
			printf("file open error!!\n");
			exit(1);
		}
		writefile(fp,init);
		fclose(fp);
		break;

	case 2:
		printf("点数を訂正したい人の名前を入力してください。\n");
		scanf("%s",target);
		if(searchList(init,target)!=NULL){
			correction(searchList(init,target));

			if((fp = fopen(argv[1], "w")) == NULL){
				printf("file open error!!\n");
				exit(1);
			}
			writefile(fp,init);
			fclose(fp);
			printf("訂正が完了しました。\n");
		}
		else{
			printf("データベースにない名前です。\n");
			exit(1);
		}
		break;

	case 3:
		printf("削除したい人の名前を入力してください。\n");
		scanf("%s",target);
		if(searchList(init,target)!=NULL){
			init=delList(init,target);
			printf("削除が完了しました。\n");
			if((fp = fopen(argv[1], "w")) == NULL){
				printf("file open error!!\n");
				exit(1);
			}
			writefile(fp,init);
			fclose(fp);

		}
		else{
			printf("データベースにない名前です。\n");
			exit(1);
		}
		break;

	case 4:
		printf("検索したい人の名前を入力してください\n");
		scanf("%s",target);
		if((s=searchList(init,target))!=NULL){
			printf("%sの点数は%sです。\n",s->name,s->score);
		}
		else{
			printf("データベースにない名前です。\n");
			exit(1);
		}
		break;

	case 5:
		printf("何順に整列しますか?\n");
		printf("1.名前\n");
		printf("2.点数\n");
		printf("番号を入力してください。\n");
		scanf("%d",&ss);
		while(ss<1 || ss>2){
			printf("1~2の数字を入力してください。\n");
			scanf("%d",&ss);
		}
		switch(ss){
		case 1:
			nsort=namesort(init);
			init=nsort;
			if((fp = fopen(argv[1], "w")) == NULL){
				printf("file open error!!\n");
				exit(1);
			}
			writefile(fp,init);
			fclose(fp);
			printf("名前順に整列しました。\n");
			nsort=listfree(nsort);
			break;

		case 2:
			ssort=scoresort(init);
			init=ssort;

			if((fp = fopen(argv[1], "w")) == NULL){
				printf("file open error!!\n");
				exit(1);
			}
			writefile(fp,init);
			fclose(fp);
			printf("点数順に整列しました。\n");
			ssort=listfree(ssort);
			break;
		}
		break;

	}
	init=listfree(init);


	return 0;
}
動作の流れとしては
最初にテキストファイルを読み込んで、テキストファイルにあるデータをリストに書き込んでいきます。
その後、選択した内容の処理を行い最後にリストを再びテキストファイルに書き込むというものです。
みなさん、いろいろありがとうございました。
また質問することがあると思いますが、その時はよろしくお願いします。

non
記事: 1097
登録日時: 14年前

Re: データベースの作成

#9

投稿記事 by non » 12年前

playhuman さんが書きました:テキストファイルの形式は
<検索キー>,<検索対象データ>
のように半角カンマで区切り、読み込みファイルに形式エラーはないとしてよい。
あなたのプログラムですと、
A , 10
のように カンマの前後にスペースが必要なのではないですか?
non

閉鎖

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