You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言实现指定格式文件扫描及按序号检索数据的问题求解

C语言文件读取+序号查询功能实现方案

常见故障原因

之前两套读取逻辑出现全0、乱码问题,基本逃不过这几个原因:

  • 未跳过首行表头:File.txt第一行是文本表头,不是有效数据,直接从文件起始位置按数值/字符串格式解析,会把表头文本写入数值变量,触发解析失败,后续文件指针位置错乱,所有数据读错
  • 字符串读取未做长度限制:name[20]最多存19个有效字符+1个字符串结束符,用无长度限制的%s读入时,一旦姓名长度超限会直接溢出数组,覆盖相邻的height、weight字段内存,直接导致数值乱码
  • 未校验解析返回值:fscanf/sscanf的返回值是成功匹配赋值的字段数,只要返回值不等于4(四个字段全匹配成功),就说明当前行解析失败,不能把无效值存入结构体,否则会残留脏数据
  • 查询逻辑直接用输入序号当下标:序号不一定从0开始、也不一定连续,直接用arr[输入序号]访问会出现数组越界,读到不属于数组的内存数据,表现为乱码甚至程序崩溃
  • 未清理输入缓冲区:scanf读入数字后会残留换行符在缓冲区,后续读入字符的逻辑会直接拿到这个换行符,导致交互逻辑异常,直接跳过用户输入。

参考实现

1. 约定File.txt格式

首行为表头,后续每行按「序号 姓名 身高(CM) 体重(KG)」顺序排列,字段间用空格/制表符分隔,示例内容:

序号 姓名 身高(CM) 体重(KG)
1 张三 175 65
2 李四 180 72
3 王五 168 52
4 赵六 183 78

2. 完整可运行代码

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

#define MAX_ENTRY 100  // 最多存储100条记录,可按需调整
#define NAME_LEN 20

// 数据存储结构体
typedef struct {
    int number;
    char name[NAME_LEN];
    int height;
    float weight;
} Person;

/**
 * 从文件加载数据
 * @param filePath 文件路径
 * @param arr 存储数据的结构体数组
 * @param count 传出参数,返回实际加载的记录条数
 * @return 0加载成功,-1加载失败
 */
int loadData(const char* filePath, Person arr[], int* count) {
    FILE* fp = fopen(filePath, "r");
    if (!fp) {
        printf("打开文件失败,请检查文件路径是否正确\n");
        return -1;
    }

    char lineBuf[1024];
    *count = 0;

    // 读取并丢弃第一行表头
    if (!fgets(lineBuf, sizeof(lineBuf), fp)) {
        fclose(fp);
        printf("文件内容为空\n");
        return -1;
    }

    // 逐行读取解析数据
    while (fgets(lineBuf, sizeof(lineBuf), fp) && *count < MAX_ENTRY) {
        // %19s限制姓名最大读入长度,防止数组溢出
        int matchCnt = sscanf(lineBuf, "%d %19s %d %f",
            &arr[*count].number,
            arr[*count].name,
            &arr[*count].height,
            &arr[*count].weight
        );
        // 只有四个字段全匹配成功才存入数组,计数+1
        if (matchCnt == 4) {
            (*count)++;
        }
    }

    fclose(fp);
    return 0;
}

// 交互查询逻辑
void queryLoop(Person arr[], int total) {
    int queryNum;
    char continueFlag;
    while (1) {
        printf("\n请输入要查询的序号:");
        // 校验输入是否为整数,非法输入清空缓冲区避免死循环
        if (scanf("%d", &queryNum) != 1) {
            while (getchar() != '\n');
            printf("输入无效,请输入数字类型的序号\n");
            continue;
        }

        // 遍历匹配序号,不要直接用序号当数组下标
        int hitIdx = -1;
        for (int i = 0; i < total; i++) {
            if (arr[i].number == queryNum) {
                hitIdx = i;
                break;
            }
        }

        if (hitIdx == -1) {
            printf("未查询到序号为%d的记录\n", queryNum);
        } else {
            printf("===== 查询结果 =====\n");
            printf("序号:%d\n姓名:%s\n身高:%dCM\n体重:%.1fKG\n",
                arr[hitIdx].number,
                arr[hitIdx].name,
                arr[hitIdx].height,
                arr[hitIdx].weight
            );
        }

        // 清空缓冲区残留的换行符,避免读入y/n时直接拿到换行
        while (getchar() != '\n');
        printf("是否继续查询?(y/n):");
        scanf("%c", &continueFlag);
        if (continueFlag != 'y' && continueFlag != 'Y') {
            printf("已退出查询\n");
            break;
        }
    }
}

int main() {
    Person people[MAX_ENTRY];
    int dataTotal = 0;

    if (loadData("File.txt", people, &dataTotal) != 0) {
        return 1;
    }
    printf("数据加载完成,共读取%d条有效记录\n", dataTotal);
    queryLoop(people, dataTotal);
    return 0;
}

关键注意点

  • 优先选fgets+sscanf的方案,比直接用fscanf鲁棒性更强,不容易因为格式不匹配导致文件指针错乱
  • 所有IO操作都要做返回值校验,不要默认读文件、解析格式一定成功
  • 字符串读入必须加长度限制,避免缓冲区溢出
  • 交互场景下注意清理输入缓冲区,否则残留的换行、非法字符会导致后续输入逻辑异常

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:51:43