ページ 11

構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 13:32
by po_po
氏名,年齢,身長(整数),体重(整数)の4つのデータをメンバにして,構造体keisokuを宣言しキーボードから入力された文字列file[]をファイル名とするファイルからデータを入力して年代ごとの平均身長と平均体重をそれぞれ小数点以下第1位(第2位以下切り捨て)まで求めて表示するプログラムを作ったのですが、結果が正しく出力されません。ファイルの中身は
{"佐藤", 41, 189, 97},
{"鈴木", 22, 178, 61},
{"高橋", 47, 178, 80},
{"田中", 14, 180, 80},
{"渡辺", 33, 192, 94},
{"伊藤", 12, 150, 51},
{"山本", 55, 185, 98},
{"中村", 17, 170, 88},
{"小林", 35, 187, 77},
{"加藤", 49, 179, 91},
{"吉田", 36, 182, 61},
{"山田", 44, 184, 71},
{"佐々木", 15, 151, 81},
{"山口", 50, 188, 93},
{"松本", 17, 178, 68},
{"井上", 13, 144, 81},
{"斎藤", 17, 163, 55},
{"木村", 23, 175, 105},
{"林", 29, 161, 79},
{"清水", 49, 185, 102},
{"山崎", 40, 187, 99},
{"森", 34, 189, 80},
{"阿部", 50, 183, 81},
{"池田", 37, 186, 97},
{"橋本", 15, 185, 83}
のようになっています
どこが間違っているのか教えてください

コード:

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

typedef struct {
  char name[10];
  int age;
  int stature;
  int weight;
} keisoku;

keisoku a[25];

main(){
FILE *fp;
char filename[10];
printf("ファイル名を入力して下さい\n");
scanf("%s",filename);
int n;
if(( fp=fopen( filename, "r" ))==NULL ) {
fprintf ( stderr, "File open error\n" ); exit( 1 );
}
fscanf( fp, "%d", &n );

 int Age[25];
 double Stature[25], Weight[25];
 int i;
 for(i = 0; i < 25; i++){
   Age[i] = a[i].age / 10;
   Stature[i] = a[i].stature;
   Weight[i] = a[i].weight;
 }
 double sumstature[5], sumweight[5];
 int num[5];

 int k,l,j;
 for(l = 1; l <= 5; l++){
 for(k = 0; k < 25; k++){
   if(Age[k] == l){
     sumstature[l-1] = Stature[k] + sumstature[l-1];
     sumweight[l-1] = Weight[k] + sumweight[l-1];
     num[l-1]++;
   }
   }
 }

 for(j = 0; j < 5; j++){
   sumstature[j] = sumstature[j]/num[j];
   sumweight[j] = sumweight[j]/num[j];
 }
 

 int astature[5],aweight[5];
 int m;
 for(m = 0; m < 5; m++){
   astature[m] = 10*sumstature[m];
   sumstature[m] = astature[m]/10;
   aweight[m] = 10*sumstature[m];
   sumweight[m] = aweight[m]/10;
 }

 int o;
 for(o = 0; o < 5;o++){
   printf("%d0代の平均身長は%.1f,平均体重は%.1fです.\n",o + 1,sumstature[o],sumweight[o]);
 }


fclose( fp );
}

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 15:25
by みけCAT
とりあえず、ファイルの中身に合わせた読み込み処理が全く書かれていない、ひどいプログラムですね。

他にも、
  • ファイル名としてfile[]が使われていない
  • 未初期化で不定の値であるsumstature、sumweight、num (の要素)が計算に使用されている
というのが致命的と思われる間違いですね。

致命的ではないがおかしい所は
  • ファイル名の読み込みでバッファオーバーランのリスクがある(書式で読み込む最大の長さを指定するべき)
  • main関数の定義が処理系依存(int main(void)とするべき)
  • ファイルの内容によって、numの要素が0であった場合にゼロ除算が発生する
  • astatureやaweightは1個だけ確保して各要素で使い回せばいいはずなのに、メモリが少し無駄になっている
という点がありますね。

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 16:55
by po_po
filenameをファイル名とするファイルを入力するプログラムでした書き間違えてましたすいません。
言われた通りなおしてみたのですがうまく動いてくれませんでした
どこがおかしいのでしょうか、

コード:

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

typedef struct {
  char name[10];
  int age;
  int stature;
  int weight;
} keisoku;

keisoku a[25];

