C语言读取CSV文件时无法获取double类型评分值,返回NULL
CSV读取电影评分时Token始终为NULL的修复方案
问题背景
自定义struct movie结构体从CSV文件读取电影数据,实现按年份筛选、按年份展示最高评分、按语言筛选等功能,但提取double类型评分值时,token始终返回NULL,导致评分被设为默认值0.0,编译标准为--std=gnu99。
相关代码片段(Main.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> struct movie { char *title; int year; char **lang; int numLang; double ratingValue; struct movie *next; }; struct movie *createMovie(char *currLine) { struct movie *currMovie = malloc(sizeof(struct movie)); char *ptr; // 提取标题 char *token = strtok_r(currLine, ",", &ptr); currMovie->title = calloc(strlen(token) + 1, sizeof(char)); strcpy(currMovie->title, token); // 提取年份 token = strtok_r(NULL, ",", &ptr); currMovie->year = atoi(token); // 提取语言(原问题代码) token = strtok_r(NULL, ",", &ptr); token = strtok_r(token, "[];", &ptr); // 复用ptr破坏逗号分割状态 currMovie->lang = NULL; int numLang = 0; while (token != NULL) { currMovie->lang = realloc(currMovie->lang, (numLang + 1) * sizeof(char *)); currMovie->lang[numLang] = calloc(strlen(token) + 1, sizeof(char)); strcpy(currMovie->lang[numLang], token); numLang++; token = strtok_r(NULL, "[];", &ptr); // 继续复用ptr } currMovie->numLang = numLang; // 提取评分(ptr状态已破坏,无法找到正确token) token = strtok_r(NULL, "\n", &ptr); if (token != NULL) { if (sscanf(token, "%lf", &currMovie->ratingValue) != 1) { currMovie->ratingValue = 0.0; printf("Token: \"%s\". Invalid or missing rating value. Setting to default (0.0).\n", token); } } else { currMovie->ratingValue = 0.0; printf("Token is NULL. Invalid or missing rating value. Setting to default (0.0).\n"); } currMovie->next = NULL; return currMovie; } struct movie *processFile(char *filePath) { FILE *movieFile = fopen(filePath, "r"); char *currLine = NULL; size_t len = 0; size_t nread; struct movie *head = NULL; struct movie *tail = NULL; while ((nread = getline(&currLine, &len, movieFile)) != -1) { struct movie *newNode = createMovie(currLine); if (newNode == NULL) continue; if (head == NULL) { head = newNode; tail = newNode; } else { tail->next = newNode; tail = newNode; } } free(currLine); fclose(movieFile); return head; }
CSV文件片段
Title,Year,Languages,Rating Value The Incredible Hulk,2008,[English;Portuguese;Spanish],6.8 Sherlock Holmes,2009,[English;French],7.6 Iron Man,2008,[English;Persian;Urdu;Arabic;Hungarian],7.9
程序输出异常
Token is NULL. Invalid or missing rating value. Setting to default (0.0). ... Highest rated movie for each year: 2008 0.0 The Incredible Hulk 2009 0.0 Sherlock Holmes ...
问题原因
处理语言字段时,复用了分割CSV逗号的状态指针ptr。strtok_r的第三个参数用于保存当前分割状态,用同一个ptr分割语言的[];分隔符时,会破坏之前逗号分割的状态,导致后续调用strtok_r(NULL, "\n", &ptr)无法找到评分字段的token,返回NULL。
修复方案
处理语言字段时使用独立的状态指针,避免干扰原有的逗号分割状态。修改createMovie函数中的语言处理部分:
// 修复后的语言提取代码 token = strtok_r(NULL, ",", &ptr); char *lang_ptr; // 新建独立状态指针 char *lang_token = strtok_r(token, "[];", &lang_ptr); // 用lang_ptr保存语言分割状态 currMovie->lang = NULL; int numLang = 0; while (lang_token != NULL) { currMovie->lang = realloc(currMovie->lang, (numLang + 1) * sizeof(char *)); currMovie->lang[numLang] = calloc(strlen(lang_token) + 1, sizeof(char)); strcpy(currMovie->lang[numLang], lang_token); numLang++; lang_token = strtok_r(NULL, "[];", &lang_ptr); // 继续使用lang_ptr } currMovie->numLang = numLang;
修复后验证
修改后重新编译运行,将不再输出"Token is NULL"的提示,评分值会被正确提取。功能2的输出会变为:
Highest rated movie for each year: 2008 7.9 Iron Man 2009 7.6 Sherlock Holmes 2010 7.2 Iron Man 2 ...
内容的提问来源于stack exchange,提问作者Domanik Logan
相关产品推荐
相关产品推荐

