何度もすいません・・・

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sub

何度もすいません・・・

#1

投稿記事 by sub » 17年前

初めましてわからないので教えて欲しいことがあったので来させて頂きました、よろしくお願いします。

ファイルから読み込んで5人目までの成績を表示するプログラムなのですが6人以上いた場合は1人の成績も表示せずに終了させるようにするにはどうすればいいでしょうか?
ファイルは
g 20 20 20
t 40 40 40
j 40 40 40
のような感じです(上ので3人)

#include <stdio.h>

typedef struct score{
	char   name[40];
	int    eng;
	int    mat;
	int    sci;
} Score;

int main(void)
{
	FILE *fp;
	char cmd[20], fname[20], rank;
	int ch=0;
	
	
	Score data[5];
	Score *p;
	p=data;	
	
	
	while (rank!='q'){
	   printf("CMD>");
	   fflush(stdout);
           gets(cmd);
           sscanf(cmd, "%c %s", &rank, fname);
	    
	    
	   switch(rank){
		     case 'r': 
		                if ((fp = fopen(fname, "r")) == NULL){
		                	printf("%sが開けません\n", fname);
		                }
		                
		                break;
		                
		                
		     case 'd':    	     
		                   while (fscanf(fp, "%s %d %d %d", p->name, &(p->eng), &(p->mat), &(p->sci)) == 4){
		                    printf("名前:%s\n",data[ch].name);
		     	            printf("英語:%d\n",data[ch].eng);
		     	            printf("数学:%d\n",data[ch].mat);
		     	            printf("理科:%d\n\n",data[ch].sci);
		                    ch++;
		                    p++;
		                    if (ch==5){
		                       break;}
		                }
		                break;
		                
		                
		     case 'q':
		       fclose(fp);
		       break;
	    }
	}
		    
	return (0);
}
あとgetsをfgetsに変えられないでしょうか?

本当によろしくお願いします・・・

なぎ

Re:何度もすいません・・・

#2

投稿記事 by なぎ » 17年前

通常のファイルで、人数を事前に把握する方法はありません。
従って、一般的な方法では、処理に先立って、ファイルを読み込み、何人分のデータがあるのか確認しておくことになります。

1)ファイルをオープン
2)データを読み込みつつ、数を確認
3)ファイルをクローズ

4)6人以上のデータがあれば終わり。
5)再度、ファイルをオープン
6)データを読み込みつつ表示
7)ファイルをクローズ

こんな感じです。

fgets() を使うのであれば、ファイルとして、 stdin (これは、FILE * 型であらかじめ定義してあります)を指定すればOKです(引数は fgets() にあわせるとして)

あと例示されているプログラムですが、
ファイルをオープン → データを表示 → プログラム終了
という流れ以外の処理はできないはずなのに、入力を 受けて case で振り分けるのは、危険です。

いきなり、d が入力されると、あまり良くないことが起こります。
2回続けて d が入力されるとか。
それに対する手当もされていないように見えますし。

なぎ

Re:何度もすいません・・・

#3

投稿記事 by なぎ » 17年前

良く見たら、配列が定義されているので、割引簡単に、できそうですね。
読み込んですぐに表示せず、後でまとめて表示する、しないを決めます。

後ほど。

なぎ

Re:何度もすいません・・・

#4

投稿記事 by なぎ » 17年前

おおよそこんな感じでできます。
ただ、このプログラムでは、わざわざポインタを使っている必然性が感じられません。
(ポインタの使い方の練習?)

それも考慮すると、
case 'd':

    while (fscanf(fp, "%s %d %d %d", data[ch].name, &data[ch].eng, &data[ch].mat, &data[ch].sci) == 4)
    {
      ch++;
      if (ch==5)   break;
    }

    if (ch < 5) // データが5人分以下なら
    {
        for (i = 0; i <= ch; i++)
        {
            printf("名前:%s\n",data[ch].name);
            printf("英語:%d\n",data[ch].eng);
            printf("数学:%d\n",data[ch].mat);
            printf("理科:%d\n\n",data[ch].sci);
        }
    }