int main(void){
FILE *fp;
char filename[10];
printf("ファイル名を入力して下さい\n");
scanf("%s",filename);
int n;
if(( fp=fopen( filename, "r" ))==NULL ) {
fprintf ( stderr, "File open error\n" ); exit( 1 );
}
fscanf( fp, "%d", &n );
int b;
for(b = 0; b < 25; b++){
	fscanf( fp, "%s,%d,%d,%d",&a[b].name,&a[b].age,&a[b].stature,&a[b].weight);
}
	
 int Age[25];
 double Stature[25], Weight[25];
 int i;
 for(i = 0; i < 25; i++){
   Age[i] = a[i].age / 10;
   Stature[i] = a[i].stature;
   Weight[i] = a[i].weight;
 }
 double sumstature[5]={0,0,0,0,0};
 double sumweight[5] = {0,0,0,0,0};
 int num[5] = {0,0,0,0,0};

 int k,l,j;
 for(l = 1; l <= 5; l++){
 for(k = 0; k < 25; k++){
   if(Age[k] == l){
     sumstature[l-1] = Stature[k] + sumstature[l-1];
     sumweight[l-1] = Weight[k] + sumweight[l-1];
     num[l-1]++;
   }
   }
 }

 for(j = 0; j < 5; j++){
   sumstature[j] = sumstature[j]/num[j];
   sumweight[j] = sumweight[j]/num[j];
 }
 

 int astature[5],aweight[5];
 int m;
 for(m = 0; m < 5; m++){
   astature[m] = 10*sumstature[m];
   sumstature[m] = (double)astature[m]/10;
   aweight[m] = 10*sumweight[m];
   sumweight[m] = (double)aweight[m]/10;
 }

 int o;
 for(o = 0; o < 5;o++){
   printf("%d0代の平均身長は%.1f,平均体重は%.1fです.\n",o + 1,sumstature[o],sumweight[o]);
 }


fclose( fp );
}


Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 18:39
by かずま
po_po さんが書きました: 言われた通りなおしてみたのですがうまく動いてくれませんでした
どこがおかしいのでしょうか、

コード:

{"佐藤", 41, 189, 97},
{"鈴木", 22, 178, 61},
ファイルの先頭は本当にこうですか?
それなら、22行目の fscanf( fp, "%d", &n ); を n = 25; に変更。
25行目の fscanf の書式を

コード:

    " {\"%[^\"]\",%d,%d,%d},"
