You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:35:20