-1

I'm doing the following program:

Programming teachers want to create a program that calculates students' end-of-semester grade. Currently, all students' partial grades are in a text file with the following format:

<first_name> <last_name1> <last_name2> | <AC1> <AC2> <AC3> <AC4> <AC5> <AC6> <AC7> <AC8> <AC9>  <AC10> | <project 1>  <project 2>  <project 3> <report> | <exam>

For example:

Joan Gomez Garcia | 8.0 9.0 7.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 | 10.0 9.0 8.5 9.0 | 6.0
Juan Perez Gonzalez | 3.0 3.0 4.8 5.0 5.0 4.0 6.0 2.0 0.0 0.0 | 8.0 7.5 7.0 8.0 | 7.5
Marta Bonet Call | 6.0 7.0 7.0 8.0 8.0 9.0 10.0 10.0 0.0 | 9.0 9.0 9.0 10.0 | 5.5
Jordi Fernandez Bou | 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 | 10.0 10.0 10.0 10.0 | 3.5

All values ​​are separated by a space and there is a slash ('|') between the continuous assessment marks, the project marks and the final exam mark. This information must be stored in a structure of type Student. You will find its definition in the typedef of the grades.h file shown below.

Continuous evaluation 1 should be stored in box CA[0], continuous evaluation 2 should be stored in CA[1], and so on until continuous evaluation 10. The grade for practice 1 should be saved in project[0], practice 2 should be saved in project[1] and practice 3 should be saved in project[2]. The memory note must be saved in the report field. Finally, the exam grade must be saved in final_exam.

To calculate each student's final grade, the following calculation must be done:

Semester Grade = 50% Knowledge Grade + 50% Project Grade

The Knowledge grade is the highest value between:

Knowledge Grade = 70% Final Exam + 30% Average of the 10 CAs

or

Knowledge Grade = 100% Final Exam

The practice grade is calculated as:

Project Grade = 30% Project 1 + 30% Project 2 + 30% Project 3 + 10% Report

The record of each student with the final grade calculated must be saved in a binary file called "students.bin". Applying the module concept, we want to create a module to solve it made up of the files grades.h and grades.c. The grades.h file is as follows:

#ifndef _GRADES_H
#define _GRADES_H
#include <stdio.h>

#define MAX 100
#define MAX_STR 50

typedef char String[31];

typedef struct {
   String first_name;
   String last_name1;
   String last_name2;
   float CA[10];
   float Project[3];
   float report;
   float final_exam;
   float sem_grade;
} Student;

int loadGrades(char filename[MAX_STR], Student students[MAX]);
void computeGrades(Student students[MAX], int n_students);
void save(Student students[MAX], int n_students);
void updateFile();

#endif

Your task is to write the contents of the grades.c file. The loadGrades() function opens and reads the contents of filename and stores all the information in the students array and also returns the number of students that have been read from the file. The computeGrades() procedure calculates the final semester grade taking into account CAs, projects and the final exam and updates the sem_grade field. The save() procedure saves the entire contents of the array students in a binary file ("students.bin") of type Student.

Finally, the grading system indicates that students who have obtained a grade of 5.0 or higher on the semester grade but do not obtain at least a grade of 4.0 on the final exam will obtain a 4.0 as the final grade of the semester. It will be necessary to search the entire Students binary file ("students.bin") for these cases and change all semester grades where this situation occurs. This is what the updateFile() function will do.

The main is:

#include <stdio.h>
#include "grade.h"

int main()
{   char filename[MAX_STR];
    Student students[MAX];
    int n_students = 0;
    
    printf("Enter filename: ");
    scanf("%s", filename);
    
    n_students = loadGrades(filename, students);    
    computeGrades(students, n_students);
    save(students, n_students);
    updateFile();    
    
    return 0;
}

This is the editable code:

int loadGrades(char filename[], Student students[]) {
    char buffer[MAX_STR];
    int n_students = 0;
    int i = 0;
    int j = 0;
    FILE *fitxer = NULL;
    fitxer = fopen(filename, "r");
    if (NULL == fitxer) {
        printf("error");
    } else {
        fscanf(fitxer, "%s", students[i].first_name);
        while (!feof(fitxer)) {
            fscanf(fitxer, "%s", students[i].last_name1);
            fscanf(fitxer, "%s", students[i].last_name2);
            fscanf(fitxer, "%s", buffer);
            for (j = 0; j < 10; j++) {
                fscanf(fitxer, "%f", &students[i].CA[j]);
            }
            fscanf(fitxer, "%s", buffer);
            for (j = 0; j < 3; j++) {
                fscanf(fitxer, "%f", &students[i].Project[j]);
            }
            fscanf(fitxer, "%f", &students[i].report);
            fscanf(fitxer, "%s", buffer);
            fscanf(fitxer, "%f", &students[i].final_exam);
            n_students++;
            fscanf(fitxer, "%s", students[i].first_name);
        }
        fclose(fitxer);
    }
    return n_students;
}