に変更。{ の前のスペースは必須。

これでどうなりますか?

もしもファイルの先頭が

コード:

25
佐藤, 41, 189, 97
なら、22行目の fscanf はそのまま。25行目の fscanf の書式は、

コード:

    " %[^,],%d,%d,%d"
に変更。%[ の前のスペースは必須。

ファイルが元のままだとして、こんなプログラムでもほぼ同じ出力になります。
構造体を使っていないので、課題の解答ではありませんが。

コード:

#include <stdio.h>

int main(void)
{
    FILE *fp;
    char file[100];
    int i, age, stature, weight;
    int num[10] = {0}, sum_stature[10] = {0}, sum_weight[10] = {0};

    printf("ファイル名を入力して下さい\n");
    scanf("%99s", file);
    fp = fopen(file, "r");
    if (!fp) { fprintf(stderr, "File open error\n"); return 1; }

    while (fscanf(fp, "%*[^,],%d,%d,%d},", &age, &stature, &weight) == 3) {
        i = age / 10;
        if (i > 9) i = 9;
        num[i]++,  sum_stature[i] += stature,  sum_weight[i] += weight;
    }
    fclose(fp);

    for (i = 0; i < 10; i++)
        if (num[i] > 0) {
            double n = num[i];
            printf("%d0代の平均身長は %.1f, 平均体重は %.1fです.\n",
                    i, sum_stature[i] / n, sum_weight[i] / n);
        }
    return 0;
}

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 19:49
by po_po
ファイルの先頭は25という数字が入っています 書き忘れていました
25行目の書式を直したのですが、うまくいきませんでした。
構造体に直接値を代入して計算してみたところ結果は正しいものとなっていたので計算部分は合っていて、ファイルの入力の部分が間違っていると思われます。
どこがおかしいのでしょうか・・

コード:

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

typedef struct {
  char name[10];
  int age;
  int stature;
  int weight;
} keisoku;

keisoku a[25];

int main(void){
FILE *fp;
char filename[10];
printf("ファイル名を入力して下さい\n");
scanf("%s",filename);
int n;
if(( fp=fopen( filename, "r" ))==NULL ) {
fprintf ( stderr, "File open error\n" ); exit( 1 );
}
fscanf( fp, "%d", &n );
int b;
for(b = 0; b < 25; b++){
	fscanf( fp, " %[^,],%d,%d,%d",a[b].name,&a[b].age,&a[b].stature,&a[b].weight);
}
	
	fclose(fp);
	
 int Age[25];
 double Stature[25], Weight[25];
 int i;
 for(i = 0; i < 25; i++){
   Age[i] = a[i].age / 10;
   Stature[i] = a[i].stature;
   Weight[i] = a[i].weight;
 }
 double sumstature[5]={0};
 double sumweight[5] = {0};
 int num[5] = {0};

 int k,l,j;
 for(l = 1; l <= 5; l++){
 for(k = 0; k < 25; k++){
   if(Age[k] == l){
     sumstature[l-1] = Stature[k] + sumstature[l-1];
     sumweight[l-1] = Weight[k] + sumweight[l-1];
     num[l-1]++;
   }
   }
 }

 for(j = 0; j < 5; j++){
   sumstature[j] = sumstature[j]/num[j];
   sumweight[j] = sumweight[j]/num[j];
 }
 

 int astature[5],aweight[5];
 int m;
 for(m = 0; m < 5; m++){
   astature[m] = 10*sumstature[m];
   sumstature[m] = (double)astature[m]/10;
   aweight[m] = 10*sumweight[m];
   sumweight[m] = (double)aweight[m]/10;
 }

 int o;
 for(o = 0; o < 5;o++){
   printf("%d0代の平均身長は%.1f,平均体重は%.1fです.\n",o + 1,sumstature[o],sumweight[o]);
 }

}

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 20:48
by かずま
po_po さんが書きました:ファイルの先頭は25という数字が入っています 書き忘れていました
25行目の書式を直したのですが、うまくいきませんでした。
構造体に直接値を代入して計算してみたところ結果は正しいものとなっていたので計算部分は合っていて、ファイルの入力の部分が間違っていると思われます。
どこがおかしいのでしょうか・・
「うまくいきませんでした」だけではいけません。どうなったかを書きましょう。
ファイルの 1行目が 25 であることは分かりました。
ファイルの 2行目はどうなっていますか? 正確に書いてください。
区切りの , の前にスペースがあるとか、最後の数字の後にも , があるとかです。

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 21:10
by po_po
ファイルの中身は
25
佐藤 41 180 71
鈴木 15 174 65
・・・
といったようなものになっています

結果は
ファイル名を入力して下さい
list.txt
10代の平均身長は-214748364.8,平均体重は-214748364.8です.
20代の平均身長は-214748364.8,平均体重は-214748364.8です.
30代の平均身長は-214748364.8,平均体重は-214748364.8です.
40代の平均身長は-214748364.8,平均体重は-214748364.8です.
50代の平均身長は-214748364.8,平均体重は-214748364.8です.
上のようになります

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 21:27
by かずま
po_po さんが書きました:ファイルの中身は
25
佐藤 41 180 71
鈴木 15 174 65
・・・
といったようなものになっています
ファイルに「,」がないのに、書式に「,」があるのをおかしいと思いませんか?
少しは考えてください。
書式は "%s%d%d%d" だけです。

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 21:30
by box
po_po さんが書きました:ファイルの中身は
25
佐藤 41 180 71
鈴木 15 174 65
・・・
といったようなものになっています
ファイルの中身が変わってしまいましたね。
{
とか
,
とか
}
とかはどこへ行ったんですか?

メモ帳などのエディターで開いた内容をそのまま貼り付けることはできますか?

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 21:57
by po_po
すいません。ファイルの入出力についてよくわかっていないので書式の重要性を知りませんでした
ファイルの中身は
25
佐藤 41 189 97
鈴木 22 178 61
高橋 47 178 80
田中 14 180 80
渡辺 33 192 94
伊藤 12 150 51
山本 55 185 98
中村 17 170 88
小林 35 187 77
加藤 49 179 91
吉田 36 182 61
山田 44 184 71
佐々木 15 151 81
山口 50 188 93
松本 17 178 68
井上 13 144 81
斎藤 17 163 55
木村 23 175 105
林 29 161 79
清水 49 185 102
山崎 40 187 99
森 34 189 80
阿部 50 183 81
池田 37 186 97
橋本 15 185 83
です

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 22:12
by box
po_po さんが書きました: 佐藤 41 189 97
ということならば、書式文字列は"%s%d%d%d"でじゅうぶんでありましょう。

ところで、ソースコードの中に「25」というマジックナンバーがちりばめられていて、
あたかも「ファイルの中身を読む『前から』データの件数が25であることがわかっているかのごとく」
振る舞ってますね。

もし、実行時に動的に領域を確保するmalloc()系の関数をご存じならば、
po_po さんが書きました: 25
この1行目を読んだ時点で25人分の領域を確保するようなコードを書く方がより適切ではないかと思います。

malloc()系の関数を知らなかったら?
25よりも多めの要素数を配列として確保しておくしかなさそうに思います。

Re: 構造体を作り、ファイルからデータを入力してその値の平均値を求めるプログラム

Posted: 2015年12月24日(木) 22:31
by po_po
解決しました。
ファイルの入出力の書式について理解していませんでした。
回答してくださった
みけCATさん、かずまさん、boxさんありがとうございました。