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
相关产品推荐
相关产品推荐

