2

I'm trying to write a simple program which receives marks, names and ID's of at most 30 students and prints average of their marks. I was wondering why the result of the program is always zero.
I appreciate if anyone could leave me a hint.
Here is the code:

#include <stdio.h>

struct student{
    char name[30];
    int mark;
    int ID;

} s[30];

int main() {
    int n, i=0, sum=0;
    float average;
    /* printf("enter the number of students: "); */
    scanf("%d", &n);
    /* printf("enter their information: "); */

    for(i=0; i<n; i++)
        scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);

    for(i=0; i<n; i++)
         sum+=s[i].mark;
    
    average=sum/(float)n ;
    printf("%.2f", average);
}
GSerg
  • 76,472
  • 17
  • 159
  • 346
Sam
  • 45
  • 6

4 Answers4

5

The format specifier %s says to read a string, and it's doing that … including your commas and subsequent characters. It's "greedy".

Then there's nothing left for the %d to absorb, so all the integers remain zero.

I suggest you read a line a time, then parse the lines.

Alternatively, there are some suggestions on this similar question.


When faced with a problem like this, you should attempt to narrow it down by examining the values of variables in your debugger, or even just by using printf, like this:

    printf("%s|%d|%d\n", s[i].name, s[i].mark, s[i].ID);

When I put that in your first loop, and pass the following input to the program:

2
A,2,3
B,4,5

the output is this:

A,2,3|0|0
B,4,5|0|0
0.00

… which clearly shows that the parsing is the problem.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
1

the problem is in this line:

scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);

it will not work as you think. To test it I have amended you program.

int main() {
    int n = 10, i=0, sum=0;
    int scanfResult;
    float average;
    /* printf("enter the number of students: "); */
    //scanf("%d", &n);
    /* printf("enter their information: "); */
    for(i=0; i<n; i++)
    {
        scanfResult = scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);
        printf("scanf has scanned %d items\n", scanfResult);
        if(scanfResult != 3) 
        {
            printf("you need to find another way of entering the data\n");
            exit(1);
        }
    }
    for(i=0; i<n; i++)
         sum+=s[i].mark; 
    average=sum/(float)n ;
    printf("%.2f", average);
}

https://godbolt.org/z/PredEd

What you need to do? You need to read the whale line with fgets and the write the parser which will split this string apart

ALWAYS CHECK THE RESULT OF SCANF

0___________
  • 60,014
  • 4
  • 34
  • 74
1

If you’re trying to enter names with spaces in them, like

Joe Smith,90,1234

then the problem is that the %s conversion specifier stops reading at the first whitespace character, so it reads "Joe" and leaves "Smith" in the input stream, which fouls up the next two reads. Alternately, if you don’t have any spaces, %s reads the entire input line into name (whether it fits or not, potentially leading to a buffer overflow).

You should use the %[ conversion specifier instead of %s and explicitly size it to avoid risking a buffer overflow. You should also check the return value of scanf to make sure you read all 3 items correctly:

/**
 * loop until we have three good inputs;
 * %29[^,] reads up to 29 characters or to the next comma;
 * An array of size 30 can store a string of up to
 * 29 characters plus the string terminator;
 * Added leading blank in the format string to consume
 * any leading whitespace. 
 */
while ( scanf( " 29%[^,],%d,%d", s[i].name, &s[i].mark, &s[i].ID) != 3 )
{
   fprintf(stderr, "Bad input, try again\n" );
   /**
    * clear out the input stream before trying again
    */
   while ( getchar() != '\n' )
     ; // empty loop body
}
John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Your problem is , in the scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);

I changed the code as follow:

scanf("%s%d%d",s[i].name,&s[i].mark,&s[i].ID);

then input and output were as: INPUT:

2
moh 1 2
test 2 3

OUTPUT:

1.50
Mohit Sharma
  • 338
  • 2
  • 13