CS50 pset4 recover - 恢复的图像不匹配
CS50 pset4 recover - Recovered image does not match
我已经尝试解决这个问题至少一个星期了,似乎无法理解问题出在哪里,我已经检查了 google 中的所有内容,并且不认识任何真正的程序员生活问他们个人,所以如果有人能帮助我,那就太好了。
None 个图像生成负载,它没有恢复 50 个,它恢复了 986 个。
我在 check50 中得到这个结果:
:) recover.c 存在。
:) recover.c 编译。
:) 处理缺少取证图像
:( 正确恢复 000.jpg
恢复的图像不匹配
:( 正确恢复中间图像
恢复的图像不匹配
:( 正确恢复 049.jpg
恢复的图像不匹配
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
int main(int argc, char *argv[])
{
//it only accepts one comand argument in the name of an image
if (argc != 2)
{
printf("Usage: ./recover IMAGE");
return 1;
}
//check if it can open the image
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("The image cannot be opened");
return 1;
}
bool jpg_before = false;
int counter = 0;
FILE *image = NULL;
char name[8];
unsigned char buffer[BLOCK_SIZE];
//while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0)
{
jpg_before = true;
}
if(jpg_before == true)
{
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "a");
fwrite(buffer, BLOCK_SIZE, 1, image);
fclose(image);
}
}
fclose(file);
}
(还请记住我是编程新手,16 岁,英语不是我的母语)
- 当您在输入中检测到 header 时,您设置
jpg_before
。但是,你永远不会清除它。
- 设置标志后,每个块将放入不同的文件中。
- 每个输出文件应该包含一个header,然后是相关的数据块。
name[8]
有点太小了。编译器会抱怨,因为 int
可能 [理论上] 是 10 位左右,所以 sprintf
可能会溢出。不要吝啬——使用(例如):char name[20];
- 输出文件应使用
"w"
而不是 "a"
打开。如果程序 运行 两次,第二次,输出文件将不正确。
重构代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
int
main(int argc, char *argv[])
{
// it only accepts one comand argument in the name of an image
if (argc != 2) {
printf("Usage: ./recover IMAGE");
return 1;
}
// check if it can open the image
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
printf("The image cannot be opened");
return 1;
}
int counter = 0;
FILE *image = NULL;
char name[20];
unsigned char buffer[BLOCK_SIZE];
// while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1) {
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0) {
if (image != NULL)
fclose(image);
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "w");
}
fwrite(buffer, BLOCK_SIZE, 1, image);
}
if (image != NULL)
fclose(image);
fclose(file);
}
更新:
来自以下评论:
Points 2 and 3 look to be handled by the file being opened for appending. Leaving the file open is probably a better idea, though. Faster and handles point 6. –
user4581301
如果 H
是 header 并且 D
是数据,对于(例如)的输入:H1,D1,D2,D3,D4,H2,D5,D6,D7
:
而不是两个输出文件:F0:H1,D1,D2,D3,D4
和 F1:H2,D5,D6,D7
我们有:F0:H1
、F1:D1
、F2:D2
、F3:D3
、F4:D4
、F5:H2
、F6:D5
, F7:D6
, F8:D7
虽然我重构的代码是正确的,但我回答的顶部部分对 OP 代码实际执行的操作的分析不正确。
我已经解决了。但是,为了使 user4581301 有意义,这里是原始分析:
- 当您在输入中检测到 header 时,您设置
jpg_before
。但是,你永远不会清除它。
- 您仅写入header块的输出流,因此任何数据都不会复制。因此,每个输出文件 仅 为 512 字节
- 您在写入 header 后立即关闭输出流。它应该保持打开状态。
- 每个块都必须转到给定的输出文件,而不仅仅是 header。
name[8]
有点太小了。编译器会抱怨,因为 int
可能 [理论上] 是 10 位左右,所以 sprintf
可能会溢出。不要吝啬——使用(例如):char name[20];
- 输出文件应使用
"w"
而不是 "a"
打开。如果程序 运行 两次,第二次,输出文件将不正确。
更新#2:
First of all thanks! But it is giving me a segmentation fault, do you have any idea why? because everything seems correct –
Isa M
根据代码检查,唯一 可能 段错误的地方是 fwrite
调用(即 image
是 NULL
).
我通过 运行 在 gdb
[我有 cs50 恢复输入文件] 下的程序确认了这一点。当程序出错时,只需执行 tb
即可获得堆栈回溯。
image
可能是 NULL
,原因如下:
输出文件的 fopen
可能会失败(由于权限、space 等)和 return NULL
。调用后没有检查,因为有打开输入文件。
image
开始是 NULL
。如果有某种额外的文件 data/file header before the first jpg header (e.g. before FF/D8/FF/E0
) if
将 not 匹配 first 块读取。即使 image
.
中有 NULL,fwrite
也会被调用
选项(2)是实际发生的,因为cs50的文件在文件顶部有一个额外的header。您可以通过使用十六进制 editor/dumper(例如)od
或 xxd
:
检查文件来看到这一点
00000000: 00000000 00000000 00000000 00000000 ................
*
00000200: 63733530 2E6C792F 73757270 72697365 cs50.ly/surprise
00000210: 00000000 00000000 00000000 00000000 ................
*
00000400: FFD8FFE0 00104A46 49460001 01000001 ......JFIF......
代码将不会看到有效的header(即if
匹配)直到偏移量400。所以,有开始时有两个 个无关的 fread
调用,直到事情同步。
解决方法是更改:
fwrite(buffer, BLOCK_SIZE, 1, image);
进入:
if (image != NULL)
fwrite(buffer, BLOCK_SIZE, 1, image);
这个问题我以前写过几个答案。但是,我忘记包括这个。我刚写了代码,但 没有 测试它 ;-)
为了解决问题,我添加了更多 return 代码检查并向 fopen
调用添加了 "rb"
和 "wb"
,以防万一运行在 Windoze 上运行。
这是 updated/fixed 代码(这次我 测试了 ;-):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
//#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
void
onerr(const char *action,const char *file)
{
printf("%s -- %s -- %s\n",action,file,strerror(errno));
exit(1);
}
int
main(int argc, char *argv[])
{
// it only accepts one comand argument in the name of an image
if (argc != 2) {
printf("Usage: ./recover IMAGE");
return 1;
}
// check if it can open the image
FILE *file = fopen(argv[1], "rb");
if (file == NULL)
onerr("The image cannot be opened",argv[1]);
int counter = 0;
FILE *image = NULL;
char name[20];
unsigned char buffer[BLOCK_SIZE];
// while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1) {
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xe0) == 0xe0) {
if (image != NULL)
fclose(image);
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "wb");
if (image == NULL)
onerr("unable to open output file",name);
}
#if 0
fwrite(buffer, BLOCK_SIZE, 1, image);
#else
if (image != NULL)
fwrite(buffer, BLOCK_SIZE, 1, image);
#endif
}
if (image != NULL)
fclose(image);
fclose(file);
return 0;
}
我已经尝试解决这个问题至少一个星期了,似乎无法理解问题出在哪里,我已经检查了 google 中的所有内容,并且不认识任何真正的程序员生活问他们个人,所以如果有人能帮助我,那就太好了。
None 个图像生成负载,它没有恢复 50 个,它恢复了 986 个。
我在 check50 中得到这个结果:
:) recover.c 存在。
:) recover.c 编译。
:) 处理缺少取证图像
:( 正确恢复 000.jpg
恢复的图像不匹配
:( 正确恢复中间图像
恢复的图像不匹配
:( 正确恢复 049.jpg
恢复的图像不匹配
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
int main(int argc, char *argv[])
{
//it only accepts one comand argument in the name of an image
if (argc != 2)
{
printf("Usage: ./recover IMAGE");
return 1;
}
//check if it can open the image
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("The image cannot be opened");
return 1;
}
bool jpg_before = false;
int counter = 0;
FILE *image = NULL;
char name[8];
unsigned char buffer[BLOCK_SIZE];
//while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1)
{
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0)
{
jpg_before = true;
}
if(jpg_before == true)
{
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "a");
fwrite(buffer, BLOCK_SIZE, 1, image);
fclose(image);
}
}
fclose(file);
}
(还请记住我是编程新手,16 岁,英语不是我的母语)
- 当您在输入中检测到 header 时,您设置
jpg_before
。但是,你永远不会清除它。 - 设置标志后,每个块将放入不同的文件中。
- 每个输出文件应该包含一个header,然后是相关的数据块。
name[8]
有点太小了。编译器会抱怨,因为int
可能 [理论上] 是 10 位左右,所以sprintf
可能会溢出。不要吝啬——使用(例如):char name[20];
- 输出文件应使用
"w"
而不是"a"
打开。如果程序 运行 两次,第二次,输出文件将不正确。
重构代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
int
main(int argc, char *argv[])
{
// it only accepts one comand argument in the name of an image
if (argc != 2) {
printf("Usage: ./recover IMAGE");
return 1;
}
// check if it can open the image
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
printf("The image cannot be opened");
return 1;
}
int counter = 0;
FILE *image = NULL;
char name[20];
unsigned char buffer[BLOCK_SIZE];
// while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1) {
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xe0) == 0xe0) {
if (image != NULL)
fclose(image);
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "w");
}
fwrite(buffer, BLOCK_SIZE, 1, image);
}
if (image != NULL)
fclose(image);
fclose(file);
}
更新:
来自以下评论:
Points 2 and 3 look to be handled by the file being opened for appending. Leaving the file open is probably a better idea, though. Faster and handles point 6. – user4581301
如果 H
是 header 并且 D
是数据,对于(例如)的输入:H1,D1,D2,D3,D4,H2,D5,D6,D7
:
而不是两个输出文件:F0:H1,D1,D2,D3,D4
和 F1:H2,D5,D6,D7
我们有:F0:H1
、F1:D1
、F2:D2
、F3:D3
、F4:D4
、F5:H2
、F6:D5
, F7:D6
, F8:D7
虽然我重构的代码是正确的,但我回答的顶部部分对 OP 代码实际执行的操作的分析不正确。
我已经解决了。但是,为了使 user4581301 有意义,这里是原始分析:
- 当您在输入中检测到 header 时,您设置
jpg_before
。但是,你永远不会清除它。 - 您仅写入header块的输出流,因此任何数据都不会复制。因此,每个输出文件 仅 为 512 字节
- 您在写入 header 后立即关闭输出流。它应该保持打开状态。
- 每个块都必须转到给定的输出文件,而不仅仅是 header。
name[8]
有点太小了。编译器会抱怨,因为int
可能 [理论上] 是 10 位左右,所以sprintf
可能会溢出。不要吝啬——使用(例如):char name[20];
- 输出文件应使用
"w"
而不是"a"
打开。如果程序 运行 两次,第二次,输出文件将不正确。
更新#2:
First of all thanks! But it is giving me a segmentation fault, do you have any idea why? because everything seems correct – Isa M
根据代码检查,唯一 可能 段错误的地方是 fwrite
调用(即 image
是 NULL
).
我通过 运行 在 gdb
[我有 cs50 恢复输入文件] 下的程序确认了这一点。当程序出错时,只需执行 tb
即可获得堆栈回溯。
image
可能是 NULL
,原因如下:
输出文件的
fopen
可能会失败(由于权限、space 等)和 returnNULL
。调用后没有检查,因为有打开输入文件。
中有 NULL,image
开始是NULL
。如果有某种额外的文件 data/file header before the first jpg header (e.g. beforeFF/D8/FF/E0
)if
将 not 匹配 first 块读取。即使image
.fwrite
也会被调用
选项(2)是实际发生的,因为cs50的文件在文件顶部有一个额外的header。您可以通过使用十六进制 editor/dumper(例如)od
或 xxd
:
00000000: 00000000 00000000 00000000 00000000 ................
*
00000200: 63733530 2E6C792F 73757270 72697365 cs50.ly/surprise
00000210: 00000000 00000000 00000000 00000000 ................
*
00000400: FFD8FFE0 00104A46 49460001 01000001 ......JFIF......
代码将不会看到有效的header(即if
匹配)直到偏移量400。所以,有开始时有两个 个无关的 fread
调用,直到事情同步。
解决方法是更改:
fwrite(buffer, BLOCK_SIZE, 1, image);
进入:
if (image != NULL)
fwrite(buffer, BLOCK_SIZE, 1, image);
这个问题我以前写过几个答案。但是,我忘记包括这个。我刚写了代码,但 没有 测试它 ;-)
为了解决问题,我添加了更多 return 代码检查并向 fopen
调用添加了 "rb"
和 "wb"
,以防万一运行在 Windoze 上运行。
这是 updated/fixed 代码(这次我 测试了 ;-):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
//#include <cs50.h>
typedef uint8_t BYTE;
#define BLOCK_SIZE 512
void
onerr(const char *action,const char *file)
{
printf("%s -- %s -- %s\n",action,file,strerror(errno));
exit(1);
}
int
main(int argc, char *argv[])
{
// it only accepts one comand argument in the name of an image
if (argc != 2) {
printf("Usage: ./recover IMAGE");
return 1;
}
// check if it can open the image
FILE *file = fopen(argv[1], "rb");
if (file == NULL)
onerr("The image cannot be opened",argv[1]);
int counter = 0;
FILE *image = NULL;
char name[20];
unsigned char buffer[BLOCK_SIZE];
// while there is still jpegs in the file
while (fread(buffer, BLOCK_SIZE, 1, file) == 1) {
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xe0) == 0xe0) {
if (image != NULL)
fclose(image);
sprintf(name, "%03i.jpg", counter);
counter++;
image = fopen(name, "wb");
if (image == NULL)
onerr("unable to open output file",name);
}
#if 0
fwrite(buffer, BLOCK_SIZE, 1, image);
#else
if (image != NULL)
fwrite(buffer, BLOCK_SIZE, 1, image);
#endif
}
if (image != NULL)
fclose(image);
fclose(file);
return 0;
}