1

Basically I need to scan all the values from this file...which it pretty much does, but it seems to skip random ones so it ends up not lining up properly. (This is only part of what I need to do for the assignment so you are not "giving away the answer" and I still want to figure it out on my own, just need a little help figuring this one out, because I'm pretty stuck)

https://www.dropbox.com/sh/wterbuyxm76wwrz/AADEtolX68OFrKELI_lxT8_Ra/assignments%20and%20labs/labs/lab5_inputFile.txt?dl=0

Here is the code:

int main()
{
    FILE *fp;
    char x[15];
    float ID [1000];
    int i=0, j=0;
    float homework [1000];
    float lab [1000];
    float midterm [1000];
    float Final [1000];
    int count=0;
    char headers[35];
    char y;

    fp= fopen("lab5_inputFile.txt", "r");

    while (fscanf(fp, "%s", x)!=EOF){
        if (count > 728){
            fscanf(fp, "%f", &ID[i]);
            printf("ID : %.1f\n", ID[i]);
            fscanf(fp, "%f", &homework[i]);
            printf("Homework: %.1f\n", homework[i]);
            fscanf(fp, "%f", &lab[i]);
            printf("lab: %.1f\n", lab[i]);
            fscanf(fp, "%f", &midterm[i]);
            printf("Midterm: %.1f\n", midterm[i]);
            fscanf(fp, "%f", &Final[i]);
            printf("Final: %.1f\n", Final[i]);

            i++;
        }
            count ++;

    }
    printf("count = %d\n", count);
    fclose(fp);

I only scanned the last few values to make it easier to read/debug, in the actual code I will only be skipping the headings, there's also a lot of other things I plan to change before submitting this, like I might use pointer type and malloc instead of arrays and a bunch of other things, but my main question is how to fix the problem I am having with reading from the file into the arrays.

Thanks in advance!

Curtis
  • 253
  • 4
  • 11
  • 2
    @Mohit Jain "fscanf returns number of characters read" is incorrect. `fscanf()` returns the number of fields converted or `EOF`. – chux - Reinstate Monica Nov 19 '14 at 05:06
  • Take the habit of reading the documentation of every function you are using (e.g. [fscanf(3)](http://man7.org/linux/man-pages/man3/scanf.3.html)...). Compile with all warnings & debug info (`gcc -Wall -Wextra -g`). **Use the debugger** (`gdb`). You could have found your issue without asking! – Basile Starynkevitch Nov 19 '14 at 05:23
  • why is the code ignoring the results of the first 728 calls to fscanf()? – user3629249 Nov 19 '14 at 07:36
  • the first line of the file needs to be ignored, not any of the following lines suggest inserting, near the top, fgets( ... ); to step past the first line. Then ALL the following calls to fscanf() need to have a format string that contains a leading ' ' so all white space will be consumed/skipped Also, each of the calls to fscanf() need to check the returned value to assure that the conversion was successful I.E. if( 1 != fscanf( ... ) ) { // handle error } use '1' because all the calls to fscanf() are only converting one parameter – user3629249 Nov 19 '14 at 07:37
  • it would be worthwhile to define a struct that contains a field for each of the items to be read from each line in the file. then define an instance of an array of 1000 of those structs. This would clean up the code and make it much easier to follow (and later maintain) what is going on in the code) – user3629249 Nov 19 '14 at 07:44
  • the compiler will output several warnings about this code (assuming you have all warnings/errors enabled) because x[] is not used, headers[] is not used, j is not used, y is not used – user3629249 Nov 19 '14 at 07:47
  • all I/O calls need to have the returned value checked, this includes fopen, fscanf and similar function calls – user3629249 Nov 19 '14 at 07:48
  • @user3629249 "ALL the following calls to fscanf() need to have a format string that contains a leading ' ' so all white space will be consumed/skipped" is incorrect. In `fscanf()`, `"%f"` will consume leading white-space even if there is no space before it. – chux - Reinstate Monica Nov 19 '14 at 16:27

3 Answers3

0

You are skipping the first line x everytime. You should rewrite it as:

char x[100];
/* while (fscanf(fp, "%s", x)!=EOF){ */
fgets(x, 100, fp);  /* Skip first line */
for(; /* ever */; ) {
    if(5 == fscanf(fp, "%f%f%f%f%f", &ID[i], &homework[i], &lab[i], &midterm[i], &Final[i])) {
       printf("ID : %.1f\n", ID[i]);
       printf("Homework: %.1f\n", homework[i]);
       printf("lab: %.1f\n", lab[i]);
       printf("Midterm: %.1f\n", midterm[i]);
       printf("Final: %.1f\n", Final[i]);
       i++;
    } else break;
}

Live example here

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • The `feof(fp)` is not in the right approach. OP's text file ends with a `'\n'` and your answer counts on the file ending with a number. As the file ends with something other than a number, the last `fscanf("%f", &Final[i]);` does not set EOF and an extra set of 5 `fscanf()` occur. Try your solution with a text file ending in `'\n'` to see that. Rather than `if(feof(fp))`, test the result of each `fscanf()`, especially the last one. – chux - Reinstate Monica Nov 19 '14 at 05:43
  • @chux I attempt to read all the values. If file doesn't read `eof` even after reading all, I increment `i` declaring the read was successful. Otherwise I break declaring at least on `fscanf` was unsuccessful. (Although OP's debug prints would appear unwantedly) – Mohit Jain Nov 19 '14 at 06:23
  • Sounds like you did not try running code on suggested input. If the last number successfully read has white-space after it, `feof()` will not be true and then the next set of 5 `fscanf(fp, "%f", ...` will all fail. Since code does not check the results of of `fscanf()`, this fail is not detected. After these failures, `feof()` will then be true. To be clear `feof()` does _not_ inform no more data will be available, `feof()` informs that a _previous_ IO operation sensed that no more data is available. – chux - Reinstate Monica Nov 19 '14 at 14:51
  • "If file doesn't read eof even after reading all, I increment i" _is_ a problem. 1) Code does not know the individual `fscanf()` worked (e.g. non digits entered) 2) The problem is the the very next `fscanf(fp, "%f", &ID[i]);` could fail as there are no more numbers to be read. This code does not detect that failure and can then perform 5 failed `fscanf()` before breaking via `if(feof(fp)) break;` Suggest reviewing http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong . – chux - Reinstate Monica Nov 19 '14 at 17:16
0

OP's approach repeated reads "a group of non-white-space text and then 5 numbers". Code should read a line once, toss it and then repeated read groups of 5 numbers.

Read and toss first line, then read lines until EOF using fgets(). Scan the buffer with sscanf() or strtod().

char buf[100];
fgets(buf, sizeof buf, fp);  // Read and toss first line
i = 0;

while (fgets(buf, sizeof buf, fp) != NULL) {  // Read until EOF
  if ((i >= 1000) || (sscanf(buf, "%f%f%f%f%f", &ID[i], &homework[i], &lab[i], 
      &midterm[i], &Final[i]) != 5)) {
    fputs("Quit as too many lines or ill formatted\n", stderr);
    break;
  }
  printf("ID : %.1f\n", ID[i]);
  printf("Homework: %.1f\n", homework[i]);
  printf("lab: %.1f\n", lab[i]);
  printf("Midterm: %.1f\n", midterm[i]);
  printf("Final: %.1f\n", Final[i]);
  i++;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0
#include <stdio.h>
#include <stdlib.h>

struct grade
{
    float ID;
    float homework;
    float lab;
    float midterm;
    float final;
};

#define ARRAYSIZE (1000)

int main()
{
    FILE *fp;
    struct grade studentGrades[ARRAYSIZE] = {{0},{0},{0},{0},{0}};
    int i=0;
    int count=0;


    if( NULL == (fp= fopen("lab5_inputFile.txt", "r") ) )
    {
        perror( "fopen for read of lab5_inputFile.txt" );
        exit(1);
    }

    // implied else fopen successful

    char* dummy = malloc(1000*sizeof(char) );
    if( NULL == dummy )
    {
        perror( "malloc for dummy buffer" );
        exit(2);
    }

    // implied else, malloc successful

    char * firstLine = fgets( dummy, sizeof(dummy), fp ); // step past first line of file
    if( NULL == firstLine )
    {
        perror( "fget of first line of file" );
        exit(3);
    }

    // implied else, fgets successful

    free( dummy );

    int itemCount = 0;
    for ( i = 0; i < ARRAYSIZE; i++ )
    {
        itemCount = fscanf(fp, " %f", &studentGrades[i].ID);
        if( EOF == itemCount ) // Note:making assumption that every line, 
                               // after first, is properly formatted
        {
            break; // exit for loop
        }
        if( 1 != itemCount )
        {
            perror("fscanf");
            exit(4);
        }

        // implied else read of ID successful, not end of file

        printf("ID : %.1f\n", studentGrades[i].ID);

        if( 1 != fscanf(fp, " %f", &studentGrades[i].homework) )
        {
            perror( "fscanf of homework");
            exit(5);
        }

        // implied else, read of homework successful

        printf("Homework: %.1f\n", studentGrades[i].homework);

        if( 1 != fscanf(fp, " %f", &studentGrades[i].lab) )
        {
            perror( "fscanf of lab" );
            exit(6);
        }

        // implied else, read of lab successful

        printf("lab: %.1f\n", studentGrades[i].lab);

        if( 1 != fscanf(fp, " %f", &studentGrades[i].midterm) )
        {
            perror( "fscanf of midterm" );
            exit(7);
        }

        // implied else, read of midterm successful

        printf("Midterm: %.1f\n", studentGrades[i].midterm);

        if( 1 != fscanf(fp, " %f", &studentGrades[i].final) )
        {
            perror( "fscanf of final" );
            exit(8);
        }

        // implied else, read of final successful

        printf("Final: %.1f\n", studentGrades[i].final);

        count ++;

    } // end for

    printf("count = %d\n", count);
    fclose(fp);

    return(0);
}
user3629249
  • 16,402
  • 1
  • 16
  • 17