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

如何在C语言中将含空格的CSV文件读取到结构体中?

解决CSV文件中含空格字段的C语言结构体解析问题

要将逗号分隔的文本文件读取到C结构体中,但书名、作者名这类含空格的字段无法用fscanf正常解析——因为fscanf("%s")会在空白字符处截断内容,导致读取的数据完全错乱。

文本文件内容

9780136019701,An Introduction to Organic Chemistry,Timberlake Karen,10,3.54,12-2008
9781506304212,Mathematics for Social Scientists,Kropko Jonathan,7,4.73,12-2015

原代码核心问题

  1. fscanf("%s")无法读取带空格的字段,会把空格后的内容错误识别为下一个字段
  2. Book结构体中price定义为int,与文件中的浮点数类型不匹配
  3. while(!feof(ptr))作为循环条件会导致最后一次循环读取无效数据
  4. 日期解析逻辑混乱,无法正确获取格式为MM-YYYY的日期值

解决方案

  1. 逐行读取完整记录:用fgets读取整行内容,确保不丢失含空格的字段
  2. 按逗号分割字段:使用strtok以逗号为分隔符拆分每个字段,支持含空格的内容
  3. 修正类型匹配:将Book结构体的price改为float,匹配文件中的浮点数
  4. 正确解析日期:拆分日期字段后,用sscanf提取月份和年份
  5. 优化循环与内存:用fgets返回值判断循环结束,初始分配内存并按需扩容,避免频繁realloc

修改后的完整代码

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

typedef struct Date
{
    int year;
    int month;
} Date;

typedef struct Book
{
    long long int isbn;
    char title[100];
    char author[100];
    int quantity;
    float price;  // 修正为float类型,匹配文件中的浮点数
    Date date;
} Book;

int main() {
    Book* books = NULL;
    int n_books = 0;
    int capacity = 2;  // 初始分配容量,减少realloc调用次数
    char line[256];    // 存储单行记录,长度足够容纳一条完整数据
    FILE *ptr = fopen("Books.txt", "r");

    if (ptr == NULL) {
        printf("无法加载图书数据\n");
        exit(EXIT_FAILURE);
    }

    // 初始内存分配
    books = malloc(sizeof(Book) * capacity);
    if (books == NULL) {
        printf("内存分配失败\n");
        fclose(ptr);
        exit(EXIT_FAILURE);
    }

    // 逐行读取文件,直到文件结束
    while (fgets(line, sizeof(line), ptr) != NULL) {
        // 内存扩容:当前记录数达到容量时,翻倍扩容
        if (n_books >= capacity) {
            capacity *= 2;
            Book* temp = realloc(books, sizeof(Book) * capacity);
            if (temp == NULL) {
                printf("内存扩容失败\n");
                free(books);
                fclose(ptr);
                exit(EXIT_FAILURE);
            }
            books = temp;
        }

        Book* current_book = &books[n_books];

        // 按逗号拆分字段
        char* token = strtok(line, ",");
        if (token == NULL) continue;
        sscanf(token, "%lld", &current_book->isbn);

        // 读取书名,安全复制避免溢出
        token = strtok(NULL, ",");
        if (token == NULL) continue;
        strncpy(current_book->title, token, sizeof(current_book->title) - 1);
        current_book->title[sizeof(current_book->title) - 1] = '\0';

        // 读取作者
        token = strtok(NULL, ",");
        if (token == NULL) continue;
        strncpy(current_book->author, token, sizeof(current_book->author) - 1);
        current_book->author[sizeof(current_book->author) - 1] = '\0';

        // 读取库存数量
        token = strtok(NULL, ",");
        if (token == NULL) continue;
        sscanf(token, "%d", &current_book->quantity);

        // 读取价格
        token = strtok(NULL, ",");
        if (token == NULL) continue;
        sscanf(token, "%f", &current_book->price);

        // 读取日期,先移除换行符再拆分
        token = strtok(NULL, ",");
        if (token == NULL) continue;
        size_t len = strlen(token);
        if (len > 0 && token[len-1] == '\n') {
            token[len-1] = '\0';
        }
        sscanf(token, "%d-%d", &current_book->date.month, &current_book->date.year);

        // 打印验证结果
        printf("书名:%s\n", current_book->title);
        printf("ISBN:%lld\n", current_book->isbn);
        printf("价格:%.2f\n", current_book->price);
        printf("出版日期:%d-%d\n", current_book->date.month, current_book->date.year);
        printf("库存:%d\n", current_book->quantity);
        printf("作者:%s\n\n", current_book->author);

        n_books++;
    }

    fclose(ptr);
    free(books);
    return EXIT_SUCCESS;
}

关键说明

  • fgets读取整行:确保每条记录的所有字段被完整捕获,不受空格干扰
  • strtok分割字段:以逗号为分隔符,精准提取每个字段,支持含空格的内容
  • 安全字符串复制:用strncpy替代strcpy,手动添加终止符避免缓冲区溢出
  • 内存安全检查:每次内存分配/扩容后都检查是否成功,避免内存泄漏或崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 15:05:25