break;
あとこういう場合は、for() の構文でこう書くこともあります。
(以前は、よく見かけたが)
case 'd':

    for (ch = 0; (ch < 5) && (fscanf(fp, "%s %d %d %d", data[ch].name, &data[ch].eng, &data[ch].mat, &data[ch].sci) == 4); ch++);
    // こちらの for() ループの実体は、空文だけ。

    if (ch < 5) // データが5人分以下なら
    {
        for (i = 0; i <= ch; i++)
        {
            printf("名前:%s\n",data[ch].name);
            printf("英語:%d\n",data[ch].eng);
            printf("数学:%d\n",data[ch].mat);
            printf("理科:%d\n\n",data[ch].sci);
        }
    }

break;
あと、後者の構文を使う時には、 「&& は、左側から順次チェックして、偽になった時点でそれ以降の評価は行わない」という規則が有効に機能しています。

ch が 5 になった時点で、(ch < 5) が偽になります。すると、この後は評価しないので、data[5] がアクセスされることはありません。

sub

Re:何度もすいません・・・

#5

投稿記事 by sub » 17年前

どうもありがとうございます。ほぼ1週間ネットできない状況が続いていました。
返事が遅れてしまいすいません。

case 'd'の中を二つに分ければよかったんですね・・・
こういうのが全く思いつかない自分にいらいらします・・・

今またこのプログラムをちょっといじってつくるものをしているところですので、
またわからないことがあると思うので、その時は教えていただけると幸いです。

ありがとうございました。

sub

Re:何度もすいません・・・

#6

投稿記事 by sub » 17年前

#include <stdio.h>

int mis(FILE *fpm); 

typedef struct score{ 
char   name[40]; 
int    eng; 
int    mat; 
int    sci; 
} Score; 

Score data[5]; 

int main(void) 
{ 
FILE *fp; 
char cmd[20], fname[20], rank; 
int j=0,m; 

while (rank!='q'){ 
       printf("CMD>"); 
       fflush(stdout); 
       fgets(cmd, 20, stdin); 
       sscanf(cmd, "%c %s", &rank, fname); 
     
     
     switch(rank){ 
        	
        	
     case 'r':  
            if ((fp = fopen(fname, "r")) == NULL){ 
            printf("Cannot open the File!\n"); 
            return (-1); 
        }                 m=mis(fp);
        if (m==1){ 
        return (-1); 
        } 
        break; 
        
        
     case 'd':          for (j=0;j<=m;j++){ 
           printf("名前:%s\n",data[j].name); 
           printf("英語:%d\n",data[j].eng); 
           printf("数学:%d\n",data[j].mat); 
           printf("理科:%d\n\n",data[j].sci);              }                break; 
     
     
     case 'q': 
        fclose(fp); 
        printf("File close!\n"); 
        break; 
     default: 
        printf("コマンドを正しく入力してください\n"); 
    } 
} 
    return (0); 
} 

int mis(FILE *fpm) 
{ 
     int i, k,m; 

     for (i=0;i<=5;i++){ 
       k = fscanf(fpm, "%s %d %d %d", data.name, &data.eng, &data.mat, &data.sci); 
              if(1<=k && k<=3){ 
       printf("%d番目のデータが不正です\n", i+1); 
       return(1); 
       } 
       else if(i==5 && k==4){ 
       printf("Error!!\n"); 
       return (1); 
       } 
       else if (k== -1){ 
       m=i-1; 
       break; 
       } 
} 
return (m); 
}


いろいろ改良してこんなふうになりました。

次の質問なのですが、mallocを使って成績データを読み込む前に、まず成績データの件数を入力し、これをもとに配列の記憶領域を動的(プログラム実行時)に確保する。
ということなんですがどうもわかりません・・・

まずファイルに

10 ←人数
g 40 40 40 1人目
t 40 40 40 2人目

として今のファイルだと10人分の記憶領域を作るということなんですが・・・
sizeof演算子とかつかわないといけないのでしょうか?
教えていただけると幸いです。

閉鎖

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