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

CS50 Recover习题:已释放内存仍出现Segmentation Fault求助

CS50 Recover习题代码段错误排查与修复

核心错误分析

你的代码编译通过但运行时触发段错误,主要源于几个关键逻辑错误:

1. 内存释放时机错误

free(filename)被放在while循环内部,第一次循环执行后就释放了filename指向的内存。后续循环中再调用sprintf(filename, ...)时,会访问已经被释放的内存空间(野指针),直接触发段错误。

2. 循环内提前关闭文件并终止程序

fclose(output_file)、fclose(input_file)和return 0都在循环内部,第一次循环就会关闭输入文件并退出程序,根本无法处理后续的512字节块。此外,首次循环时output_file初始值为NULL,调用fclose(NULL)属于未定义行为,也会导致崩溃。

3. 未关闭前一个JPEG文件

当检测到新的JPEG头时,直接打开新的output_file却没有关闭之前打开的文件,会造成文件资源泄漏,同时可能导致写入数据混乱。

修复后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;

int main(int argc, char *argv[])
{
    // 检查命令行参数数量
    if (argc != 2)
    {
        printf("Usage: ./recover FILENAME\n");
        return 1;
    }

    // 打开输入文件
    FILE *input_file = fopen(argv[1], "r");
    if (input_file == NULL)
    {
        printf("No existing file\n");
        return 1;
    }

    unsigned char buffer[512];
    int image_count = 0;
    FILE *output_file = NULL;
    // 分配文件名内存:"%03i.jpg"最多需要7字符+1终止符,8字节足够
    char *filename = malloc(8 * sizeof(char));
    if (filename == NULL)
    {
        fclose(input_file);
        printf("Memory allocation failed\n");
        return 1;
    }

    while (fread(buffer, sizeof(BYTE), 512, input_file) == 512)
    {
        // 检测JPEG文件头
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            // 如果已经打开了一个JPEG文件,先关闭它
            if (output_file != NULL)
            {
                fclose(output_file);
            }

            // 生成文件名并打开新的输出文件
            sprintf(filename, "%03i.jpg", image_count);
            output_file = fopen(filename, "w");
            image_count++;
        }

        // 如果当前有打开的输出文件,写入数据
        if (output_file != NULL)
        {
            fwrite(buffer, sizeof(BYTE), 512, output_file);
        }
    }

    // 循环结束后关闭最后一个输出文件(如果存在)
    if (output_file != NULL)
    {
        fclose(output_file);
    }

    // 释放内存并关闭输入文件
    free(filename);
    fclose(input_file);
    return 0;
}

关键修复点说明

  • 将free(filename)、fclose和return 0移到循环外部,确保内存只在程序结束前释放,输入文件处理完所有块后再关闭。
  • 检测到新JPEG头时,先关闭之前打开的output_file,避免资源泄漏。
  • 增加filename分配失败的检查,增强程序健壮性。
  • 用sizeof(BYTE)代替sizeof(char),与之前的类型定义保持一致,更清晰。

内容的提问来源于stack exchange,提问作者lukadeving

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:01:17