使用strtok处理大内存文件时Valgrind检测到内存错误求助
你的Valgrind错误根源很明确:strtok函数要求处理的是标准C字符串(即以'\0'结尾的字符序列),但你当前的buffer没有预留终止符的空间,导致strtok扫描到文件末尾后,继续越界访问内存。
具体原因解释
你用calloc分配了和文件大小完全一致的buffer,然后用fread把整个文件内容读进去。但CSV文件本身的内容不会自带'\0'终止符,当strtok解析到buffer的最后一个字节时,它会继续往后查找分隔符或终止符,这就触发了Valgrind检测到的"Invalid read"错误——它访问了buffer之外的内存地址。
服务器内存足够大不是问题所在,完全是字符串处理的规范问题。
修复步骤
我给你整理了几个关键的修复点,按优先级排序:
给buffer多分配1字节,添加字符串终止符
把buffer的分配逻辑修改为:// 原代码:char* buffer = (char*) calloc(1, size); char* buffer = (char*) malloc(size + 1); // 多留1字节存'\0' if (buffer == NULL) { perror("Failed to allocate buffer"); fclose(fptr); free(intended_schedule); exit(EXIT_FAILURE); }读取文件后,手动添加终止符:
size_t bytes_read = fread(buffer, 1, size, fptr); if (bytes_read != size) { perror("Failed to read entire file"); fclose(fptr); free(buffer); free(intended_schedule); exit(EXIT_FAILURE); } buffer[size] = '\0'; // 手动添加字符串终止符这里用
malloc比calloc更高效,因为不需要初始化几百MB的内存为0——我们只需要最后一个字节是0就行。检查内存分配的返回值
你当前没有检查intended_schedule和buffer的malloc/calloc结果,虽然服务器内存大,但极端情况下还是可能分配失败,加上检查能让程序更健壮:intended_schedule = (int*) malloc(no_of_houses * no_of_appliances * no_of_sectors * sizeof(int)); if (intended_schedule == NULL) { perror("Failed to allocate intended_schedule"); exit(EXIT_FAILURE); }优化字符转整数的可读性
把token[0] - 48改成token[0] - '0',两者功能完全一样,但后者用字符常量更直观,其他开发者一眼就能看懂你是在把ASCII字符转成对应的整数。
其他可选优化建议
如果你处理的是超大型CSV文件,一次性读入内存虽然可行,但可以考虑逐行读取的方式(比如用fgets),这样能减少内存峰值占用。不过你的场景下128GB内存完全能hold住当前的内存需求,所以这个属于可选优化。
内容的提问来源于stack exchange,提问作者PPGoodMan

