CS50车牌读取代码Valgrind检测内存泄漏求助
CS50 License练习内存泄漏排查
问题背景
编写的C语言代码用于读取TXT文件中的车牌信息并打印,但Valgrind检测到内存泄漏,日志如下:
==11625== 448 bytes in 8 blocks are definitely lost in loss record 1 of 1 ==11625== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so) ==11625== by 0x109227: main (license.c:29) ==11625== ==11625== LEAK SUMMARY: ==11625== definitely lost: 448 bytes in 8 blocks ==11625== indirectly lost: 0 bytes in 0 blocks ==11625== possibly lost: 0 bytes in 0 blocks ==11625== still reachable: 0 bytes in 0 blocks ==11625== suppressed: 0 bytes in 0 blocks ==11625== ==11625== For lists of detected and suppressed errors, rerun with: -s ==11625== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
原本认为已通过以下代码释放内存,但实际无效:
while (idx < 8) { free(plates[idx]); idx ++; }
完整代码实现:
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char *argv[]) { // Check for command line args if (argc != 2) { printf("Usage: ./read infile\n"); return 1; } // Create buffer to read into char buffer[7]; // Create array to store plate numbers char *plates[8]; FILE *infile = fopen(argv[1], "r"); int idx = 0; while (fread(buffer, 1, 7, infile) == 7) { // Replace '\n' with '\0' buffer[6] = '\0'; plates[idx] = malloc (7 * sizeof(char *)); // Save plate number in array strcpy(plates[idx], buffer); idx++; } for (int i = 0; i < 8; i++) { printf("%s\n", plates[i]); } //free memory fclose(infile); while (idx < 8) { free(plates[idx]); idx ++; } return 0; }
问题排查与修复
1. 内存释放逻辑完全错误
你当前的释放循环条件while (idx < 8)完全搞反了:
idx是已经成功malloc并存储车牌的元素的下一个索引(比如读取了3个车牌,idx的值就是3)- 这个循环会去释放
idx到7的元素,但这些元素根本没有被malloc过(初始是野指针),而真正需要释放的0到idx-1的已分配内存完全没被处理,直接导致所有malloc的内存泄漏。
正确的释放逻辑应该是遍历所有已分配的元素:
for (int i = 0; i < idx; i++) { free(plates[i]); }
2. malloc内存大小计算错误
代码中plates[idx] = malloc (7 * sizeof(char *));存在错误:
- 我们需要分配的是存储7个char的数组,而不是7个char指针的数组
- 在64位系统下,
sizeof(char*)是8字节,这会导致每个车牌分配56字节(78),而实际只需要7字节,虽然这不是泄漏的直接原因,但会造成内存浪费,Valgrind日志中448字节8块正好是568,也能对应这个问题。
正确的malloc写法应该是:
plates[idx] = malloc(7 * sizeof(char)); // 或者更简洁的写法,因为sizeof(char)总是1 plates[idx] = malloc(7);
修正后的完整代码
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, char *argv[]) { // Check for command line args if (argc != 2) { printf("Usage: ./read infile\n"); return 1; } // Create buffer to read into char buffer[7]; // Create array to store plate numbers char *plates[8]; FILE *infile = fopen(argv[1], "r"); if (infile == NULL) { // 检查文件打开是否成功,避免空指针操作 printf("Failed to open file\n"); return 1; } int idx = 0; while (idx < 8 && fread(buffer, 1, 7, infile) == 7) // 限制循环次数,防止数组越界 { // Replace '\n' with '\0' buffer[6] = '\0'; plates[idx] = malloc(7 * sizeof(char)); if (plates[idx] == NULL) { // 检查malloc是否成功 printf("Malloc failed\n"); // 释放已分配的内存后退出 for (int i = 0; i < idx; i++) { free(plates[i]); } fclose(infile); return 1; } // Save plate number in array strcpy(plates[idx], buffer); idx++; } for (int i = 0; i < idx; i++) // 只打印已读取的车牌,避免打印未初始化的指针 { printf("%s\n", plates[i]); } //free memory fclose(infile); for (int i = 0; i < idx; i++) { free(plates[i]); } return 0; }
额外新增了几个健壮性优化:
- 检查文件是否成功打开,避免后续fread操作空指针
- 限制循环次数不超过数组大小(8),防止数组越界
- 检查malloc是否成功,避免内存分配失败后的非法访问
- 打印时只遍历已读取的车牌,避免打印未初始化的野指针
内容的提问来源于stack exchange,提问作者Mia
相关产品推荐
相关产品推荐

