0

いくつかのファイルからデータを読み取り、それを配列にスキャンし、最終的に画面に 13 の名前を出力し、それぞれの隣に 4 つの数字と、それらの数字の後に一種の評価チャートの文字を表示するプログラムに取り組んでいます。

ただし、平均を計算する目的で使用している関数の1つに問題があります。1 つの生徒のテストのすべてのスコアを 1 つの値に結合し、それを 4 で割って平均を求め、その平均を別の配列の 1 つの要素に格納します。

関数呼び出しは次のとおりです。

avg(&scores, &average);

スコアと平均は次のように定義されます。

int scores[13][4];
float average[13];

スコアは次のループを使用して入力されています。

for(i=0; i<=13; i++)
{
    for(j=0; j<=4; j++)
    {
    fscanf(score, "%d", &scores[i][j]);
    }
}
fclose(score);

参考までに、使用されるファイルを開くステートメントは次のとおりです。

FILE *student, *score;
score = fopen("scores.dat", "r");

関数自体は次のようになります。

void avg(int *scores, float *average)
{
int total1 = scores[0][0] + scores[0][1] + scores[0][2] + scores[0][3];
int total2 = scores[1][0] + scores[1][1] + scores[1][2] + scores[1][3];
int total3 = scores[2][0] + scores[2][1] + scores[2][2] + scores[2][3];
int total4 = scores[3][0] + scores[3][1] + scores[3][2] + scores[3][3];
int total5 = scores[4][0] + scores[4][1] + scores[4][2] + scores[4][3];
int total6 = scores[5][0] + scores[5][1] + scores[5][2] + scores[5][3];
int total7 = scores[6][0] + scores[6][1] + scores[6][2] + scores[6][3];
int total8 = scores[7][0] + scores[7][1] + scores[7][2] + scores[7][3];
int total9 = scores[8][0] + scores[8][1] + scores[8][2] + scores[8][3];
int total10 = scores[9][0] + scores[9][1] + scores[9][2] + scores[9][3];
int total11 = scores[10][0] + scores[10][1] + scores[10][2] + scores[10][3];
int total12 = scores[11][0] + scores[11][1] + scores[11][2] + scores[11][3];
int total13=  scores[12][0] + scores[12][1] + scores[12][2] + scores[12][3];

float avg1 = total1 / 4;
float avg2 = total2 / 4;
float avg3 = total3 / 4;
float avg4 = total4 / 4;
float avg5 = total5 / 4;
float avg6 = total6 / 4;
float avg7 = total7 / 4;
float avg8 = total8 / 4;
float avg9 = total9 / 4;
float avg10 = total10 / 4;
float avg11 = total11 / 4;
float avg12 = total12 / 4;
float avg13 = total13 / 4;

return;
}

まだ完全ではありません。配列に avg1-avg13 を割り当てるように関数に指示する必要があります。しかし、このエラーを修正したら、それに取り組みます。

プログラムをそのまま実行しようとすると、多くのエラーが発生しますが、それらはすべて基本的に同じです。

ghp11.c: In function 'avg':
ghp11.c:127: error: subscripted value is neither array nor pointer

正しく動作するように修正する方法が正確にはわかりません。4 つの配列値を 1 つの整数値に結合して、total1 などに格納しようとしています。それらを平均化して保存できるようにします。

4

3 に答える 3

2

&from&scores&averageへの呼び出しを削除しますavg

avg( scores, average );

のプロトタイプをavgに変更します

void avg( int (*scores)[4], float *average ) // or int scores[][4]

の本体をavgに変更します

{
  int i = 0;

  for ( i = 0; i < 13; i++ )
  {
    // you could write another loop for summing your total, 
    // but for just 4 elements writing it out isn't a big deal.

    int total = scores[i][0] + scores[i][1] + scores[i][2] + scores[i][3];
    average[i] = total / 4.0;
  }
}

sizeofこれが機能する理由: 、_Alignof、または単項演算子のオペランドである場合を除いて、&「 " の N 要素配列T" 型の式は、" へのポインター " 型の式に変換 ("減衰") されますTscoresへの呼び出しの の型avgは「の 4 要素配列の 13 要素配列int」であるため、関数に渡される式は「の 4 要素配列へのポインタint」、またはint (*)[4].

同様に、式「平均」の型は、「13要素配列float」から「へのポインタ」に変換されますfloat

の型は、&scores「の 4 要素配列の 13 要素配列へのポインタint」、またはint (*)[14][3]. それを行うこともできますが、関数に添字を付けるにscoresは、関数で明示的に逆参照する必要があります。avg

int total = {*scores)[0][0] + (*scores)[0][1] + ...;

ただし、 として渡したのでint (*scores)[4]、次のように記述できます。

int total = scores[0][0] + scores[0][1] + ...;

添え字操作はscores[0]暗黙的にポインターを逆参照するためです。

あなたのコードでは、平均はすべて、より低い整数値に切り捨てられることに注意してください。整数を整数で割ると整数の結果5/4が得られるため、次のような式では 1 が3/4返され、0 が返されます。小数値を取得する場合は、オペランドの 1 つを浮動小数点数にする必要があります。

average[i] = total / 4.0;

average最後に、結果の平均を配列に書き込んでいません。avg関数にローカルな一連の変数を作成して割り当てるだけです。関数が終了すると、これらの変数は単純に消えます。上記のコードでは、変数を配列の要素に置き換えただけです。avgNavgNaverage

avg1avg2、のような変数の束を作成していることに気付いたときはいつでもavg3、一歩下がって、ここで本当に必要なのは配列であることに気付きます。同様に、次のようなステートメントを書いていることに気付いたとき

avg1 = total1 / 4.0;
avg2 = total2 / 4.0;
avg3 = total3 / 4.0;

ここで本当に欲しいのループです:

for ( i = 0; i < N; i++ )
   avg[i] = total[i] / 4.0;

実際に残っている唯一の欠点は、avg関数が各配列に常に 13 個の要素があると想定しているため、その有用性が制限されることです。行数を別のパラメーターとして渡すのが最善です。

void average( int (*scores)[4], int *average, size_t rows )
{
  size_t i;

  for ( i = 0; i < rows; i++ )
  {

    int total = scores[i][0] + scores[i][1] + scores[i][2] + scores[i][3];
    average[i] = total / 4.0;
  }
}

そしてそれを次のように呼び出します

size_t rows = sizeof scores / sizeof scores[0]; // divides the total number of bytes
                                                // in the array by the number of bytes
                                                // in a single element, giving the
                                                // number of elements in the array
avg( scores, average, rows );

もちろん、 の列数はscores4 に固定されています。任意の列数のスコアをサポートしたい場合は、別のことを行う必要があります。ただし、それは将来のために残します。

于 2013-04-22T23:39:29.403 に答える
1

2D 配列を関数に渡すには、関数定義を次のように記述する必要があります。

void avg( int score[][4], float *average );
于 2013-04-22T23:04:42.880 に答える
1

最初に気付くのは、バッファ オーバーフローです。for i および for j ループは 1 だけオーバーフローします。

于 2013-04-22T23:05:15.050 に答える