CS50 pset4 recover程序运行触发Segmentation fault问题求助
问题原因分析
以下是导致段错误的核心问题:
fread返回值判断逻辑写反
fread返回值为成功读取的元素个数,你代码中写while(fread(buffer, sizeof(BLOCK_SIZE), 1, infile) == 0)意味着只要成功读取到512字节块就直接退出循环,逻辑完全错误。正确写法为判断返回值等于1,代表成功读取一个完整块。
- 非法访问未初始化的
outfile指针
未找到第一个JPEG头时,
outfile还未通过fopen赋值,此时走到else分支会直接调用fwrite写野指针;如果输入文件中没有JPEG,循环结束后直接调用fclose(outfile)也会访问野指针,这是触发段错误的直接原因,和valgrind输出的未初始化值访问报错完全对应。
- 文件打开模式错误
读写二进制文件需要使用
"rb"(读二进制)、"wb"(写二进制)模式,你当前用的文本模式"r"/"w"在部分系统下会导致二进制数据解析异常。
- 文件名数组长度卡边界(非崩溃直接原因,建议优化)
你定义的
char file[8]刚好能存下000.jpg加末尾的字符串结束符\0,没有冗余空间,建议直接定义为char file[16]避免后续修改规则时出现缓冲区溢出。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <stdint.h> int main(int argc, char *argv[]) { const int BLOCK_SIZE = 512; typedef uint8_t BYTE; if (argc != 2) { printf("Usage: ./recover image\n"); return 1; } // 二进制模式打开输入文件 FILE *infile = fopen(argv[1], "rb"); if (infile == NULL) { printf("Could not open input file\n"); return 2; } int index = 0; FILE *outfile = NULL; // 初始化空指针,避免野访问 char file[16]; // 扩大文件名数组容量 BYTE buffer[BLOCK_SIZE]; // 正确判断fread返回值,成功读一个块才进入循环 while (fread(buffer, BLOCK_SIZE, 1, infile) == 1) { // 检测JPEG头 if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { // 已经有打开的输出文件,先关闭 if (outfile != NULL) { fclose(outfile); } // 生成新文件名 sprintf(file, "%03i.jpg", index); // 二进制模式打开输出文件 outfile = fopen(file, "wb"); if (outfile == NULL) { printf("Could not create output file %s\n", file); fclose(infile); return 3; } index++; } // 只有输出文件已经打开时才写数据 if (outfile != NULL) { fwrite(buffer, BLOCK_SIZE, 1, outfile); } } // 关闭前先判断指针不为空 if (outfile != NULL) { fclose(outfile); } fclose(infile); return 0; }
内容的提问来源于stack exchange,提问作者Annie
相关产品推荐
相关产品推荐

