C 韩元';无法从文件读取到结构

C 韩元';无法从文件读取到结构,c,file,struct,C,File,Struct,这个问题我已经解决了两天了,我不知道我做错了什么。我试过调试(有点?还是有点新的),然后点击这个链接:我试过谷歌和各种各样的东西。基本上,我是从以下格式的文件中读取的: 2015年7月17日星期一18.00 FCN-特别提款权0-23.211 我必须让程序把它读入一个结构,但是当我试着打印信息时,结果是完全错误的。我的代码如下所示: #include <stdio.h> #include <string.h> #include <stdlib.h> #defi

这个问题我已经解决了两天了,我不知道我做错了什么。我试过调试(有点?还是有点新的),然后点击这个链接:我试过谷歌和各种各样的东西。基本上,我是从以下格式的文件中读取的:

2015年7月17日星期一18.00 FCN-特别提款权0-23.211

我必须让程序把它读入一个结构,但是当我试着打印信息时,结果是完全错误的。我的代码如下所示:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_INPUT 198

typedef struct game{
    char   weekday[4],
           home_team[4],
           away_team[4];
    int    round,
           hour,
           minute,
           day,
           month,
           year,
           home_goals,
           away_goals,
           spectators;}game;

game make_game(FILE *superliga);

int main(void){
    int    input_number,
           number_of_games = 198,
           i = 0;
    game   tied[MAX_INPUT];

    FILE *superliga;
    superliga = fopen("superliga-2015-2016.txt", "r");

    for(i = 0; i < number_of_games; ++i){
                tied[i] = make_game(superliga);
                printf("R%d %s %d/%d/%d %d.%d %s - %s %d - %d %d\n",
                        tied[i].round, tied[i].weekday, tied[i].day, tied[i].month,
                        tied[i].year, tied[i].hour, tied[i].minute, tied[i].home_team,
                        tied[i].away_team, tied[i].home_goals, tied[i].away_goals,
                        tied[i].spectators);}

 fclose(superliga);

 return 0;
}

game make_game(FILE *superliga){
    double spect;
    struct game game_info;

    fscanf(superliga, "R%d %s %d/%d/%d %d.%d %s - %s %d - %d %lf\n",
            &game_info.round, game_info.weekday, &game_info.day, &game_info.month,
            &game_info.year, &game_info.hour, &game_info.minute, game_info.home_team,
            game_info.away_team, &game_info.home_goals, &game_info.away_goals,
            &spect);

         game_info.spectators = spect * 1000;

    return game_info;
 }
