こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

平均値を関数を用いて出力したいのですが。。

平均値を関数を用いて出力したいのですが一箇所でつまずいてしまい
ました。ソースは
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*構造体宣言*/
struct Students{
int N;
int A;
int B;
int C;
double ave;
};

/*平均値を計算する関数*/
struct Students Average(struct Students std[i]){
std[i].ave=(double)(std[i].A+std[i].B+std[i].C)/3;
return std[i];
}

int main(void){
struct Students std[49]; /*構造型配列*/

int i,N,A,B,C,num,scannum;

FILE*file; /*ファイルのポインタを用意*/

srand((unsigned)time(NULL)); /*乱数の初期化/


file=fopen("Data.txt","r"); /*Dataファイルの読み込み*/

/*ファイルのオープンチェック*/
if(file==NULL){
fprintf(stderr,"cannnot open file 'Data.txt'\n");
exit(1);
}
/*Studentsにデータを格納*/
for(i=0;i<=49;i++){
fscanf(file,"%d%d%d",&N,&A,&B);
std[i].N=N;
std[i].A=A;
std[i].B=B;
std[i].C=70+(rand()/(RAND_MAX+1.0)*31);
std[i].ave=Average(std[i]);

/*表示*/
printf("学籍番号:%d.",std[i].N);
printf("科目A:%d.\n",std[i].A);
printf("科目B:%d.\n",std[i].B);
printf("科目C:%d.\n",std[i].C);
printf("平均点:%d.\n",std[i].ave);

fclose(file);

return 0;
}
目標はA,B,Cの平均を出したいのですが関数宣言の際にstd[i]を
用いると未定義扱いになってしまい実行が出来ない状態です。
自分としては↑のソースでi番目の配列の平均値を導出し、表示
させようとしてるのですが。。。。アドバイスをお願いします。
m(__)m

投稿日時 - 2008-07-12 01:20:06

QNo.4169739

困ってます

質問者が選んだベストアンサー

double Average(struct Students tmp);
{
return (double)(tmp.A+tmp.B+tmp.C)/3;
}

のようにするべきでは?

関数を呼び出すときの引数は値をコピーするための一時的な変数です。

std[i].ave = Average(std[i]);

としてAverage関数を呼び出すときには

struct Students Average(struct Students tmp)
tmp = std[i];
{
return (double)(tmp.A+tmp.B+tmp.C)/3;
}

とちょっと書き方は変になりますが、std[i]という変数を一時的に引数で宣言されている変数にコピーして
関数の中で計算を行いますので、std[i]のように名前が同じである必要がありません。
名前を同じにしても良いのですが、関数の中と外とでは全く違う変数として扱われます。
また、引数として宣言できる変数名は普通の変数宣言と同じ形式ですので
std[i]というような変数名を宣言することはできません。

あと、averageの中身ですが平均値を計算したいのであれば上記のように
平均値を戻り値としないと

std[i].ave=Average(std[i]);

で、型が違うのでエラーがでるのでは?

投稿日時 - 2008-07-12 01:43:39

補足

アドバイスありがとうございます。参考にさせて頂いたのですが
自信がありません。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*構造体宣言*/
struct Students{
int N;
int A;
int B;
int C;
double ave;
};

/*平均値を計算する関数*/
struct Students Average(struct Students tmp){/*←構造体tmpを引数とする平均関数*/
tmp=std[i]; /*平均関数の式。構造体tmpに構造体std[i]の値を代入*/
tmp.ave=(double)(tmp.A+tmp.B+tmp.C)/3; /*平均関数の式2.↑から得た平均値を求める*/
return(double)tmp.ave; /*戻り値は平均値*/
}

int main(void){
struct Students std[50]; /*構造型配列*/

int i,N,A,B,C,num,scannum;

FILE*file; /*ファイルのポインタを用意*/

srand((unsigned)time(NULL)); /*乱数の初期化*/


file=fopen("Data.txt","r"); /*Dataファイルの読み込み*/

/*ファイルのオープンチェック*/
if(file==NULL){
fprintf(stderr,"cannnot open file 'Data.txt'\n");
exit(1);
}
/*Studentsにデータを格納*/
for(i=0;i<=49;i++){
fscanf(file,"%d%d%d",&N,&A,&B);
std[i].N=N;
std[i].A=A;
std[i].B=B;
std[i].C=70+(rand()/(RAND_MAX+1.0)*31);
std[i].ave=Average(tmp);

/*表示*/
printf("学籍番号:%d.",std[i].N);
printf("科目A:%d.\n",std[i].A);
printf("科目B:%d.\n",std[i].B);
printf("科目C:%d.\n",std[i].C);
printf("平均点:%f.\n",std[i].C);

fclose(file);

return 0;
}
アドバイスを頂いた関数の部分に自分なりの解釈をメモしたのですが
これで正しいでしょうか?このソースでコンパイルするとエラーが
出てきてしまいました。

1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(16) : error C2065: 'i' : 定義されていない識別子です。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(16) : error C2109: 配列または、ポインタでない変数に添字が使われました。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(18) : error C2440: 'return' : 'double' から 'Students' に変換できません。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(44) : warning C4244: '=' : 'double' から 'int' への変換です。データが失われる可能性があります。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(45) : error C2065: 'tmp' : 定義されていない識別子です。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(45) : error C2440: '関数' : 'int' から 'Students' に変換できません。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(45) : warning C4024: 'Average' : の型が 1 の仮引数および実引数と異なります。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(45) : error C2440: '=' : 'Students' から 'double' に変換できません。
1>c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(58) : fatal error C1075: 左側 中かっこ '{' に対応するものが 'c:\documents and settings\devil\my documents\visual studio 2008\projects\レポート\レポート\test1.c(21)' で見つかる前に EOF が検出されました。

以前に他の方のアドバイスも参考にさせていただきだいぶエラーが減
ったのですが未だに。。。。

投稿日時 - 2008-07-12 03:01:57

お礼

大変参考になりました。当初はこのアドバイスでもいまいち理解に
かけていましたが引数と仮引数、左と右の型に注目することで
実行することが出来ました。ありがとうございました。

投稿日時 - 2008-07-12 16:12:54

ANo.3

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

-広告-
-広告-

回答(8)

ANo.8

#4です。
>[49]とすると0から49までの合計50個になる気がするんですが
[49]とすると49個欲しいって宣言で、使えるのは[0]から[48]までです。
int n[0];って宣言はコンパイルできないでしょ。

ついでに言うと
for(i=0;i<=49;i++){ より
for(i=0;i<50;i++){ のほうが一般的だと思います。


ANo.3の頭の部分を重視して欲しかった。
(よく見るとセミコロンが余分でしたが)

それと(double)の位置が変みたい。は取り下げます。
/3が気になったのだけど、ちゃんと動くようなので。


あと、Data.txtは150行あると思っていいのかな?
うまく動かなかったらData.txtの最初の3行ぐらいを教えてください。

投稿日時 - 2008-07-12 15:24:46

お礼

配列を復習したところ明らかに私のミスでした。すいません。。。

当初ANo3さんのアドバイスでさえ理解に苦しみましたが
Averageの仮引数と中身を整理した結果、ANo3さんに書いていただいた
ソースになりました。

>あと、Data.txtは150行あると思っていいのかな?
はい、150行でした。実行結果にもしっかりと出ました。

アドバイスありがとうございました。

投稿日時 - 2008-07-12 16:25:19

ANo.7

とりあえず、関数と引数、変数のスコープについて整理しましょう。
スコープという単語がわからないようでしたら、もう一度教科書なり参考書なりで、関数について学んでください。
この部分は基本的なことですので、お持ちのそれらをご覧になったほうが早いかもしれません。

また、No.3での回答の途中にある文章は説明するための文章であって、プログラムじゃありません。さらにソース部分、説明部分ともに、関数の戻り値定義がおかしいままです。

関数定義を以下のとおりに変更してください。
double Average(struct Students tmp)
{
  return (double)(tmp.A+tmp.B+tmp.C)/3;
}

呼び出しは今までどおり、
std[i].ave = Average(std[i]);
です。
あと、fcloseの前に}が必要と思われます。
これらでとりあえず動くはずです。動いたら、動かなかったときとなにが違うのかを確認してください。また、なぜこれで動くのかを確認してください。

投稿日時 - 2008-07-12 12:21:05

お礼

回答ありがとうございます。動かなかった原因としては
仮引数であるtmpをmain関数内で変数として使ったいたこと。
for文の括弧が欠落
tmp.aveに反映してたつもりだったこと
だと考えております。
この後偏差値を求めるソースを追加しなくてはならないので
実践としてやってみたいと思います。
回答ありがとうございました。

投稿日時 - 2008-07-12 16:33:11

ANo.6

平均を求める関数を
/*平均値を計算する関数*/
double Average(struct Students tmp){
  return (double)(tmp.A + tmp.B + tmp.C)/3.0;
}
といった具合に

50人分なら
struct Students std[50]; /*構造型配列*/
とします

結果の表示で
printf("平均点:%d.\n",std[i].ave);

printf("平均点:%lf\n",std[i].ave);
としましょう

投稿日時 - 2008-07-12 06:52:38

ANo.5

> [49]とすると0から49までの合計50個になる気がするんですが
49は要素数。
> 私の思い違いでしょうか?
そうです。
参考書なりを調べたらすぐ分かると思います。

http://homepage3.nifty.com/mmgames/c_guide/13-01.html


> これで正しいでしょうか?
> このソースでコンパイルするとエラーが出てきてしまいました。
エラーが出てるなら正しくないのでは?
エラーメッセージをみればどこが間違ってるか何を間違ってるか分かるんだから、
せめてエラーを全部無くしてください。

> tmp=std[i]; /*平均関数の式。構造体tmpに構造体std[i]の値を代入*/
意味不明。なんで関数Average内にこんな記述があるの?

> tmp.ave=(double)(tmp.A+tmp.B+tmp.C)/3; /*平均関数の式2.↑から得た平均値を求める*/
tmp.aveに代入してもそれが呼び出し元には反映されないのは分かってる?

> return(double)tmp.ave; /*戻り値は平均値*/
関数Averageの戻り値はstruct Students型と宣言してるのに
ここではdouble型になってる。

> std[i].ave=Average(tmp);
tmpなんて変数は存在しない。
右辺がstruct Students型なのに左辺がdouble型。

投稿日時 - 2008-07-12 06:07:42

お礼

>意味不明。なんで関数Average内にこんな記述があるの?
根本的に仮引数の思い違いをしていました。。。


>tmp.aveに代入してもそれが呼び出し元には反映されないのは分かってる?
当初は反映されてると思っていました。

>tmpなんて変数は存在しない。
右辺がstruct Students型なのに左辺がdouble型。
引数と仮引数を混同しておりました。ここのアドバイスのおかげで
無事エラーをなくして実行できるようになりました。
アドバイスありがとうございました。

投稿日時 - 2008-07-12 16:19:47

ANo.4

度々失礼。
std[i]がまずいことは判ってたんですね。
で、ここは他の方のおっしゃる通りとして。

(double)の位置が変みたい。
for(i=0;i<=49;i++){で配列49個じゃまずい。
doubleの記述は%fか%gあたりを使いましょう。
あと、コメントもちゃんと閉じてない です。

投稿日時 - 2008-07-12 01:59:34

補足

アドバイスありがとうございます。配列なんですが
[49]とすると0から49までの合計50個になる気がするんですが
私の思い違いでしょうか?

投稿日時 - 2008-07-12 03:07:31

ANo.2

あぁ!
Average(struct Students std[i]){
ここに[i]があったのね。
これじゃだめです。

投稿日時 - 2008-07-12 01:40:39

ANo.1

ちゃんと見てないけど
std[i].ave=Average(std[i]);
なら
double Average(struct Students std[i]){
じゃない?

閉じる括弧も足りないようだし
実行できない以前にコンパイルできないでは?

投稿日時 - 2008-07-12 01:37:30

-広告-
-広告-

あなたにオススメの質問

-広告-
-広告-