C语言JPG恢复程序出现段错误(疑为指针/数组问题)
存储卡JPG恢复程序段错误排查与修复
核心错误点分析
- 重复读取导致数据异常:while循环头部已经完成一次512字节块的读取,但在分支逻辑中又重复调用
fread,导致每次循环实际读取2个块,不仅跳过了匹配到JPG头的关键块,还会在文件末尾触发无效读取,引发后续操作的非法内存访问。 - 未初始化指针非法访问:在找到第一个JPG之前,
img指针为NULL,此时else分支直接调用fwrite写入img,必然触发段错误。 - 变量重定义与内存操作错误:在第一个JPG的处理分支中,重定义了
file_name变量,覆盖了外部的命令行参数指针,最后free(file_name)实际是在释放系统管理的argv指针,属于非法操作;同时分支内malloc的文件名指针未被释放,造成内存泄漏。 - JPG头判断逻辑错误:
(buffer[3] & 0xf0) == 0不符合JPG文件规范,正确的第四字节应该是0xe0-0xef区间,即(buffer[3] & 0xf0) == 0xe0。
修正后的完整代码
#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 = fopen(argv[1], "r"); if (input == NULL) { printf("file <%s> could not be opened\n", argv[1]); return 1; } const int BLOCK_SIZE = 512; BYTE buffer[BLOCK_SIZE]; int jpeg_counter = 0; FILE *img = NULL; char output_filename[17]; // 固定长度足够存储"XXX.jpg"格式的文件名 // 循环读取每个512字节块 while (fread(buffer, sizeof(BYTE), BLOCK_SIZE, input) == BLOCK_SIZE) { // 判断当前块是否为JPG文件起始签名 if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { // 如果已有打开的JPG文件,先关闭 if (img != NULL) { fclose(img); } // 生成输出文件名(000.jpg, 001.jpg...) sprintf(output_filename, "%.3i.jpg", jpeg_counter); img = fopen(output_filename, "w"); if (img == NULL) { fclose(input); return 1; } // 将当前块写入新的JPG文件 fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, img); jpeg_counter++; } // 若已处于JPG写入状态,继续写入当前块 else if (img != NULL) { fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, img); } } // 关闭所有打开的文件,释放资源 if (img != NULL) { fclose(img); } fclose(input); return 0; }
关键修正说明
- 移除重复读取操作:仅在循环头部执行一次
fread,后续直接使用buffer中的数据,确保每个块都被正确处理,不会跳过关键数据。 - 增加空指针校验:在写入操作前检查
img是否有效,避免对未初始化指针的非法访问。 - 优化文件名存储:改用固定大小的字符数组存储输出文件名,避免malloc/free带来的内存管理错误和泄漏。
- 修复JPG头判断:修正第四字节的判断逻辑,符合JPG文件的起始签名标准。
- 完善资源清理:确保所有打开的文件都被正确关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Charlie Webster
相关产品推荐
相关产品推荐

