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

C++读取CSV至结构体数组报错:整数与字符数组读取失败

搞定CSV读取与二进制写入的坑

需求与现有问题

你需要读取CSV文件,将数据存入struct后写入二进制文件,CSV列对应:

  • (int) 年份
  • (int) 排名
  • (char[]) 大学名称
  • (float) 评分
  • (char[]) 城市
  • (char[]) 国家

示例CSV内容:

2018,1,Harvard University,97.7,Cambridge,United States
2018,2,University of Cambridge,94.6,Cambridge,United Kingdom
2018,3,University of Oxford,94.6,Oxford,United Kingdom
2018,4,Massachusetts Institute of Technology (MIT),92.5,Cambridge,United States
2018,5,Johns Hopkins University,92.1,Baltimore,United States

当前代码存在两个核心问题:整数读取受逗号干扰,调用getline读取字符数组时出现段错误,原代码如下:

struct Data
{
  int year;
  int rank;
  char name[30];
  float score;
  char city[30];
  char country[30];
};


Data *universitie = new Data [5];
ifstream read ( "myFile.csv" );
int i = 0;

while ( !read.eof() ) {
  read >> universitie[i].year;
  read >> universitie[i].rank;
  read.getline (universitie[i].name, 30, ','); //此处出现段错误
  read >> universitie[i].score;
  read.getline (universitie[i].city, 30, ','); //此处出现段错误
  read.getline (universitie[i].country, 30, '\n'); //此处出现段错误
  i++;
}
read.close ();

注:因后续需写入二进制文件,必须使用char[30]而非string。


问题根源分析

  1. 整数读取残留分隔符:>>运算符读取整数后,会将输入流中的逗号留在缓冲区,后续getline会直接读取这个逗号,导致读取内容为空或异常。
  2. 段错误触发原因:
    • 残留的分隔符让getline读取的内容不符合预期,甚至导致字符数组越界写入。
    • 使用!read.eof()作为循环条件是典型陷阱——EOF仅在读完最后一个字符后触发,读取失败后仍会继续循环,导致数组下标越界访问。

修正后的完整代码

#include <fstream>
#include <cstring>
#include <limits> // 用于处理输入流的最大长度

using namespace std;

struct Data
{
    int year;
    int rank;
    char name[30];
    float score;
    char city[30];
    char country[30];
};

int main() {
    const int MAX_UNIVERSITIES = 5;
    Data* univs = new Data[MAX_UNIVERSITIES];
    ifstream infile("myFile.csv");
    int idx = 0;

    // 循环条件:未超出数组上限,且输入流状态正常
    while (idx < MAX_UNIVERSITIES && infile) {
        // 读取年份,跳过后续所有字符直到逗号(兼容整数与逗号间的空格)
        infile >> univs[idx].year;
        infile.ignore(numeric_limits<streamsize>::max(), ',');

        // 读取排名,跳过后续逗号
        infile >> univs[idx].rank;
        infile.ignore(numeric_limits<streamsize>::max(), ',');

        // 读取大学名称(到逗号为止),处理数组长度不足的情况
        infile.getline(univs[idx].name, sizeof(univs[idx].name), ',');
        if (infile.fail() && !infile.eof()) {
            infile.clear(); // 清除输入流错误状态
            infile.ignore(numeric_limits<streamsize>::max(), ','); // 跳过当前字段剩余内容
        }

        // 读取评分,跳过后续逗号
        infile >> univs[idx].score;
        infile.ignore(numeric_limits<streamsize>::max(), ',');

        // 读取城市(到逗号为止)
        infile.getline(univs[idx].city, sizeof(univs[idx].city), ',');
        if (infile.fail() && !infile.eof()) {
            infile.clear();
            infile.ignore(numeric_limits<streamsize>::max(), ',');
        }

        // 读取国家(到换行符为止)
        infile.getline(univs[idx].country, sizeof(univs[idx].country));
        if (infile.fail() && !infile.eof()) {
            infile.clear();
            infile.ignore(numeric_limits<streamsize>::max(), '\n');
        }

        idx++;
    }
    infile.close();

    // 将结构体数组写入二进制文件
    ofstream outfile("universities.bin", ios::binary);
    if (outfile) {
        outfile.write(reinterpret_cast<char*>(univs), sizeof(Data) * idx);
        outfile.close();
    }

    delete[] univs;
    return 0;
}

关键注意事项

  • 正确处理整数后的分隔符:用ignore(numeric_limits<streamsize>::max(), ',')替代单纯的ignore(),能跳过整数与逗号之间的所有字符(包括空格),确保后续getline读取到正确内容。
  • 安全使用getline读取字符数组:
    • 始终用sizeof(数组名)指定读取长度,避免硬编码数值,防止数组长度修改后出现遗漏。
    • 每次getline后检查流状态,若因数组长度不足导致读取失败,需先清除错误状态,再跳过当前字段剩余内容,避免后续读取全部失效。
  • 避免!read.eof()的陷阱:直接用infile作为循环条件,它会同时检查EOF、错误、失败三种状态,再结合数组上限限制,彻底避免数组越界。
  • 二进制写入的必要设置:打开文件时必须指定ios::binary模式,防止Windows系统自动转换换行符,破坏二进制数据结构。

内容的提问来源于stack exchange,提问作者Étalo Alves Rabelo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:05:33