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

使用strtok()时未正确检测EOF导致重复读取数据问题

问题:读取书籍CSV数据时重复输出最后一条记录

数据格式

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
9781506304213,Discrete Mathematics,Jonathan,15,19.73,10-2013
9780136019702,Chemotherapy,Karen,1,2.54,1-2002
9781152304222,Advanced Mathematics Techniques,Antony Smith,5,5.21,2-2007 
9781506304215,Social Studies,Simon Minter,10,9.73,11-2013

原错误代码

int load(Book *books, int* numberOfBooks){
  system("cls");
  // Implement
  int bookCounter = 0;
  char c;
  char line[STRING_LENGTH];

  FILE *file = fopen("books.txt", "r");
  if (file == NULL){
    printf("Error opening file");
    exit(1);
  }

  while (!feof(file))
  {
    fgets(line, STRING_LENGTH, file);
    line[strcspn(line, "\n")] = 0;
    printf("\n%s \n", line);
    
    char *bookToken = strtok(line, ",");

    strcpy(books[bookCounter].isbn, bookToken);

    bookToken = strtok(NULL, ",");

    strcpy(books[bookCounter].title, bookToken);

    bookToken = strtok(NULL, ",");
    strcpy(books[bookCounter].author, bookToken);

    bookToken = strtok(NULL, ",");
    int quantity = atoi(bookToken);
    books[bookCounter].quantity = quantity;

    bookToken = strtok(NULL, ",");
    double price = atof(bookToken);
    books[bookCounter].price = price;
    
    bookToken = strtok(NULL, ",");
    strcpy(books[bookCounter].date, bookToken);
    
  }
    bookCounter++;
    
  }
  fclose(file);
  printf("%d", bookCounter);

  return 0;

}

错误现象

程序运行时会重复输出最后一条记录的ISBN,输出如下:

780136019701,An Introduction to Organic Chemistry,Timberlake Karen,10,3.54,12-2008

781506304212,Mathematics for Social Scientists,Kropko Jonathan,7,4.73,12-2015

781506304213,Discrete Mathematics,Jonathan,15,19.73,10-2013

780136019702,Chemotherapy,Karen,1,2.54,1-2002

781152304222,Advanced Mathematics Techniques,Antony Smith,5,5.21,2-2007

781506304215,Social Studies,Simon Minter,10,9.73,11-2013

781506304215

错误原因

  1. !feof(file)的误用:这是C语言读取文件的典型错误。feof()只有在程序尝试读取超过文件末尾的内容后才会返回非零值。读取到最后一行有效数据后,!feof(file)仍为真,循环会再执行一次:此时fgets()读取失败,line数组保留着上一次的内容,导致重复处理。
  2. 语法与计数逻辑错误:原代码中bookCounter++;被放在循环外部的多余大括号内,导致整个循环结束后才计数一次,完全无法实现逐行计数。
  3. 无空指针检查:未判断strtok()返回的指针是否为NULL,若遇到格式错误的行(字段不足6个),会触发空指针访问崩溃。

修复方案

  1. 替换循环条件:用fgets()的返回值作为循环判断依据,直接确认是否成功读取一行数据。
  2. 修正计数位置:将bookCounter++;移到循环内部,每处理完一行就递增计数。
  3. 添加空指针检查:确保每个strtok()返回的指针不为NULL,避免非法内存访问。
  4. 修正语法错误:移除多余的大括号,保证代码结构正确。

修复后的代码

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

// 假设Book结构体定义如下
typedef struct {
    char isbn[20];
    char title[100];
    char author[50];
    int quantity;
    double price;
    char date[10];
} Book;

#define STRING_LENGTH 256

int load(Book *books, int* numberOfBooks){
    system("cls");
    int bookCounter = 0;
    char line[STRING_LENGTH];

    FILE *file = fopen("books.txt", "r");
    if (file == NULL){
        printf("Error opening file");
        exit(1);
    }

    // 用fgets的返回值判断读取是否成功
    while (fgets(line, STRING_LENGTH, file) != NULL)
    {
        // 去掉换行符
        line[strcspn(line, "\n")] = 0;
        // 跳过空行
        if (strlen(line) == 0) {
            continue;
        }
        printf("\n%s \n", line);
        
        char *bookToken = strtok(line, ",");
        if (bookToken == NULL) continue;
        strcpy(books[bookCounter].isbn, bookToken);

        bookToken = strtok(NULL, ",");
        if (bookToken == NULL) continue;
        strcpy(books[bookCounter].title, bookToken);

        bookToken = strtok(NULL, ",");
        if (bookToken == NULL) continue;
        strcpy(books[bookCounter].author, bookToken);

        bookToken = strtok(NULL, ",");
        if (bookToken == NULL) continue;
        books[bookCounter].quantity = atoi(bookToken);

        bookToken = strtok(NULL, ",");
        if (bookToken == NULL) continue;
        books[bookCounter].price = atof(bookToken);
        
        bookToken = strtok(NULL, ",");
        if (bookToken == NULL) continue;
        strcpy(books[bookCounter].date, bookToken);
        
        bookCounter++;
    }

    fclose(file);
    *numberOfBooks = bookCounter; // 更新输出参数
    printf("Total books loaded: %d\n", bookCounter);

    return 0;
}

内容的提问来源于stack exchange,提问作者Saif eldeen Adel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 15:10:38