C言語のプログラムです。どなたかご助力お願いいたします。

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

C言語のプログラムです。どなたかご助力お願いいたします。

#1

投稿記事 by misa » 10年前

100人以下の学生の学籍番号、3つの科目(英語、数学、国語)の得点が記録されたデータファイルがあります。
(ファイルの中身)
E0000 90 85 93

これらのデータを読み込んでいき、各合計点を計算し、各科目と合計点の平均・標準偏差を読み込んだ順に出力するプログラムを作成しています。
しかしなかなかうまくいきません。
出力結果は、

ID   Eng  Math Jap Total
------ ---- ---- ---- -----
E0000 90  85   93 268
...
...
------------------------------------
Avr 75.1 80.5 85.7 254.2
Avr 36.7 19.4 15.9 58.2

このような形にしたいのです。
Totalの部分がうまくいっていないように感じられるのですが、どのようにしたらいいのかわかりません。
ご教授よろしくお願いいたします。

コード:

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

typedef struct{
  char id[6];
  int eng;
  int math;
  int jap;
  int total;
} Student;

int main(void)
{
  Student student[101];
  int num, scan_val, i;
  double total,avr_e, avr_m, avr_j, dev_e, dev_m, dev_j;

  for(num=0; num<101;){
    scan_val=scanf("%5s %d %d %d",student[num].id,&student[num].eng,&student[num].math,&student[num].jap);
    if(scan_val == 4)
      num++;
    else if (scan_val == EOF)
      break;
    else {
      printf("Warning: Illegal data appears.(%d-th data)\n",num);
      break;
    }
  }

  if(num == 101){
    printf("Warning: There are 101 or more student.\n"
	   "         ==> We process first 101 student.\n");
  }

  total=0.0
    for(i=0;i<num;++i){
      student.total.=student.eng+student.math+student.jap;
    }

  avr_e=0.0
    for(i=0;i<num;++i){{
      avr_e+=student[i].eng;
    }
      avr_e/=num;
    }
  
  avr_m=0.0
    for(i=0;i<num;++i){{
      avr_m+=student[i].math;
    }
      avr_m/=num;
    }

  avr_j=0.0
    for(i=0;i<num;++i){{
      avr_j+=student[i].jap;
    }
      avr_j/=num;
    }

  dev_e=0.0
    for(i=0;i<num;++i){
      dev_e+=(student[i].eng=avr_e)*(student[i].eng - avr_e);
      dev_e/=num;
      dev_e=sprt(dev_e)
    }
 
  dev_m=0.0
    for(i=0;i<num;++i){
      dev_m+=(student[i].math=avr_m)*(student[i].math - avr_m);
      dev_m/=num;
      dev_m=sprt(dev_m)
    } 

  dev_j=0.0
    for(i=0;i<num;++i){
      dev_j+=(student[i].jap=avr_j)*(student[i].jap - avr_j);
      dev_j/=num;
      dev_j=sprt(dev_j)
    }

  printf("Id-no   Eng  Math   Jap   Total \n"
	 "-----  ----  ---- ---- -----\n");
  for (i=0;i<num;i++)
    printf("%5s %3d %3d %3d %3d\n",student[i].id,student[i].eng,student[i].math,student[i].jap,student.total);
  printf("------------------------------\n");
    printf("Avr %2.1f %2.1f %2.1f %2.1f\n",avr_e,avr_m,avr_j,total);
  
    printf("------------------------------\n");
    printf("Dev %2.1f %2.1f %2.1f %2.1f\n",dev_e,dev_m,dev_j,total);

  return 0;
}
 
また、
学生の人数は100人以下で不定とすること、一人一人のデータは構造体としStudentというデータ型名を付け、Student型を用とする配列を用意する
という条件があるのですが、きちんと条件どおりになっているでしょうか?

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

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#2

投稿記事 by amehirune » 10年前

パッと見ただけですが、totalを求める式に、
misa さんが書きました:

コード:

   total=0.0
    for(i=0;i<num;++i){
      student.total.=student.eng+student.math+student.jap;
    }
となってるのが気になります。
studentは構造体配列なのに対し、添え字(だったっけ?)がありません。
正しくは、

