简体   繁体   中英

Using fscanf in C

I am trying to read from a file into array. My file called Players.txt contains:

Del Piero|3|Italy|Juventus|
Ronaldo|0|Portugal|Real Madrit

I used fscanf , but it is not working correctly , I am not doing right the conversion.

can anyone help me to read and store them into arrays. Like the array player name to contain { Del Piero, Ronaldo}

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

#define NUM_PLAYERS 20
#define NAME_LENGTH 100
#define COUNTRY_NAME 20

int main (void)

{
    FILE *Players;

    char player_name [NUM_PLAYERS][NAME_LENGTH] = {0};
    char country_name[NUM_PLAYERS][COUNTRY_NAME] = {0};
    char team_name[NUM_PLAYERS][NAME_LENGTH] = {0};
    int goals_scored[NUM_PLAYERS] = {0};
    int i;

    Players = fopen("G:\\COP2220\\Project 5\\Players.txt", "r");
    if (Players == NULL)
    {
        printf("File not found.\n");
    }
    else

    {

       while (fscanf(Players, " %[^|]s %[^|]d %[^|]s %[^|]s",player_name[i],&goals_scored[i],country_name[i],team_name[i]))
       {
           printf("The player %s, scored %d from %s plays in %s\n", player_name, goals_scored,country_name, team_name );
       }
    }

   fclose(Players);
   return 0;
}

[] is a type all in itself, you shouldn't append s or d at the its end. All you really have to do is change the format to this:

"%[^|] | %d | %[^|] | %[^|]|\n"

And consider changing your while loop to break when fscanf doesn't return 4 .

Here's some working code:

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

#define NUM_PLAYERS 20
#define NAME_LENGTH 100
#define COUNTRY_NAME 20

int
main (void)
{
    FILE * Players;
    char player_name [NUM_PLAYERS][NAME_LENGTH] = {0};
    char country_name[NUM_PLAYERS][COUNTRY_NAME] = {0};
    char team_name[NUM_PLAYERS][NAME_LENGTH] = {0};
    int  goals_scored[NUM_PLAYERS] = {0};
    int i = 0, ret = 0;

    Players = fopen("testfile", "r");

    if (Players == NULL)
        {
            printf("File not found.\n");
        }

    else
        {
            for (;;)
                {
                    ret = fscanf(Players, "%[^|] | %d | %[^|] | %[^|]|\n",
                            player_name[i],
                            &goals_scored[i],
                            country_name[i],
                            team_name[i]);

                    if (ret != 4)
                        {
                            printf ("only %d arguments were matched\n", ret);
                            break;
                        }

                    printf("The player %s, scored %d from %s plays in %s\n",
                            player_name[i],
                            goals_scored[i],
                            country_name[i],
                            team_name[i]);
                    i++;
                }
            fclose(Players);
        }
    return 0;
}

You never actually consume the "|" characters in between your fields. Instead you're only reading up until the "|" character. Try adjusting your format string to something like:

"%[^|]|%[^|]d|%[^|]|%[^|]"

The scanf format %[^|]s reads a string of non- | characters followed by an s character, which can never match (since the next character after the string, if it exists, must be a | , not an s ). You probably want something more like:

while (4 == fscanf(Players, " %99[^|\n]|%d| %19[^|\n]| %99[^|\n]", player_name[i], &goals_scored[i], country_name[i], team_name[i]))

Note the additional string size limits to avoid overflowing arrays, and the newlines in the patterns, so that they can't be included in any of the strings (but can appear between strings).

Note also that this will match your second line, but will leave |Madrit to be read by the next call to fscanf, so you might want to put

fscanf(Players, "%*[\n]%*c");

in the loop to read the rest of the line up to the newline and throw it away.

Your format scan string is incorrect. The %[..] is itself the format specifier, adding the s or d after it is just taken to be a literal s or d in the scan string, and not a %s or %d like you are expecting.

Also, your printf() prints out the goals_scored address rather than the stored value for the player. You forgot to index the array.

It is possible to get your format scan string to work, but since the last field appears optional, you have some complexity to deal with that case. In the code below, we deal with this by explicitly calling out that the newline should not be part of the last field. Then the %*c will discard either the | or the \\n at the end. The space at the end of the scan string allows fscanf() to move to the next line in the case that the | was discarded.

   while (fscanf(Players, " %[^|]|%d|%[^|]|%[^|\n]%*c ",
                 player_name[i], &goals_scored[i], country_name[i], team_name[i]) == 4)
   {
       printf("The player %s, scored %d from %s plays in %s\n",
              player_name, goals_scored[i], country_name, team_name);
   }

However, this problem seems ideal for strtok() . The advantage is that you have more control over how to deal with each field, and you can get more information about where errors are occurring during a parse of the line.

int parse_line (char *buffer,
               char *name, int *goals, char *country, char *team,
               char **rest)
{
    char *tok = strtok(buffer, "|");
    int count = 0;
    while (tok && count < 4) {
        ++count;
        switch (count) {
        case 1: strcpy(name, tok); break;
        case 2: *goals = atoi(tok); break;
        case 3: strcpy(country, tok); break;
        case 4: strcpy(team, tok); break;
        default: break;
        }
        tok = strtok(0, "|");
    }
    *rest = tok;
    return count;
}

You would change your code to read in a line of data, and then feed that line to the parse_line() function.

char buf[MAX_LINE_LENGTH];
char *rest;
while (fgets(buf, sizeof(buf), Players) != 0) {
    parse_line(buf,
               player_name[i], &goals_scored[i], country_name[i], team_name[i],
               &rest);
    printf("The player %s, scored %d from %s plays in %s\n",
           player_name, goals_scored[i], country_name, team_name);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM