在C中使用fscanf

时间:2013-07-10 02:22:53

标签: c scanf

我正在尝试从文件读入数组。 我的名为Players.txt的文件包含:

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

我使用了fscanf,但它无法正常工作,我没有做正确的转换。

任何人都可以帮我阅读并将它们存储到数组中。就像包含{ 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;
}

4 个答案:

答案 0 :(得分:2)

[]本身就是一种类型,不应在其末尾添加sd。您真正需要做的就是将格式更改为:

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

并考虑在while未返回fscanf时将4循环更改为中断。

这是一些有效的代码:

#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;
}

答案 1 :(得分:1)

你从未真正消费过“|”字段之间的字符。相反,你只是阅读,直到“|”字符。尝试将格式字符串调整为:

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

答案 2 :(得分:1)

scanf格式%[^|]s读取一串非|字符后跟一个s字符,该字符永远不会匹配(因为字符串后面的下一个字符,如果存在,则必须是|,而不是s)。你可能想要更像的东西:

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

请注意额外的字符串大小限制,以避免数组溢出,以及模式中的换行符,以便它们不能包含在任何字符串中(但可以出现在字符串之间)。

另请注意,这将与您的第二行匹配,但会在下次调用fscanf时让|Madrit读取,因此您可能希望将

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

在循环中读取换行的其余部分并将其扔掉。

答案 3 :(得分:0)

您的格式扫描字符串不正确。 %[..]本身就是格式说明符,只需将sd添加为扫描字符串中的文字sd,而不是像你期望的%s%d

此外,您的printf()打印出goals_scored地址,而不是播放器的存储值。你忘了索引数组。

可以使您的格式扫描字符串起作用,但由于最后一个字段显示为可选字段,因此处理该情况会有一些复杂性。在下面的代码中,我们通过明确地指出换行不应该是最后一个字段的一部分来处理这个问题。然后%*c会丢弃最后的|\n。在fscanf()被丢弃的情况下,扫描字符串末尾的空格允许|移动到下一行。

   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);
   }

然而,这个问题似乎是strtok()的理想选择。优点是您可以更好地控制如何处理每个字段,并且可以获得有关在解析行期间错误发生位置的更多信息。

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;
}

您可以将代码更改为在一行数据中读取,然后将该行提供给parse_line()函数。

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);
}