Xerinos
Xerinos

Reputation: 91

subscripted value is neither array nor pointer function error

Working on a program that will read data from a few files, scan it into arrays, and eventually print to the screen 13 names, with 4 numbers next to each of them, and a letter after those numbers in a kind of grading chart.

However I'm having a problem with one of the functions I'm using whose purpose is to calculate the averages. It combines all of the scores for one students tests into a single value and then divides it by 4 to find the average, then stores that average into one element of a different array.

The function call is:

avg(&scores, &average);

Scores and Average are defined like this:

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

and scores has been populated using this loop:

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

for reference, the file opening statement used is:

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

The function itself looks like this:

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;
}

It's not complete, I still have to tell the function to assign avg1-avg13 to the array. But I'll be working on that once I fix this error.

Attempting to run the program as is gives me a lot of errors, all of which are basically the same:

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

I'm not exactly sure how to fix it so that it works properly. I'm trying to combine 4 of the array values into one integer value and store it in total1, etc; so that they can be averaged out and stored.

Upvotes: 0

Views: 1030

Answers (3)

John Bode
John Bode

Reputation: 123448

Drop the & from &scores and &average in the call to avg:

avg( scores, average );

Change the prototype for avg to

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

and change the body of avg to

{
  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;
  }
}

Why this works: except when it is the operand of the sizeof, _Alignof, or unary & operators, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T". Since the type of scores in the call to avg is "13-element array of 4-element arrays of int", the expression that gets passed to the function will have type "pointer to 4-element arrays of int", or int (*)[4].

Similarly, the type of the expression "average" will be converted from "13-element array of float" to "pointer to float".

The type of &scores would be "pointer to 13-element array of 4-element arrays of int", or int (*)[14][3]. You could do that, but you would have to explicitly dereference scores in the avg function in order to subscript it, such as

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

However, since we passed it as int (*scores)[4], we can write

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

because the subscript operation scores[0] implicitly dereferences the pointer.

Note that in your code, your averages are all going to end up being truncated to the lower integer value; an integer divided by an integer gives an integer result, so an expression like 5/4 would yield 1, and 3/4 would yield 0. If you want to get a fractional value, you'll need to make one of the operands a float:

average[i] = total / 4.0;

Finally, you're not writing the resulting averages to your average array; you're just creating and assigning a bunch of variables that are local to the avg function; once the function exits, those avgN variables simply go away. In the code above, I've simply replaced your avgN variables with elements of the average array.

Anytime you find yourself creating a bunch of variables like avg1, avg2, avg3, take a step back and realize that what you really want here is an array. Similarly, when you find yourself writing statements like

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

what you really want here is a loop:

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

The only real remaining flaw is that the avg function assumes that there will always be 13 elements in each array, which limits its utility. Best to pass the number of rows as a separate parameter:

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;
  }
}

and call it as

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 );

Of course, the number of columns in scores is still fixed at 4. If you want to support scores with an arbitrary number of columns, then you'll have to do something different. However, we'll leave that for the future.

Upvotes: 2

user2035147
user2035147

Reputation: 207

first thing I notice is your buffer overflow. for i and for j loops overflow by one.

Upvotes: 1

yngccc
yngccc

Reputation: 5684

to pass your 2D array to a function, you have to write the function definition like this

void avg( int score[][4], float *average );

Upvotes: 1

Related Questions