c - CS50 PSET4 recover.c - 我只恢复 25 jpg's
问题描述
我正在学习 CS50 课程并卡在 PSET4 上。我编写了一个从 card.raw 中恢复 JPG 的代码。问题是我在运行我的程序后只得到 25 个选择(从 000.jpg 到 024.jpg),应该有 50 个。我不知道为什么会这样。你能给我指点吗:)
我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
char *name[9] = {"card.raw"};
int i;
int a = -1;
char recovered[sizeof "050.jpg"];
uint8_t buffer[512];
int main(int argc, char *argv[])
{
//Check for valid quantity of command line arguments
if (argc != 2 || (strcmp (argv[1], *name) != 0))
{
printf("Usage: ./recover image\n");
return 1;
}
FILE *card = fopen(argv[1], "r");
//Check if file card.raw exists
if (card == NULL)
{
printf("Could not open file\n");
return 1;
}
while(fread(&buffer, 512, 1, card))
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3] & 0xf0) == 0xe0))
{
a++;
sprintf(recovered, "%03d.jpg", a);
FILE *output = fopen(recovered,"w");
if (output == NULL)
{
printf("Could not create file %03d/n",a);
return 1;
}
fwrite(buffer, 512, 1, output);
while(fread(&buffer, 512, 1, card))
{
if ( !(buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3] & 0xf0) == 0xe0)))
{
fwrite(buffer, 512, 1, output);
}
else
{
break;
}
}
fclose(output);
}
}
fclose(card);
return 0;
}
解决方案
有几个问题。
你有两个嵌套循环。你只想要一个。
当内部循环检测到标题时,您会跳出循环。
但是,只有外循环打开输出文件。
它进行新的读取,因此它永远不会看到内部循环检测到的标头,也不会打开下一个输出文件。
因此,您只能获得一半的输出文件。而且,它们都已损坏,因为它们具有第一个文件中的标头和数据,而只有第二个文件中的数据。这在整个过程中交替重复。
FILE *output
是循环范围的。它应该是功能范围的。
recovered
以非常规的方式定义。最好只用大量来定义它。这可以防止编译器将其标记为太小。编译器假设a
可能是(例如)1000000000,并且sprintf
会溢出recovered
name
也以非正统的方式定义。
i
从未使用过。
这是一个重构和注释的版本。它可以编译,但我没有测试过:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
const char *name = "card.raw";
int a = -1;
char recovered[1000];
uint8_t buffer[512];
int
main(int argc, char **argv)
{
// Check for valid quantity of command line arguments
if (argc != 2 || (strcmp(argv[1], name) != 0)) {
printf("Usage: ./recover image\n");
return 1;
}
FILE *card = fopen(argv[1], "r");
// Check if file card.raw exists
if (card == NULL) {
printf("Could not open file\n");
return 1;
}
FILE *output = NULL;
while (fread(buffer, sizeof(buffer), 1, card)) {
// detect new input header
if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) &&
(buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0)) {
// close previous output stream
if (output != NULL)
fclose(output);
// open new output stream
++a;
sprintf(recovered, "%03d.jpg", a);
output = fopen(recovered, "w");
if (output == NULL) {
printf("Could not create file %03d/n", a);
return 1;
}
}
// write data to output stream
// this writes both the header and data for a given output file
if (output != NULL)
fwrite(buffer, sizeof(buffer), 1, output);
}
// close the last output stream
if (output != NULL)
fclose(output);
fclose(card);
return 0;
}
推荐阅读
- java - 何时使用 JPA 锁定?
- ios - 在 AVPlayerViewController 上显示 UILabel
- java - 创建名称为“clienteController”的 bean 时出错:通过字段“clienteService”表示的依赖关系不满足;
- docker - 从 gitlab ci 使用 docker 发布图像
- python - 根据 pyspark 中一列的变化增加每个分区中的值
- c# - ARCore Unity 更改白平衡 (Android)
- java - Spring Boot Web 应用程序的行为就像它是单线程的
- python - 无法从网页的某个块递归解析所有链接
- c++ - 从存档中提取到内存 - libarchive
- excel - 如何根据所选的切片器编辑 VBA 脚本以保存到特定文件夹