コード:

   total=0.0
    for(i=0;i<num;++i){
      student[i].total.=student[i].eng+student[i].math+student[i].jap;
    }
とすべきです。

ざっと見ただけなので、詳しいところはわかりません。ごめんなさい^^;
ほら、来いよ!! 誤字や矛盾を指摘したい奴から、前に出てこいよぉおおおおおおおッ!!!
※都合により、不定期でしか現れません。即返などはできませんのでご了承ください※

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#3

投稿記事 by misa » 10年前

>> amehirune様
失念しておりました!
ご助言感謝致します。

超初級者
記事: 56
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#4

投稿記事 by 超初級者 » 10年前

100人以下、という仕様であるのに対し、
101人まで入力できるように見える点に
ついては、どのようにお考えですか?

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#5

投稿記事 by misa » 10年前

>> 超初級者様
これはデータ数が100を超えた場合にエラーを返すことが出来るようにする為です。
100を超えた場合、一旦101番目に読み込み、

コード:

if(num == 101){
    printf("Warning: There are 101 or more student.\n"
       "         ==> We process first 101 student.\n");
  }
この部分にてエラー処理をするようにしたつもりです。

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

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#6

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

提示されたコードは、「普通」のC言語としてコンパイルしようとすると、
大量のエラーがあってコンパイルできません。
特殊な環境をお使いですか?

コード:

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

typedef struct{
  char id[6];
  int eng;
  int math;
  int jap;
  int total;
} Student;

int main(void)
{
  Student student[101];
  int num, scan_val, i;
  double total,avr_e, avr_m, avr_j, dev_e, dev_m, dev_j;

  for(num=0; num<101;){
    scan_val=scanf("%5s %d %d %d",student[num].id,&student[num].eng,&student[num].math,&student[num].jap);
    if(scan_val == 4)
      num++;
    else if (scan_val == EOF)
      break;
    else {
      printf("Warning: Illegal data appears.(%d-th data)\n",num);
      break;
    }
  }

  if(num == 101){
    printf("Warning: There are 101 or more student.\n"
	   "         ==> We process first 101 student.\n");
  }

  total=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){
      /* 添字がない(No: 2で指摘済み)、C言語に.=という演算子は無いはず */
      student.total.=student.eng+student.math+student.jap;
    }

  avr_e=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){{
      avr_e+=student[i].eng;
    }
      avr_e/=num;
    }
  
  avr_m=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){{
      avr_m+=student[i].math;
    }
      avr_m/=num;
    }

  avr_j=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){{
      avr_j+=student[i].jap;
    }
      avr_j/=num;
    }

  dev_e=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){
      /* 同じ式で順番が不定の代入と参照をしているので、結果が未定義になる */
      dev_e+=(student[i].eng=avr_e)*(student[i].eng - avr_e);
      dev_e/=num;
      dev_e=sprt(dev_e) /* sprtという関数は標準で無さそう、セミコロンが無い */
    }
 
  dev_m=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){
      /* 同じ式で順番が不定の代入と参照をしているので、結果が未定義になる */
      dev_m+=(student[i].math=avr_m)*(student[i].math - avr_m);
      dev_m/=num;
      dev_m=sprt(dev_m) /* sprtという関数は標準で無さそう、セミコロンが無い */
    } 

  dev_j=0.0 /* セミコロンが無い */
    for(i=0;i<num;++i){
      /* 同じ式で順番が不定の代入と参照をしているので、結果が未定義になる */
      dev_j+=(student[i].jap=avr_j)*(student[i].jap - avr_j);
      dev_j/=num;
      dev_j=sprt(dev_j) /* sprtという関数は標準で無さそう、セミコロンが無い */
    }

  printf("Id-no   Eng  Math   Jap   Total \n"
	 "-----  ----  ---- ---- -----\n");
  for (i=0;i<num;i++)
    /* 第6引数で必要な添字が無い */
    printf("%5s %3d %3d %3d %3d\n",student[i].id,student[i].eng,student[i].math,student[i].jap,student.total);
  printf("------------------------------\n");
    printf("Avr %2.1f %2.1f %2.1f %2.1f\n",avr_e,avr_m,avr_j,total);
  
    printf("------------------------------\n");
    printf("Dev %2.1f %2.1f %2.1f %2.1f\n",dev_e,dev_m,dev_j,total);

  return 0;
}
amehirune さんが書きました:正しくは、

