Home > Software design >  fscanf doesn't seem to be reading from file while in a loop
fscanf doesn't seem to be reading from file while in a loop

Time:11-18

I'm trying to write a program as an exercise that takes some values from a file sorts them into two variables named studentsPassed and studentsFailed, then prints the number of students that have passed and the number of students that have failed aswell as the module code and the number of students.

Here is the .txt file:

101 20
65 72 23 59 80 75 55 88 92 77 44 57 73 31 48 59 71 48 66 59

101 is the module code, and 20 is the number of students in the class. The 20 numbers in the row below are the marks each one of those 20 students scored (e.g. Student 1 scored 65, Student 2 scored 72, etc.)

Here is my code:

#include <stdio.h>

FILE *fp;

int main(){

    //Open the file and assign its address/disk location to file pointer
    fp = fopen("marks.txt", "r");

    //Variables
    int moduleCode, numStudents;
    const int size = 20;

    int studentMark;
    int studentsPassed;
    int studentsFailed;

    //Scan in the first line for the module code and the number of students
    fscanf(fp, "%d %d", &moduleCode, &numStudents);

    //Scan in the student marks and loop through them
    for (int i = 0; i < size; i  )

        if (fscanf(fp, "%d", &studentMark) < 40){

            int studentsFailed = studentsFailed   1;

        }

        else if (fscanf(fp, "%d", &studentMark) >= 40){

            int studentsPassed = studentsPassed   1;

        }

        else{

            printf("Error: Number of marks exceeds cap!");
            return 0;
        }

    //Print the results
    printf("%d %d\n", moduleCode, numStudents);
    printf("Number of students passed: %d\n", studentsPassed);
    printf("Number of students failed: %d\n", studentsFailed);

    return 0;
}

What the program should do is read the module code and the number of students and print them on the first line (which is successfully does), then the program should loop through each of the 20 numbers and sort them into different variables based on if they are higher or lower than 40, this is the part that I am struggling on, as the program executes, but it will print out a random large number for studentsPassed, and "1" for studentsFailed every time I run it.

What am I doing wrong? I feel like I am missing something to do with looping through each of the numbers but I'm not sure how to correct it.

Note: This is what I initially tried (which also didn't work) before reading another answer on this website to get what my current code is.

//Scan in the student marks and loop through them
    fscanf(fp, "%d", &studentMark);
    for (int i = 0; i < size; i  )

        if (studentMark < 40){

            int studentsFailed = studentsFailed   1;

        }

        else if (studentMark >= 40){

            int studentsPassed = studentsPassed   1;

        }

CodePudding user response:

Your second version is almost correct, except that the call to fscanf() needs to be inside the loop.

Also, you shouldn't re-declare studentsFailed and studentsPassed in the if blocks. Just assign to the variables that were declared earlier.

    for (int i = 0; i < size; i  )
        fscanf(fp, "%d", &studentMark);
        if (studentMark < 40){
            studentsFailed  ;
        }
        else{
            studentsPassed  ;
        }
    }

You also shouldn't use else if when the second condition is the opposite of the first one. Just use else.

CodePudding user response:

The value that *scanf returns is the number of conversion specifiers that were successfully matched. It is unrelated to the values that it reads from the input stream.

You should get out of the habit of relying on the input stream to provide the number of expected data points; it is fragile and usually not necessary. Instead, just read all of the data until you reach the end of the input stream. In your case, you can do something like:

#include <stdio.h>

int
main(int argc, char **argv)
{
    int moduleCode, numStudents, studentsPassed = 0, studentsFailed = 0;
    int actualNumStudents = 0;
    int score;
    FILE *fp = argc > 1 ? fopen(argv[1], "r") : stdin;

    if( fp == NULL ){
        perror(argv[1]);
        return 1;
    }
    if( fscanf(fp, "%d%d", &moduleCode, &numStudents) != 2 ){
        fprintf(stderr, "invalid input\n");
        return 1;
    }
    while( fscanf(fp, "%d", &score) == 1 ){
        actualNumStudents  = 1;
        *( score < 40 ? &studentsFailed : &studentsPassed )  = 1;
    }
    if( ! feof(fp) ){
        fprintf(stderr, "invalid input or read error\n");
        return 1;
    }
    if( actualNumStudents != numStudents ){
        fprintf(stderr, "Warning: the declared number of students does "
            "not match the actual number of students\n");
    }

    printf("%d %d\n", moduleCode, actualNumStudents);
    printf("Number of students passed: %d\n", studentsPassed);
    printf("Number of students failed: %d\n", studentsFailed);
}
  • Related