从CSV读取数据存入哈希表后,string转float失败(stof抛出异常)
问题分析与修复
核心错误原因
你的代码里内部while循环逻辑完全错误——每次用getline(s, data[i], ',')读取一个字段后,立刻就给stu结构体赋值,这时候data数组还没读满5个元素(比如第一次循环只读到data[0],data[1]到data[4]都是空值或乱码),用stof(data[4])转换空字符串或无效内容,必然抛出std::invalid_argument异常。
另外还可能存在CSV格式问题:比如某行字段数量不足5个,或者score字段不是合法浮点数(包含空格、字母等),也会触发该错误。
修复方案
1. 修正读取逻辑:先读完整行字段,再赋值
把内部while循环改为仅负责读取所有字段到data数组,等整行5个字段全部读取完成后,再进行哈希计算和结构体赋值。
2. 增加数据校验
- 检查每行读取的字段数量是否为5,避免数组越界和无效数据。
- 捕获
stof的转换异常,防止程序直接崩溃,同时定位错误行。
3. 细节优化
- 遵循C++标准,将
main函数改为返回int类型。 - 初始化
stu数组,避免输出时出现乱码。 - 修改
display函数,只输出有数据的位置,减少无效空行。
修改后的完整代码
#include <iostream> #include <fstream> #include <sstream> #include <string> #include <bits/stdc++.h> using namespace std; struct student { string id; string name; string gender; string department; float score; }; // 初始化数组,避免默认值乱码 student stu[2000] = {}; int hash_function(string s){ int total = 0; for(int i=0; i<s.size(); i++){ total += (int)s[i]; } return total % 2000; } void display(){ for(int i=0; i<2000; i++){ // 只输出有数据的位置,避免大量空行 if(!stu[i].id.empty()){ cout << "Position " << i << ": " << stu[i].id << " " << stu[i].name << " " << stu[i].gender << " " << stu[i].department << " " << stu[i].score << endl; } } } int main(){ // 标准main返回int fstream myfile; string line; string data[5]; myfile.open("I3list.csv", ios::in); if(!myfile.is_open()){ // 检查文件是否成功打开 cerr << "无法打开文件!" << endl; return 1; } while(getline(myfile, line)){ int i = 0; stringstream s(line); // 先把整行的所有字段读入data数组 while(getline(s, data[i], ',') && i < 5){ i++; } // 校验字段数量是否为5 if(i != 5){ cerr << "无效行,字段数量不对:" << line << endl; continue; } // 所有字段读取完成,开始处理 int index = hash_function(data[1]); stu[index].id = data[0]; stu[index].name = data[1]; stu[index].gender = data[2]; stu[index].department = data[3]; // 捕获stof转换异常 try{ stu[index].score = stof(data[4]); } catch(const std::invalid_argument& e){ cerr << "分数转换失败,行内容:" << line << endl; cerr << "错误信息:" << e.what() << endl; // 设置默认值避免后续出错 stu[index].score = 0.0f; } catch(const std::out_of_range& e){ cerr << "分数超出范围,行内容:" << line << endl; cerr << "错误信息:" << e.what() << endl; stu[index].score = 0.0f; } } display(); myfile.close(); return 0; }
额外注意事项
- 确保CSV文件每行都是5个字段,用英文逗号分隔,无多余空格或换行。
- 如果CSV存在带逗号的字段(比如名字包含逗号),这种简单的按逗号分割方式会失效,需要更专业的CSV解析逻辑,但普通格式场景下上述代码足够使用。
内容的提问来源于stack exchange,提问作者Ly Makara
相关产品推荐
相关产品推荐

