CS50 Recover中为何需检查文件指针非空?能否直接写入?
CS50 Recover作业代码疑问解答
你提到的两段代码核心差异在于对JPEG完整数据的写入逻辑,以及空指针安全处理,下面具体解释:
为什么第一段必须检查output_file非空?
1. 满足JPEG的连续块存储要求
在Recover作业的磁盘镜像里,JPEG是被拆成连续的512字节块存储的:一个完整JPEG = 起始标识块 + N个后续数据块,直到下一个JPEG的起始块出现或文件结束。
第一段代码的逻辑是:
- 检测到JPEG起始块时,打开对应的输出文件
- 之后每一次循环读取的512字节块,只要当前有打开的输出文件(
output_file != NULL),就写入该文件
这样就能把当前JPEG的所有后续数据块都写入到同一个文件里,保证生成的JPEG是完整可打开的。
而第二段代码只在检测到起始块时写入那一个512字节块,后续属于该JPEG的所有数据块都被忽略了,生成的文件只有开头512字节,是损坏的。
2. 避免空指针操作的安全风险
fopen并非一定能成功(比如磁盘满了、权限不足、路径错误),失败时会返回NULL指针。如果直接对NULL调用fwrite,会触发未定义行为——程序可能崩溃、输出垃圾数据,甚至破坏其他内存数据。
第一段代码的if (output_file != NULL)检查,确保只有文件成功打开时才执行写入,从根源避免了这种风险。而第二段代码完全没有这个检查,一旦fopen失败,后续操作必然出问题。
3. 过滤开头的无效垃圾数据
磁盘镜像的开头可能存在不属于任何JPEG的垃圾数据,第一段代码里output_file初始化为NULL,这些垃圾数据会因为output_file == NULL被跳过,不会写入任何文件,保证输出的都是有效JPEG内容。
第一段完整代码(整理后)
FILE *input_file = fopen(argv[1], "r"); // 检查输入文件是否打开失败 if (input_file == NULL) { printf("Could not open file"); return 2; } // 存储512字节数据块的缓冲区 unsigned char buffer[512]; // 统计找到的JPEG数量 int count_image = 0; // 输出文件指针,初始化为NULL FILE *output_file = NULL; // 分配文件名存储内存(格式为"000.jpg",占8字节) char *filename = malloc(8 * sizeof(char)); // 循环读取512字节块,直到文件结束 while (fread(buffer, sizeof(char), 512, input_file)) { // 检查当前块是否是JPEG起始标识 if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { // 生成格式化文件名(如001.jpg) sprintf(filename, "%03i.jpg", count_image); // 打开输出文件 output_file = fopen(filename, "w"); // 计数加一 count_image++; } // 如果输出文件已成功打开,写入当前数据块 if (output_file != NULL) { fwrite(buffer, sizeof(char), 512, output_file); } } // 释放内存并关闭文件 free(filename); fclose(output_file); fclose(input_file); return 0;
第二段代码片段
if(buffer[0]==0xff && buffer[1]==0xd8 && buffer[2]==0xff && (buffer[3] & 0xf0) == 0xe0) { sprintf(filename, "%03i.jpg", counter); img = fopen(filename, "w"); fwrite(buffer,sizeof(uint8_t),512,img); counter++; }
内容的提问来源于stack exchange,提问作者ptk03
相关产品推荐
相关产品推荐