コード:

   total=0.0
    for(i=0;i<num;++i){
      student[i].total.=student[i].eng+student[i].math+student[i].jap;
    }
とすべきです。
total=0.0の後にセミコロンが無く、student.totalの後ろに余計なドットがあるので、
「普通」のC言語であれば正しくありません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

超初級者
記事: 56
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#7

投稿記事 by 超初級者 » 10年前

misa さんが書きました:

コード:

 if(num == 101){
   printf("Warning: There are 101 or more student.\n"
      "         ==> We process first 101 student.\n");
 }
初めの101人について処理する、と。
「100人以下の」という仕様と明らかに食い違っていますが、
どのように説明なさいますか?

100人以下、って言ってるのですから、「最大でも100回ループすればよい」
のではありませんか?

それから、最初に提示されているコードで、
代入文の最後にセミコロンが付いていない箇所が多数あります。
これじゃあコンパイルエラーですよね。

とりあえずコンパイルができているコードを載せてくださると、
話が進みやすくなると思います。

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#8

投稿記事 by misa » 10年前

>> みけCAT様

いろいろと疎かになってしまっていて申し訳ありません。
ご指摘いただいた添え字とセミコロンを書き加えました。
sprtはsqrtのミスでした。大変失礼いたしました。

使用しているのはLinuxです。

「同じ式で順番が不定の代入と参照をしているので、結果が未定義になる」
とのご指摘を頂きましたが、よく理解できません。理解力がなく大変申し訳ないのですが、
もう少し詳しくご教授願えませんでしょうか。

コード:

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

typedef struct{
  char id[6];
  int eng;
  int math;
  int jap;
  int total;
} Student;

int main(void)
{
  Student student[101];
  int num, scan_val, i;
  double total,avr_e, avr_m, avr_j, dev_e, dev_m, dev_j;

  for(num=0; num<101;){
    scan_val=scanf("%5s %d %d %d",student[num].id,&student[num].eng,&student

[num].math,&student[num].jap);
    if(scan_val == 4)
      num++;
    else if (scan_val == EOF)
      break;
    else {
      printf("Warning: Illegal data appears.(%d-th data)\n",num);
      break;
    }
  }

  if(num == 101){
    printf("Warning: There are 101 or more student.\n"
	   "         ==> We process first 101 student.\n");
  }

  total=0.0;
    for(i=0;i<num;++i){
      student[i].total=student[i].eng+student[i].math+student[i].jap;
    }

/*各科目の平均を求める*/
  avr_e=0.0;
    for(i=0;i<num;++i){{
      avr_e+=student[i].eng;
    }
      avr_e/=num;
    }
  
  avr_m=0.0;
    for(i=0;i<num;++i){{
      avr_m+=student[i].math;
    }
      avr_m/=num;
    }

  avr_j=0.0;
    for(i=0;i<num;++i){{
      avr_j+=student[i].jap;
    }
      avr_j/=num;
    }

/*各科目の標準偏差を求める*/
  dev_e=0.0;
    for(i=0;i<num;++i){
      dev_e+=(student[i].eng=avr_e)*(student[i].eng - avr_e);
      dev_e/=num;
      dev_e=sqrt(dev_e);
    }
 
  dev_m=0.0;
    for(i=0;i<num;++i){
      dev_m+=(student[i].math=avr_m)*(student[i].math - avr_m);
      dev_m/=num;
      dev_m=sqrt(dev_m);
    } 

  dev_j=0.0;
    for(i=0;i<num;++i){
      dev_j+=(student[i].jap=avr_j)*(student[i].jap - avr_j);
      dev_j/=num;
      dev_j=sqrt(dev_j);
    }

/*データを出力*/
  printf("Id-no   Eng  Math   Jap   Total \n"
	 "-----  ----  ---- ---- -----\n");
  for (i=0;i<num;i++)
    printf("%5s %3d %3d %3d %3d\n",student[i].id,student[i].eng,student

[i].math,student[i].jap,student[i].total);
  printf("------------------------------\n");
    printf("Avr %2.1f %2.1f %2.1f %2.1f\n",avr_e,avr_m,avr_j,total);
  
    printf("------------------------------\n");
    printf("Dev %2.1f %2.1f %2.1f %2.1f\n",dev_e,dev_m,dev_j,total);

  return 0;
}

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#9