#包括
#包括
#包括
#定义最大输入198
typedef结构游戏{
字符工作日[4],
主队[4],
客场球队[4];
整数圆,
小时,
分钟,
白天
月,
年,
家庭目标,
客场进球,
观众;}比赛;
游戏制作(文件*超级联赛);
内部主(空){
int输入_编号,
游戏数量=198,
i=0;
打成平局[最大输入];
文件*superliga;
superliga=fopen(“superliga-2015-2016.txt”,“r”);
对于(i=0;i<游戏数;++i){
打成平局(超级联赛);
printf(“R%d%s%d/%d/%d%d.%d%s-%s%d-%d%d\n”,
平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,平局,
打成平局[i]。年,打成平局[i]。小时,打成平局[i]。分钟,打成平局[i]。主队,
平手[i]。客场球队,平手[i]。主场进球,平手[i]。客场进球,
并列的,并列的【例】观众
fclose(超级联赛);
返回0;
}
游戏制作(文件*超级联赛){
双spect;
结构游戏信息;
fscanf(superliga,“R%d%s%d/%d/%d%d.%d%s-%s%d-%d%lf”,
&game_info.round、game_info.weekday、game_info.day和game_info.month、,
&游戏信息年、游戏信息小时、游戏信息分钟、游戏信息主场团队、,
比赛信息。客场比赛团队,比赛信息。主场比赛进球,比赛信息。客场比赛进球,
&spect);
游戏信息观众=spect*1000;
返回游戏信息;
}

如果文件中的每一行都是单独的记录,则应将每一行作为字符串读取,然后尝试分析每个字符串

(请注意,这还增加了推测性解析的功能:您可以尝试以几种不同的格式解析行,并接受正确解析的格式。我喜欢在接受向量输入时使用此功能,以便用户可以使用
x y z
x,y,z
x/y/z
(x,y,z)
[x,y,z]
等等,这取决于他们喜欢什么。毕竟,每种格式只需额外扫描一次。)

要读取行,您可以使用到本地缓冲区中。本地缓冲区必须足够长。如果该程序仅在POSIX.1机器上运行(即,不在Windows上),那么您可以使用它,它可以根据需要动态地重新分配给定的缓冲区,因此您不受任何特定行长度的限制

要解析字符串,请使用

请注意,所有scanf函数系列中模式中的所有制表符、空格和换行符都被完全相同地对待:它们表示任意数量的任意类型的空白。换句话说,
\n
并不意味着“然后换行”;它的意思与空格相同,即“这里可能还有一些空格”。但是,除了
%c
%[
之外的所有转换都会自动跳过任何前导空格;因此,除了这两个空格之前的空格外,模式中的空格仅对我们人类有意义,它们在扫描中没有任何功能效果

所有scanf系列函数都返回成功转换的次数。(唯一的例外是“conversion”
%n
,它产生所消耗的字符数;有些实现将其包含在转换计数中,而有些实现则不包含。)如果在第一次转换之前出现输入结束,或出现读取错误,或输入与模式的固定部分不匹配,则函数将返回
EOF

即使您禁止保存转换结果——例如,如果输入中有一个不需要的字,您也可以转换,但可以使用
%*s
--放弃它,它也会被计数。因此,例如
sscanf(line,“%*d%*s%*d”)
如果该行以整数开头,后跟一个字,则返回3(任何不是换行符或不包含空格的内容),后跟整数

与其让函数返回解析后的结构,不如传递一个指向该结构的指针(以及要读取的文件句柄),然后返回一个状态码。我更喜欢
0
表示成功,非零表示失败,但可以随意更改

换句话说,我建议您将read函数改为

#ifndef  GAME_LINE_MAX
#define  GAME_LINE_MAX   1022
#endif

int read_game(game *one, FILE *in)
{
    char  buffer[GAME_LINE_MAX + 2]; /* + '\n' + '\0' */
    char *line;

    /* Sanity check: no NULL pointers accepted! */
    if (!one || !in)
        return -1;

    /* Paranoid check: Fail if read error has already occurred. */
    if (ferror(in))
        return -1;

    /* Read the line */
    line = fgets(buffer, sizeof buffer, in);
    if (!line)
        return -1;

    /* Parse the game; pattern from OP's example: */
    if (sscanf(line, "R%d %3s %d/%d/%d %d.%d %3s - %3s %d - %d %d\n",
                     &(one->round), one->weekday,
                     &(one->day), &(one->month), &(one->year),
                     &(one->hour), &(one->minute)
                     one->home_team,
                     one->away_team,
                     &(one->home_goals),
                     &(one->away_goals),
                     &(one->spectators)) < 12)
        return -1; /* Line not formatted like above */

    /* Spectators in the file are in units of 1000; convert: */
    one->spectators *= 1000;

    /* Success. */
    return 0;
}
上面的两个
if
子句分别用于检查是否存在真正的读取错误(例如,硬件问题或类似问题),以及是否存在未读取/未分析的数据(不是在文件末尾)

与OP相比,扫描模式有两个不同之处:首先,所有解析的字符串都限制为3个字符,因为结构中每个字符串只能容纳3+1个字符。一个字符保留在字符串
'\0'
的末尾,这不计入
%s
的最大长度。其次,我解析观众计数直接,如果成功,将字段乘以1000

还要注意我是如何使用
one->weekday
one->home\u team
one->away\u team
来引用字符数组的。这是有效的,因为数组变量可以被用作指向该数组中第一个元素的指针。(给定
char a[5];
a
&a
&a
(a[0]))都可以用来引用数组中的第一个元素
a
)。我喜欢在扫描时使用这种“原始形式”,因为这样可以更容易地将它们与
%s
转换匹配
game  g;

while (!read_game(&g, stdin)) {

    /* Do something with current game stats, g */

}

if (ferror(stdin)) {

    /* Read error occurred! */

} else
if (!feof(stdin)) {

    /* Not all data was read/parsed! */

}
fscanf(superliga, " R%d %s %d/%d/%d %d.%d %s - %s %d - %d %lf\n",
            &game_info.round, game_info.weekday, &game_info.day, &game_info.month,
            &game_info.year, &game_info.hour, &game_info.minute, game_info.home_team,
            game_info.away_team, &game_info.home_goals, &game_info.away_goals,
            &spect);