void computeGrades(Student students[], int n_students) {
    int i = 0;
    int j = 0;
    float average = 0;
    float kg = 0;
    float pg = 0;
    for (i = 0; i < n_students; i++) {
        average = 0;
        kg = 0;
        pg = 0;
        for (j = 0; j < 10; j++) {
            average += students[i].CA[j];
        }
        average /= 10;
        pg = students[i].Project[0] * 0.3 + students[i].Project[1] * 0.3 +
             students[i].Project[0] * 0.3 + students[i].report * 0.1;
        kg = 0.7 * students[i].final_exam + 0.3 * average;
        if (students[i].final_exam > kg) {
            kg = students[i].final_exam;
        }
        students[i].sem_grade = 0.5 * kg + 0.5 * pg;
    }   
}

void save(Student students[], int n_students) {
    FILE *fitxer = NULL;
    int i = 0;
    fitxer = fopen("students.bin", "wb");
    if (NULL != fitxer) {
        for (i = 0; i < n_students; i++) {
            fwrite(&students[i], sizeof(Student), 1, fitxer);
        }
    }
    fclose(fitxer);
}

void updateFile() {
    Student student;
    FILE *fitxer = NULL;
    int i = 1;
    char filename[MAX_STR];
    strcpy(filename, "students.bin");
    fitxer = fopen(filename, "rb+");
    if (NULL != fitxer) {
        fread(&student, sizeof(Student), 1, fitxer);
        while (!feof(fitxer)) {
            fseek(fitxer, i * sizeof(Student), SEEK_SET);
            if ((5 <= student.sem_grade) && (4 > student.final_exam)){
                student.sem_grade = 4;
            }
            fseek(fitxer, i * sizeof(Student), SEEK_SET);
            fwrite(&student, i - 1 * sizeof(student), 1, fitxer);
            i++;
            fread(&student, sizeof(Student), 1, fitxer);
        }
    } else {
        printf("error");
    }
}

I think my the problem is in the function loadGrades(), somehow I'm only storing the last student in the file.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Pepinho02
  • 11
  • 3
  • 3
    First of all, start *small* and *simple*. Add only small and simple bits, one at a time, to the code. That will make it *much* easier to test and debug. As for the problem itself, I suggest you read *lines* from the file, and then parse each line separately in a function (and let the function return a single `Student` structure). Separate as much as possible, making lots of functions, where each function have a single responsibility, it should do only one thing. Again this makes it much easier to test and debug. – Some programmer dude Mar 03 '23 at 09:16
  • 3
    Also please take some time to read [Why is “while( !feof(file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong) And to continue the previous comment, just don't try to do too much at once. Write small simple pieces of code, one by one. Build (with extra warning enabled, treated as errors), test and possibly debug. Only continue with the next small piece of code once everything you currently have is building cleanly and is working. – Some programmer dude Mar 03 '23 at 09:16
  • `fscanf(fitxer, "%s",....` is bad. It should have a _width_ to prevents buffer overflow. The return value should be checked. `"%s"` fails to read last names with spaces in them. – chux - Reinstate Monica Mar 03 '23 at 14:36

2 Answers2

1

There are multiple issues in the code:

  • never use feof() to test for end of file, just test the return value of fscanf() and fread() instead.

  • the element length in fwrite(&student, i - 1 * sizeof(student), 1, fitxer); seems invalid. Did you mean:

      fwrite(&student, sizeof(student), 1, fitxer);
    
  • you must issue a call to fseek() or rewind() between calls for reading and writing to the file in update mode.

  • Update mode is very confusing and error prone, you should consider a different approach.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

I think the solution to your problem is that you never increment i in your while-loop. You may want to replace i with n_students to fix that and save some space. I am pretty sure there are more mistakes in your code but we aren't here to do your home work for you ;)

Some more tips for you:

  • Declare as local as possible
  • Pass pointers instead of arrays, technically both are the same but the probability of someone getting the idea to use sizeof() wrong is reduced
  • Use Guard Conditions instant of if-else for error handling
Schiggy25
  • 3
  • 3