0

iv got an xls file to open in c. in this file there are 10 rows(each row represents a student), and in each row there are 12 numbers (each number represents the student grade for each subject,12 together). i need to scan the this data and calculate the GPA and the degree of classificaton for each students. so what i need to show on the screen is 12 grade (from number converted to letter) for each students(10) and their GPA and qualification classification. bellow is what i have done so far. im able to get the 10 rows onto a screen with 12 numbers in each row, but i dont know how i can make calculations with those numbers after i read them. thanks for any help or advice.

#include <stdio.h>
#include <stdlib.h>

int main()  
{
    FILE * fPointer;
    fPointer=fopen("hello.xls", "r");

    int singleLine[150];

    while(!feof(fPointer)) {;
        fgets (singleLine,150,fPointer);
        puts(singleLine);
    }

    fclose(fPointer);

    return 0;
}
kaylum
  • 13,833
  • 2
  • 22
  • 31
  • You need to parse the values into individual variables. Using either `strtok`+`strtol` or `sscanf`. Do a search as there are many many questions and examples out there. – kaylum Mar 22 '17 at 23:36
  • While you are researching, you should read about [why you should not control a loop to read a file with `feof()`](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). – ad absurdum Mar 22 '17 at 23:42
  • suggest, to replace the first two lines in the loop: `while( fgets (singleLine, sizeof( singleLine), fPointer); – user3629249 Mar 23 '17 at 00:05
  • when calling `fopen()`, always check (!=NULL) the returned value to assure the operation was successful. If not successful, use: `{ perror( "fopen for hello.xls for read failed" ); exit( EXIT_FAILURE );` where `exit()` and `EXIT_FAILURE` are in the `stdlib.h` header file – user3629249 Mar 23 '17 at 00:08
  • after the call to `puts()`, call a new function, passing it a pointer to the char array `singleLine[]`. That new function can parse the input line into the individual fields. Then calculate the student average/GPA. The 12 grades can be easily extracted using a loop that incorporates the functions: `strtok()` and the function: `strtol()` – user3629249 Mar 23 '17 at 00:14

1 Answers1

0

A few preliminary matters. The function signature for main() should be int main(void), int main(int argc, char **argv), or int main(int argc, char *argv[]).

When you open a file, it is always necessary to check for failure. fopen() returns a null pointer when it fails, so you can check for this, and handle the error appropriately.

When reading the contents of a file in a loop, it is almost always a mistake to use feof() to control the loop. This is because feof() checks the end-of-file pointer, which is itself set only when an IO operation fails. In the case of the posted code, the loop is entered, and if there is nothing to read, the singleLine buffer contents remain unchanged, doubling the final line of the text file.

The simplest way to solve your problem is to take as given that each line contains 12 grades, and use sscanf() to parse each line of input as it is retrieved. This is not an elegant soulution:

#include <stdio.h>
#include <stdlib.h>

#define MAX_STUDENTS  100

int main(void)
{
    /* Open a file */
    FILE *fPointer = fopen("hello.xls", "r");

    /* Make sure file opened successfully */
    if (fPointer == NULL) {
        fprintf(stderr, "Unable to open file\n");
        exit(EXIT_FAILURE);
    }

    char singleLine[500];
    double studentGPA[MAX_STUDENTS];
    int grade[12];
    size_t studentIndex = 0;

    /* Loop to fetch data and calculate GPAs */
    while ((fgets(singleLine, sizeof singleLine, fPointer)) != NULL &&
           studentIndex < MAX_STUDENTS) {
        if (sscanf(singleLine, "%d %d %d %d %d %d %d %d %d %d %d %d",
                   &grade[0], &grade[1], &grade[2], &grade[3],
                   &grade[4], &grade[5], &grade[6], &grade[7],
                   &grade[8], &grade[9], &grade[10], &grade[11]) != 12) {
            fprintf(stderr, "Incorrect number of grades on line %zu\n",
                    studentIndex);
            exit(EXIT_FAILURE);
        }
        int sum = 0;
        for (size_t i = 0; i < 12; i++) {
            sum += grade[i];
        }
        studentGPA[studentIndex] = sum / 12.0;
        ++studentIndex;
    }

    /* Display GPAs */
    for (size_t i = 0; i < studentIndex; i++) {
        printf("Student %zu GPA: %.2f\n", i, studentGPA[i]);
    }

    return 0;
}

Note that the return value of fgets() is checked to control the file read loop; when a null pointer is returned, or when the maximum number of students has been reached, the loop terminates. This code allows more than 10 students, but requires 12 grades per student. If a line of student grades does not contain 12 entries, the program prints an error message and exits. This is done by checking the return value from sscanf(), which is the number of successful conversions made. After each student's grades have been read, the average is calculated and stored in an array of studentGPAs.

I have assumed integer grade entries, as suggested in the question post, but the GPAs are calculated with floating point values. Also note that I have assumed that the grades are separated by whitespace. If the grades are separated by commas (or other delimiters) the format string will need to be modified accordingly.

A more elegant approach uses strtok() to break the lines of grades into individual tokens, based on a string of delimiters. These delimiters, delims = " ,\r\n", indicate that strtok() should break the line into tokens where spaces, commas, or newlines occur. Other delimiters can simply be added to the string if needed.

Each line of grades is fetched, and strtok() is called a first time. If there is a token, it is converted to an int by atoi(), and added to sum. numGrades is updated, and strtok() is called again for a new token. When all grades have been read from a line, the average is calculated and stored in the studentGPA array. Note that the denominator in the average calculation is multiplied by 1.0 to force the calculation to be double. Also note that a more robust code would use strtol() instead of atoi(), checking the conversion for errors.

With this version, any number of students up to MAX_STUDENTS can be evaluated, with differing numbers of grades.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STUDENTS  100

int main(void)
{
    /* Open a file */
    FILE *fPointer = fopen("hello.xls", "r");

    /* Make sure file opened successfully */
    if (fPointer == NULL) {
        fprintf(stderr, "Unable to open file\n");
        exit(EXIT_FAILURE);
    }

    char singleLine[500];
    double studentGPA[MAX_STUDENTS];
    size_t studentIndex = 0;
    char *token;
    char *delims = " ,\r\n";

    /* Loop to fetch data and calculate GPAs */
    while ((fgets(singleLine, sizeof singleLine, fPointer)) != NULL &&
           studentIndex < MAX_STUDENTS) {
        int sum = 0;
        int numGrades = 0;

        /* Get grade tokens */
        token = strtok(singleLine, delims);

        while (token) {
            sum += atoi(token);
            ++numGrades;
            token = strtok(NULL, delims);
        }

        /* Calculate student GPA */
        studentGPA[studentIndex] = sum / (1.0 * numGrades);
        ++studentIndex;
    }

    /* Display GPAs */
    for (size_t i = 0; i < studentIndex; i++) {
        printf("Student %zu GPA: %.2f\n", i, studentGPA[i]);
    }

    return 0;
}

Here is a sample hello.xls file, with mixed comma and space delimiters. The first program will not work with this file, unless the commas are removed.

3 4 2 3 3 4 3 2 3 3 4 4
2 2 3 4 2 3 3 2 3 2 2 3
1 2 3, 3 2 3 3, 3, 4 2 3 3
3 2 2 3 3 2 1 2 2 2 1 1
4 4 3 4 4 4 4 3 4 4 4 4
4, 3, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4
2 3 2 2 2 1 2 2 2 3 2 2
3 4 4 4 4 4 4 4 4 4 4 4
3 2 3 3 2 3 3 3 2 3 3 3
4 1 4 3 4 4 4 2 4 4 4 4

Here is the output of the second program with this grade file:

Student 0 GPA: 3.17
Student 1 GPA: 2.58
Student 2 GPA: 2.67
Student 3 GPA: 2.00
Student 4 GPA: 3.83
Student 5 GPA: 3.83
Student 6 GPA: 2.08
Student 7 GPA: 3.92
Student 8 GPA: 2.75
Student 9 GPA: 3.50
ad absurdum
  • 19,498
  • 5
  • 37
  • 60