如何将CSV文件读取到C语言struct中?配料字段读取失败求助
问题描述
需要读取特定格式的CSV文件,将每列数据存入指定的order结构体中。
CSV示例数据:
1.00,1.00,hawaiian_m,1.00,1/1/2015,11:38:36,13.25,13.25,M,Classic,"Sliced Ham, Pineapple, Mozzarella Cheese",The Hawaiian Pizza 2.00,2.00,classic_dlx_m,1.00,1/1/2015,11:57:40,16.00,16,M,Classic,"Pepperoni, Mushrooms, Red Onions, Red Peppers, Bacon",The Classic Deluxe Pizza 3.00,2.00,five_cheese_l,1.00,1/1/2015,11:57:40,18.50,18.5,L,Veggie,"Mozzarella Cheese, Provolone Cheese, SmokedGouda Cheese, Romano Cheese, Blue Cheese, Garlic",The Five Cheese Pizza
指定的结构体定义:
typedef struct{ float pizza_id; float order_id; char pizza_name_id[50]; float quantity; char order_date[50]; char order_time[50]; float unit_price; float total_price; char pizza_size; char pizza_category[50]; char pizza_ingredients[100]; char pizza_name[50]; } order;
编写的读取代码中,pizza_ingredients字段无法正常读取:
while (!feof(f)) { read = fscanf(f,"%f,%f,%49[^,],%f,%49[^,],%49[^,],%f,%f,%c,%49[^,],%2047[^34],%49[^,]\n", &or[linea].pizza_id, &or[linea].order_id, or[linea].pizza_name_id, &or[linea].quantity, or[linea].order_date, or[linea].order_time, &or[linea].unit_price, &or[linea].total_price, &or[linea].pizza_size, or[linea].pizza_category, or[linea].pizza_ingredients, or[linea].pizza_name); linea++; }
问题原因
- 格式控制符错误:读取
pizza_ingredients时使用的%2047[^34]逻辑错误,[^34]表示读取到ASCII码34(双引号)为止,但未处理字段前后的双引号边界,导致读取内容不符合预期。 pizza_size读取异常:%c会直接读取total_price后的逗号,而非目标字符(如'M'/'L'),因为没有跳过字段间的分隔符。feof误用:while (!feof(f))会导致最后一行被重复读取,因为feof仅在尝试读取超出文件末尾时才会触发。- 缓冲区溢出风险:
%2047[^34]指定的读取长度远大于pizza_ingredients数组的100字节容量,会导致内存溢出。
修正方案
1. 修正读取代码
调整格式控制字符串,适配带双引号的字段,并修复其他读取问题:
// 用fscanf返回值判断是否成功读取所有12个字段,替代feof判断 while (fscanf(f,"%f,%f,%49[^,],%f,%49[^,],%49[^,],%f,%f, %c,%49[^,],\"%99[^\"]\",%49[^\n]\n", &or[linea].pizza_id, &or[linea].order_id, or[linea].pizza_name_id, &or[linea].quantity, or[linea].order_date, or[linea].order_time, &or[linea].unit_price, &or[linea].total_price, &or[linea].pizza_size, or[linea].pizza_category, or[linea].pizza_ingredients, or[linea].pizza_name) == 12) { linea++; }
关键修正点:
pizza_size读取:在%c前添加空格%c,自动跳过字段间的逗号和空白字符,确保读取到正确的尺寸字符。pizza_ingredients读取:使用\"%99[^\"]\",先匹配开头的双引号,再读取所有非双引号字符(最多99个,适配数组100字节的容量),最后匹配结尾的双引号,完美适配带逗号的配料字段。- 替换
feof判断:通过fscanf返回值是否等于12(字段总数)来控制循环,避免重复读取,同时能在读取失败时及时退出。 pizza_name读取:用%49[^\n]读取到换行符为止,避免被不存在的逗号截断。
2. 额外注意事项
- 确认
pizza_ingredients数组长度足够容纳最长的配料字符串,若实际数据超过100字节,需增大数组容量,避免缓冲区溢出。 - 若CSV文件存在复杂格式(如字段内换行),
fscanf的健壮性不足,建议改用逐行读取后手动分割字段的方式,或使用成熟的CSV解析库。
内容的提问来源于stack exchange,提问作者gonza
相关产品推荐
相关产品推荐

