-2

I have a problem when I try to read the file information for my struct with fscanf(). It just reads the first line of the string and the loop never ends. How can I solve the problem?

Struct

typedef struct {
    int id;
    char name[80];
    char nameStadium[80];
    int numberPlacesStadium;
    float funds;
    float monthlyExpenses;
    int active;
} Team;

And I use this code to read

void showAll(void)
{
    FILE* file;
    Team team;

    file = fopen("file.txt", "rt");

    if (file == NULL)
    {
        printf("!!!Cant open file!!!\n");
        return;
    }

    rewind(file);

    printf("\n\n=== TEAMS ======\n");
    printf("%s\t%s\n", "ID", "NAME");

    while (fscanf(file, "%6d %s %s %6d %f %f %03d\n", &team.id, team.name, team.nameStadium, &team.numberPlacesStadium, &team.funds, &team.monthlyExpenses, &team.active) != EOF)
    {
        if (team.active != 0)
        {
            printf("%d\t%s\n", team.id, team.name);
        }
    }

    fclose(file);

}

I can't understand why fscanf() just gets the first word and not the full string

Does anyone know how to solve this?

Nuno Antunes
  • 49
  • 1
  • 2
  • 11
  • 4
    1) do not compare against `EOF`, compare against expected success `while (fscanf(file, "%6d %s %s %6d %f %f %03d\n", ....) == 7)` 2) **post sample** file.txt. Even better a [mcve] 3) `%03d` is questionable. Try `%3d`. 4) Do names/stadia contain spaces? – chux - Reinstate Monica Dec 22 '19 at 05:31
  • Your question title states "fscanf reads only first word" but later in the text it is said "it just reads the first line", so did the fscanf stop working after first word or first line? If it stopped after the first word when trying to read the `team.name` as a string (`%s`), this post (https://stackoverflow.com/questions/1247989/how-do-you-allow-spaces-to-be-entered-using-scanf) might help. Anyway, as @chux - Reinstate Monica already commented, sample input is helpful. – Yingyu YOU Dec 22 '19 at 06:45
  • 1
    `char *path="file.txt"; if( (file = fopen(path, "r")) == NULL ) { perror(path); ...}` . Error messages matter. They should tell you the reason for the failure and be written to the proper stream. – William Pursell Dec 22 '19 at 06:46
  • See [The 10 Commandments for C Programmers - No. 6](http://www.seebs.net/c/10com.html) Ye be warned... – David C. Rankin Dec 22 '19 at 06:49
  • chux - Reinstate Monica, Yes name and stadium have spaces in the strings – Nuno Antunes Dec 22 '19 at 07:03
  • 1
    The `%s` scan format stops at the first space, whereas in print formats, it prints the whole string — spaces, newlines and all. Therefore, you can print data that cannot be read back using the same format that was used to produce it. How can you tell which words belong to the stadium name? Can you use a scan set (such as `%79[^0-9]`) to control the input up to the first digit (assuming stadium names contain no digits, which probably isn't safe). There are reasons people use delimiter characters (other than white space) — this is an example of why. – Jonathan Leffler Dec 22 '19 at 07:07
  • `%s` - String of characters - Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence. See http://www.cplusplus.com/reference/cstdio/scanf/ – Yingyu YOU Dec 22 '19 at 07:08

1 Answers1

0

I just tested out your code with a sample text file I made following the format you posted. Everything is read in and seems to be fine except that you didn't properly close the file. It should look like this.

fclose(file);

If you want your code to be able to read in strings with spaces, your best bet is to use a delimiter system. The code below reads for their type (assuming the integers won't have spaces in-between them), reads for a sequence of 80 characters that aren't commas (which will be the names), and then proceeds with the other numbers separated by commas.

  while (fscanf(file, "%d, %80[^,], %80[^,], %d, %f, %f, %d\n", &team.id, 
     team.name, team.nameStadium, &team.numberPlacesStadium, &team.funds, 
    &team.monthlyExpenses, &team.active) != EOF) 
  {
      if (team.active != 0)
    {
        printf("%d\t%s %s\n", team.id, team.name, team.nameStadium);
    }
  }

I've tested it to work and it does, but keep in mind this also isn't the most elegant solution.

These are what the rows in my text file looks like:

 133222, Bears, Bears Stadium, 444333, 23, 35.3, 52
 666222, Eagles, Eagles Stadium, 322222, 13, 56.3, 54
dinonugs
  • 59
  • 1
  • 4
  • Did your string have more than one word ?? Regarding the fclose error was a typo in the post, may the problem be involved with the fact that I am using Visual Studio IDE? – Nuno Antunes Dec 22 '19 at 07:01
  • Yes but your strings have no space, they have a special character, if you have space it won't work right – Nuno Antunes Dec 22 '19 at 14:15
  • 1
    I mean, you technically could, but it would be very sloppy-looking and hard to track while scanning. Most file I/O with text files is done with some sort of delimiter for convenience and stability, and that delimiter is usually a comma. It's the standard when it comes to databases like Access and Excel. – dinonugs Dec 22 '19 at 21:02