C言語関係掲示板

過去ログ

No.255.リストについて


No.1534

リストについて
投稿者---yusuke(2002/05/19 21:14:39)


こんばんは。yusukeです。
自己参照構造体を勉強中なのですが、どうしてもわからないところがあるので、質問させてください。
ここのHPで、自己参照構造体を勉強した後、自分なりに考えてプログラムを作ってみました。構造体に入れるデータがファイルに予め用意されている、というものです。ファイル形式は、「商品コード(最大10文字列)」「商品名(最大40文字列)」「値段」を1行として、最大100行です。(ここでは6行にしています)
たとえば、
JZK-30 Jizake_tsumeawase 4500
というような感じです。
これを、ファイルに書いてあるのとは逆の順序で表示したいのですが、なぜか、最初の1行が表示されない上、そのままの順序で表示されてしまいます。
struct vertex{
	char code[10];
	char name[50];
	int price;
	struct vertex *next;
};

main()
{
	struct vertex *new, *top, file;
	FILE *fp;
	char str1[20], str2[]="gifts.txt";
	char code[10]={0}, name[40]={0};
	int price=0;

	top = NULL;

	printf("Input filename : ");
	scanf("%s", str1);

	if((strcmp(str1, str2)) == 0){
		fp = fopen("gifts.txt", "r");
		if(fp == NULL){
			printf("Can't open the file.\n");
			return 0;
		}
	}

	while(1){
		fscanf(fp, "%s %s %d", code, name, &price);
		if((feof(fp)) != 0){   /* ファイルの終わりにきたら抜ける */
			break;
		}
		new = (struct vertex *)malloc(sizeof(struct vertex));

		strcpy(new->code, code);
		strcpy(new->name, name);
		new->price = price;

		new->next = top;  /* ポインタのつなぎ換え */
		top = new;
	}

	while(new != NULL){   /* 出力 */
		printf("%s %s %d\n", new->code, new->name, new->price);
		new = new->next;
	}


主要な部分だけ抜粋しました。やはりポインタのつなぎ換え部分がまずいのでしょうか?



No.1540

Re:リストについて
投稿者---ともじ(2002/05/20 15:36:11)


こんにちは。

>これを、ファイルに書いてあるのとは逆の順序で表示したいのですが、なぜか、最初の1行が表示されない上、そのままの順序で表示されてしまいます。

ご提示のプログラムですが、
	while(1){
		fscanf(fp, "%s %s %d", code, name, &price);
		if((feof(fp)) != 0){   /* ファイルの終わりにきたら抜ける */
			break;
		}

と、fscanf の後にfeof の判定を行っていますよね。
これですと、fscanf でファイルENDを読み出すと、feofの判定が
!= 0 になってしまい、リストへの登録をせずにbreakしてしまいます。
ですから、feof後にfscanfを呼ぶなど、順序を変えてみてください。



No.1542

Re:リストについて
投稿者---snow(2002/05/20 15:48:08)


すみません、間の悪い投稿してしまいました。
しかもタブ失敗(涙。
ただ、もう1つの投稿に書いたように、私の環境では
問題なく動くのですが、コンパイラとかに関係が有るんでしょうか?

No.1541

Re:リストについて
投稿者---snow(2002/05/20 15:36:25)


はじめまして、snowです。
ここに質問を書いている私が答えるのはあれな気がしますが(w

>これを、ファイルに書いてあるのとは逆の順序で表示したいのですが、なぜか、最初の1行が表示されない上、そのままの順序で表示されてしまいます。

書いてあったプログラムですが、私の環境では問題なく動きました。
環境はwindows98SE,borland c++ Compiler5.5,cPadを使用しています。

>主要な部分だけ抜粋しました。やはりポインタのつなぎ換え部分がまずいのでしょうか?

いえ、問題ないと思います。これならちゃんと一番新しいデータをポインタtopがさしているはずです。

以下に原型を変えない程度に、気になる点を修正したものを載せます。
あんまり力に慣れなくてスマソ
<PRE>
struct base{
char code[10];
char name[50];
int price;
};

struct vertex{
struct base data;
struct vertex *next;
};

int main()
{
struct vertex *new_data, *top, file; //c++ではnewは予約語
struct base wk; //データ入力領域
FILE *fp;
char str1[20],str2[]="gifts.txt";
char buf[30];

fgets(buf,20,stdin);
buf[strlen(buf)-1]='\0';


if((strcmp(buf, str2)) == 0){
fp = fopen("gifts.txt", "r");
if(fp == NULL){
printf("Can't open the file.\n");
return 0;
}
}
else {
printf("file Unknown %s\n",buf);
return 0;
}

while(1){
fscanf(fp, "%s %s %d", wk.code, wk.name, &wk.price);
if((feof(fp)) != 0){ // ファイルの終わりにきたら抜ける
break;
}
new_data = (struct vertex *)malloc(sizeof(struct vertex));

new_data->data=wk;

new_data->next = top; // ポインタのつなぎ換え
top = new_data;
}

while(new_data != NULL){ // 出力
printf("%s %s %d\n", new_data->data.code, new_data->data.name, new_data->data.price);

new_data = new_data->next;
}
}
</PRE>



No.1548

Re:リストについて
投稿者---yusuke(2002/05/20 17:57:38)


返信ありがとうございます。
もう少し自分で考えてみます。

No.1553

Re:リストについて
投稿者---yusuke(2002/05/20 19:27:04)


どうも。あれからまた考えてみました。どうやらあれで正常に動くみたいです。snowさん、ともじさん、お手数をおかけしてすみませんでした。もっと自分で考えてから投稿すべきでした。反省しております。
ところで、ジャスミン茶さんも質問されていますが、free()についてです。
ともじさんは、リストを辿って順に解放するようにと言ってますが、以下のやり方ではだめなのでしょうか?
struct vertex{
  char code[10];
  char name[50];
  int price;
  struct vertex *next;
};

main()
{
  struct vertex *new, *top, file;
  FILE *fp;
  char str1[20], str2[]="gifts";
  
  top = NULL;

  printf("Input filename : ");
  scanf("%s", str1);
  if((strcmp(str1, str2))!=0){
    printf("そのようなファイルは見つかりませんでした。\n");
    return 0;
  }
  
  fp = fopen("gifts", "r");
  
  while(1){
    fscanf(fp, "%s %s %d", file.code, file.name, &file.price);
    if((feof(fp))!=0){
      break;
    }
    new = (struct vertex *)malloc(sizeof(struct vertex));
    
    strcpy(new->code, file.code);
    strcpy(new->name, file.name);
    new->price = file.price;
    new->next = top;
    top = new;
  }

  while(new!=NULL){
    printf("%s %s %d\n", new->code, new->name, new->price);
    new=new->next;
  }
  
  fclose(fp);
  free(new);
}

これでは、「全部解放!」というわけにはいかないのですか?

No.1554

Re:リストについて
投稿者---ジャスミン茶(2002/05/20 20:04:39)


while(new!=NULL){
printf("%s %s %d\n", new->code, new->name, new->price);
new=new->next;
}

fclose(fp);
free(new);

はじめまして、ジャスミン茶です。
初心者ですが答えさせてください。
最後のfree関数が指定している構造体型のポインタnewは直前にwhile文があることからNULLですよね?
malloc関数で確保したメモリは位置(アドレス)的にそれぞれ全く関係がないわけです。
(どこに作ったのか分からないから、+1しても次のデータに移動できない)
だから構造体のメンバに次のデータへのポインタ(アドレス)を入れて各データに繋がりを持たせている、というわけです。
だからwhile文を実行する前にnewのアドレスをコピーしておいて

struct vertex *copy;
copy = new;
while(copy!=NULL){
free(copy);
copy=copy->next;
}

ではどうでしょう?

私としては別の配列にIDのような形でアドレスを登録するのが良いんじゃないかと思っているのですが…
更に言うとメンバ毎のソート用にアドレスやなにやらを格納するための構造体をもう1つ作ると良いのではないかと。
こうして置けばメモリは沢山使ってしまいますがソートが一瞬で行えますね。
(というか新規作成する度にソートを行ってその結果を構造体においておく。)

生意気言ってスミマセン。

No.1568

Re:リストについて
投稿者---yusuke(2002/05/21 23:45:45)


アドバイスありがとうございます。なんとかやってみます。
しかし発想力が全然違いますね。私なんかとは。
もっと努力しようと思うばかりです。

戻る


「初心者のためのポイント学習C言語」 Last modified:2002.06.28
Copyright(c) 2000-2002 TOMOJI All Rights Reserved