0

I'm trying to read some data from a file then print it out but My code is only reading the first content and then gets stuck in an infinite loop (in the while loop). What am I doing wrong? My output is just Student: Abby GPA: 3 I'm using Visual Studio 2012. I am just following an example from my book.

//My data is Abbie 3.4 Oakley 3.5 Sylvia 3.6 Uwe 3.7 Ken 3.8 Aaron 3.9 Fabien 4 

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

void main()
{    
    unsigned int GPA;//GPA
    char student[10];//Student
    FILE * cfPter;
    //Check if file opened
        if((cfPter = fopen("data.txt", "r")) ==NULL)
        {
                puts("File could not be opened");
            }
        //Read Contents
        else
            {
                puts("Contents of file:\n");
                fscanf(cfPter,"%s %f ", student, &GPA);
            }
        //While not at end Print the contents read
        while(!feof(cfPter))
        {
            printf("Student: %s GPA: %f",student,GPA);
            fscanf(cfPter, "%s %f", student, GPA);
            //system("pause");
        }

    fclose(cfPter);
    system("pause");
} //end main    
j.yang29
  • 65
  • 9
  • 1
    `system("pause")` perhaps? – Michael Albers Apr 28 '16 at 03:28
  • 3
    You will also want to see [**Why is “while ( !feof (file) )” always wrong?**](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong?s=1|2.6948) – David C. Rankin Apr 28 '16 at 03:30
  • Your while loop should be inside your else clause...but it isn't. – John Zwinck Apr 28 '16 at 03:31
  • 1
    1 Mistake I made is the scanf is a decimal right now when I'm trying to read a double. Oops – j.yang29 Apr 28 '16 at 03:31
  • Take a closer look at those `fscanf` calls. How do you pass arguments? Which order do you pass them in? Why are you two calls different? Why do you need two calls? – Some programmer dude Apr 28 '16 at 03:32
  • And why are you printing the values *before* you read them? – Some programmer dude Apr 28 '16 at 03:33
  • @DavidC.Rankin but isn't the whole point of feof to return true if it's not at the end, so !feof(file) shouldn't be wrong? Since !feof(file) should return false until the end? – j.yang29 Apr 28 '16 at 03:38
  • @JoachimPileborg What do you mean printing before reading? I read the data in the if statement then print it in the while loop? – j.yang29 Apr 28 '16 at 03:41
  • "isn't the whole point of feof" Have you tried to follow the link? The linked page explains the problem very well. – n. m. could be an AI Apr 28 '16 at 03:44
  • @n.m I followed the link, but following it's definition: the function feof was written for a reason, Also it's the way it's done in my book, and the only way I've seen it being done in my examples – j.yang29 Apr 28 '16 at 03:48
  • The `feof` function will not return "true" until *after* you first try to read from *beyond* the end of the file. That means your loop will run one time to many. – Some programmer dude Apr 28 '16 at 03:52

3 Answers3

0

You are getting there, but a couple of tweaks can make life easier. First, if your fopen fails, either handle the failure by prompting for another file name, or simply return (exit) at that point. That way the rest of your code isn't wrapped inside an else statement.

Next, I provided the link for why while (!feof(file)) is always wrong (when reading character data from a file). When you read input, validate you received input -- that is really all you need to do. Check the return for your fscanf call.

With that in mind, you could do something similar to the following:

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

int main (void) {

    float GPA = 0.0;        /* GPA     */
    char student[10] = "";  /* Student */
    FILE *cfPter = NULL;

    /* open file/validate file is open */
    if (!(cfPter = fopen ("data.txt", "r"))) {
        fprintf (stderr, "error: file open failed 'data.txt'.\n");
        return 1;
    }

    /* Read Contents */
    while (fscanf (cfPter, " %9s %f", student, &GPA) == 2)
        printf ("Student: %-10s GPA: %.2f\n", student, GPA);

    fclose (cfPter);
    return 0;                   /* main is type 'int' and returns a value */
}

Example data.txt

$ cat data.txt
Abbie 3.4 Oakley 3.5 Sylvia 3.6 Uwe 3.7 Ken 3.8 Aaron 3.9 Fabien 4

Example Use/Output

$ ./bin/feofissue
Student: Abbie      GPA: 3.40
Student: Oakley     GPA: 3.50
Student: Sylvia     GPA: 3.60
Student: Uwe        GPA: 3.70
Student: Ken        GPA: 3.80
Student: Aaron      GPA: 3.90
Student: Fabien     GPA: 4.00

(note while MS will let you use void main from long ago, main is defined as type int and returns a value. )

Also to pause, you generally #include <conio.h> on windows and call getch(); to prevent the terminal window from closing. You can try it either way. Let me know if you have questions.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Why do you have it ==2? also I tried the tweak, but it has no errors and it's not reading any information. The way you did it, it is scanning two elements, student and gpa, and then printing it, and then moving on? – j.yang29 Apr 28 '16 at 03:49
  • `"%d %s"` is the `format-string` used by `fscanf`. Inside there are `2` *conversion-specifiers* (`%d` and `%s`). The return of `fscanf` is the *match-count* of successful conversions according to the *format-string*. Therefore by checking the return equals `2`, you can insure you read all values in the line. When you reach the end of file - no conversions take place and the loop exits. – David C. Rankin Apr 28 '16 at 03:52
  • Shouldn't "%f be used because it is reading a decimal rather than a integer? also it should be %s before %d(or f) in the scanf in the while loop? – j.yang29 Apr 28 '16 at 03:56
  • Oh Yes sorry. I didn't see the float up top. You cannot declare are as `unsigned` and use `%f`, that must be fixed as well. – David C. Rankin Apr 28 '16 at 03:58
0

I'm working on this as well, and someone told me to try using strcmp() to read the file line by line until you found the line you were looking for? I'm working with that idea but haven't figured out how it would be able to read the GPA after that.

Community
  • 1
  • 1
0

one plan to avoid reading different types of date in the fscanf is to always read char data into a local char array. then use sscanf to convert it to the data type you need. this allows you to add data checks between the fscanf and sscanf. this will avoid fscanf reading nothing (spinning wheels) and never getting to eof

kmstudio
  • 1
  • 2