You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何正确使用fscanf读取含空格与'-'的足球比赛数据文件

解决C语言解析足球比赛TXT数据的问题

首先,你的核心问题是fscanf格式字符串没有正确匹配文本中的固定分隔符-,另外file_read里用feof循环也有坑,咱们一步步来解决:

一、修复fscanf的格式问题

你的数据里,队名之间是teamA - teamB,比分是goalsA - goalsB,这些-是固定的分隔符,直接把它们写进fscanf的格式字符串里就行——fscanf会自动跳过前后的空白字符。

修改read_match函数的fscanf语句:

Match read_match(FILE *file_ptr) {
    Match input = {0}; // 初始化结构体,避免垃圾值干扰调试
    // 直接把固定的"-"写进格式串,精准匹配数据中的分隔规则
    int read_count = fscanf(file_ptr, "%s %s %s %s - %s %d - %d %d",
                           input.day, input.date, input.time,
                           input.team_A, input.team_B,
                           &input.goals_A, &input.goals_B,
                           &input.spectators);
    // 调试时可以打印读取成功的字段数,快速定位问题
    if (read_count != 8) {
        printf("Warning: 读取一行失败,仅读取了%d个字段\n", read_count);
    }
    printf("(day) %s (date) %s (time) %s (teamA) %s (teamB) %s (scoreA) %d (scoreB) %d (spect) %d\n", 
           input.day, input.date, input.time, input.team_A, input.team_B, 
           input.goals_A, input.goals_B, input.spectators);
    return input;
}

二、修复file_read的循环逻辑

原代码用while(!feof(file_ptr))是典型的错误写法——feof只有在读取失败后才会被置位,这会导致你最后多读一行无效数据。正确的做法是通过fscanf的返回值判断是否成功读取了完整的一行:

修改file_read函数:

int file_read(char *file_input, Match arr_matches[]) {
    int r = 0;
    FILE *file_ptr = fopen(file_input, "r");
    if (file_ptr == NULL) {
        printf("Error! Can't open file!");
        return -1; // 返回-1表示打开错误,和正常读取行数区分开
    }
    Match temp;
    // 用fscanf返回值判断是否成功读取8个字段
    while (fscanf(file_ptr, "%s %s %s %s - %s %d - %d %d",
                  temp.day, temp.date, temp.time,
                  temp.team_A, temp.team_B,
                  &temp.goals_A, &temp.goals_B,
                  &temp.spectators) == 8) {
        arr_matches[r] = temp;
        r++;
        // 防止数组越界,避免内存错误
        if (r >= MATCHES) {
            printf("Warning: 比赛数量超过数组上限,已停止读取\n");
            break;
        }
    }
    fclose(file_ptr);
    return r;
}

三、用strtok的替代方案

如果你想用strtok来解析,需要注意分隔符是空格和-,而且要跳过空token(因为-前后有空格,会产生空的分割结果)。修改后的strtok示例:

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

int main () {
    char str[80] = "Fre 12/07 19.00 FCM - EFB 1 - 0 7310 ";
    const char *delim = " -"; // 分隔符是空格和-
    char *token;

    token = strtok(str, delim);
    int field_idx = 0;
    while( token != NULL ) {
        // 跳过空token(连续分隔符会产生空结果)
        if (strlen(token) == 0) {
            token = strtok(NULL, delim);
            continue;
        }
        // 根据字段索引对应到结构体的各个字段
        switch(field_idx) {
            case 0: printf("Day: %s\n", token); break;
            case 1: printf("Date: %s\n", token); break;
            case 2: printf("Time: %s\n", token); break;
            case 3: printf("Team A: %s\n", token); break;
            case 4: printf("Team B: %s\n", token); break;
            case 5: printf("Goals A: %d\n", atoi(token)); break;
            case 6: printf("Goals B: %d\n", atoi(token)); break;
            case 7: printf("Spectators: %d\n", atoi(token)); break;
        }
        field_idx++;
        token = strtok(NULL, delim);
    }
    return 0;
}

这种方法适合数据格式可能有变动的场景,但需要手动处理字符串到整数的类型转换。

四、额外注意事项

  • 结构体初始化:一定要初始化结构体(比如Match input = {0};),避免未初始化的垃圾值干扰调试结果。
  • 数组越界保护:file_read里要检查r是否超过MATCHES,防止数组溢出导致内存错误。
  • 错误处理区分:fopen失败返回-1,而不是1,这样main函数可以区分是打开错误还是正常读取了1行数据。

内容的提问来源于stack exchange,提问作者MMAndersen

火山引擎 最新活动