投稿記事 by misa » 10年前

>> 超初級者様

ご指摘ありがとうございます。
データが101あった場合、いったん配列の101番目の要素に読み込む必要があるのではないのでしょうか?
実際に処理を行えるのは100人までということになるので、条件を満たしているのではないかと考えておりました。
条件は、「学生の人数は100人以下で不定とする(100人以下ならプログラムを修正せずに対処できなければならない)」
というものです。説明不足で申し訳ありません。

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

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#10

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

misa さんが書きました:「同じ式で順番が不定の代入と参照をしているので、結果が未定義になる」
とのご指摘を頂きましたが、よく理解できません。理解力がなく大変申し訳ないのですが、
もう少し詳しくご教授願えませんでしょうか。
The C89 Draft さんが書きました:Except as indicated by the syntax or otherwise specified later (for the function-call operator () , && , || , ?: , and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
(http://port70.net/~nsz/c/c89/c89-draft.html#3.3)
と書かれているように、「普通」の二項演算子(*など)の左辺と右辺のどっちを先に評価するかはC言語では未定義です。
したがって、例えば

コード:

#include <stdio.h>

int main(void) {
	int a = 5, b = 3;
	int c = (a = b) * (a - b);
	printf("%d\n", c);
	return 0;
}
というコードを実行した時、5行目で(a = b)と(a - b)のどっちが先に実行(評価)されるかはわかりません。
もし(a = b)が先に評価された場合、cは3 * (3 - 3)すなわち0になります。
(a - b)が先に評価された場合、cは(a = 3) * (5 - 3)すなわち6になります。
このように、コンパイラの実装などによって結果が変わることがあるので、このような式を書くべきではありません。
上記のコードをgccでコンパイルすると

コード:

prog.c: In function 'main':
prog.c:5:13: warning: operation on 'a' may be undefined [-Wsequence-point]
 int c = (a = b) * (a - b);
            ^
という警告が、clangでコンパイルすると

コード:

prog.c:5:13: warning: unsequenced modification and access to 'a' [-Wunsequenced]
       int c = (a = b) * (a - b);
                  ^       ~
1 warning generated.
という警告が出ました。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

超初級者
記事: 56
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#11

投稿記事 by 超初級者 » 10年前

misa さんが書きました:100人以下の学生の
学籍番号、3つの科目(英語、数学、国語)の得点が記録された
データファイルがあります。
この仕様のもとでプログラムを書くのに、どうして101回ループする必要が
あるのでしょうか。

「ファイルそのものが100人以下」なのだから、
ループはたかだか100回でいいはずです。

あと、別の回答者さんから指摘が入っている件について。
そこは、本当に「=」でいいんですか?

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

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#12

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

超初級者 さんが書きました:
misa さんが書きました:100人以下の学生の
学籍番号、3つの科目(英語、数学、国語)の得点が記録された
データファイルがあります。
この仕様のもとでプログラムを書くのに、どうして101回ループする必要が
あるのでしょうか。

「ファイルそのものが100人以下」なのだから、
ループはたかだか100回でいいはずです。
どうしてたった1回の「無駄」なループに対してそんなに怒る(怒っているように感じる表現をする)のでしょうか?
本当の所は出題者に聞いてみないとわからないですが、100人以下のデータに対して正しく動作すれば、
200人に対応させても100億人に対応させても仕様を満たしていることにはならないでしょうか?

そんなことより、
misa さんが書きました:

コード:

    for(i=0;i<num;++i){{
      avr_e+=student[i].eng;
    }
      avr_e/=num;
    }
の部分でavr_eに我々がよく知っている平均値ではないものが格納される方が気になりますね。
avr_m, avr_jも同様です。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#13

投稿記事 by misa » 10年前

私の理解が及ばないばっかりにお手間をおかけし大変申し訳ありません。
「同じ式で順番が不定の代入と参照をしているので、結果が未定義になる」
という意味を理解することが出来ました。大変わかりやすいご説明ありがとうございます。

コード:

 dev_e=0.0;
    for(i=0;i<num;++i){
      dev_e+=((student[i].eng-avr_e)*(student[i].eng-avr_e));
      dev_e/=num;
      dev_e=sqrt(dev_e);
    }
 
  dev_m=0.0;
    for(i=0;i<num;++i){
      dev_m+=((student[i].math-avr_m)*(student[i].math-avr_m));
      dev_m/=num;
      dev_m=sqrt(dev_m);
    } 

  dev_j=0.0;
    for(i=0;i<num;++i){
      dev_j+=((student[i].jap-avr_j)*(student[i].jap-avr_j));
      dev_j/=num;
      dev_j=sqrt(dev_j);
    }
平均については考え直してみます。


超初級者
記事: 56
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#15

投稿記事 by 超初級者 » 10年前

そもそも100人以下だっていってるんだから、
misa さんが書きました:

コード:

 Student student[101];
 for(num=0; num<101;){
ここは素直に

コード:

   Student student[100];
   for (num = 0; num < 100;) {
って書けばいいし、
misa さんが書きました:

コード:

 if(num == 101){
ここのくだりは不要です。
余分なコードを書いたがために変な動きをすることだってあるってことで。

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

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#16

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

超初級者 さんが書きました:余分なコードを書いたがために変な動きをすることだってあるってことで。
確かにそういうこともありますが、今回はここのエラー処理という「余分なコード」を書いたがために「変な動き」をしていますか?
仕様外の入力に対してエラーメッセージを表示する、という処理を入れることは、
超初級者 さんが書きました:「100人以下の」という仕様と明らかに食い違っていますが、
どのように説明なさいますか?
というように、「仕様と明らかに食い違って」いる行為ですか?

もちろん絶対に仕様外の入力はされない(とされる)オンラインジャッジであればエラー処理は不要ですが、
今回の課題がそのような性質のものであるかはわからないので、
超初級者さんやmisaさんの考えはどうかわかりませんが、私は今回の課題でエラー処理を作ることは
「仕様と明らかに食い違って」いるほどの重罪だとは思えません。
エラー処理を付ける場合は、
超初級者 さんが書きました:

コード:

   Student student[100];
   for (num = 0; num < 100;) {
としてしまうと、データがちょうど100件入力されたのか、まだデータがあるのに打ち切られたのかわからないので、
misa さんが書きました:

コード:

 Student student[101];
 for(num=0; num<101;){
として、データが100件を超えるかの判定に利用するほうがいいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#17

投稿記事 by misa » 10年前

超初級者様、 みけCAT様、ご意見ありがとうございます。
エラー処理があることで減点されるようなことはないと思うので、エラー処理に関してはこのままにしておきたいと思います。(教科書の似たような例題でもエラー処理はありました)

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#18

投稿記事 by misa » 10年前

平均の計算は、次のようにしてもダメでしょうか…?

コード:

avr_e=0.0;
    for(i=0;i<num;++i){
      scanf("%lf",&student[i].eng);
      avr_e+=student[i].eng;
    }
      avr_e/=num;

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

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#19

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

misa さんが書きました:平均の計算は、次のようにしてもダメでしょうか…?

コード:

avr_e=0.0;
    for(i=0;i<num;++i){
      scanf("%lf",&student[i].eng);
      avr_e+=student[i].eng;
    }
      avr_e/=num;
自分でテストはしましたか?
そのようなデータの読み込み方では、提示された入力の条件と合わない気がします。
今回の仕様とは関係ない「平均の計算」としては大丈夫だと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

misa
記事: 9
登録日時: 10年前

Re: C言語のプログラムです。どなたかご助力お願いいたします。

#20

投稿記事 by misa » 10年前

>>みけCAT様
>自分でテストはしましたか?
自宅ではコンパイルできないのです。(visualC?をダウンロードしてみたのですがうまく動きません…)
翌朝、学校でテストしてみます。

>そのようなデータの読み込み方では、提示された入力の条件と合わない気がします。
うーん、難しいものですね…習い始めたばかりでなかなか思うように組み立てることが出来ません。
もう少し考え直してみます。

閉鎖

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