问题
So I'm trying CS50 Recover exercise (where you need to search for jpg files in a memory card and whenever you find one- you open a new file and write the jpg found to the new file). My code compiles but when I'm running the check50 command I'm receiving the following errors:
:( recovers 000.jpg correctly
recovered image does not match
:( recovers middle images correctly
recovered image does not match
:( recovers 049.jpg correctly
recovered image does not match
Can somebody help me figure out what am I doing wrong? This is my code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// Checking if the user entered a correct input:
if (argc!=2)
{
printf("You're not using it correctly!\n");
return 1;
}
// Opening the file in argv[1]
FILE *f=fopen(argv[1], "r");
// Validating that there's a file in argv[1]
if(f==NULL)
{
printf("File hasn't found\n");
return 1;
}
unsigned char bytes[512];
int counter=0;
FILE *img= NULL;
while (fread(bytes, 512, 1, f)==1)
{
if (bytes[0]==0xff && bytes[1]==0xd8 && bytes[2]==0xff && (bytes[3]&0xf0)==0xe0)
{
// If it's the first jpg found:
if (counter==0)
{
img=fopen("000.jpg", "w");
}
else
{
fclose(img);
char filename[8];
sprintf(filename,"%03i.jpg", counter);
img= fopen(filename, "w");
if (img==NULL)
{
printf("Couldn't open file\n");
return 1;
}
}
counter++;
fwrite(bytes, 512, 1, img);
}
}
fclose(img);
fclose(f);
}
回答1:
Your primary problem is that you are not handling multiblock files correctly.
You only do the fwrite
if the current block has the header. Otherwise, you are throwing away the data.
That's because the fwrite
is inside the if
block that detects the header.
If you have encountered the first (i.e. any) header, you will have an open output stream. Therefore, after that, you have to do the fwrite
on each loop iteration.
Since you set img
to NULL
before entering the outer loop, there is no need to special case the 000.jpg
And, if the input file did not have a header [ever], the final fclose
would segfault because the img
pointer would be NULL
.
I've annotated the bugs [with fixes]. I've wrapped the old/new code if #if 0
blocks:
#if 0
// old/original code
#else
// new/refactored code
#endif
Here's the code:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
// Checking if the user entered a correct input:
if (argc != 2) {
printf("You're not using it correctly!\n");
return 1;
}
// Opening the file in argv[1]
FILE *f = fopen(argv[1], "r");
// Validating that there's a file in argv[1]
if (f == NULL) {
printf("File hasn't found\n");
return 1;
}
unsigned char bytes[512];
int counter = 0;
FILE *img = NULL;
while (fread(bytes, 512, 1, f) == 1) {
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff &&
(bytes[3] & 0xf0) == 0xe0) {
// NOTE/BUG: no need to special case the first file
#if 0
// If it's the first jpg found:
if (counter == 0) {
img = fopen("000.jpg", "w");
}
else {
fclose(img);
#else
if (img != NULL)
fclose(img);
#endif
char filename[8];
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
if (img == NULL) {
printf("Couldn't open file\n");
return 1;
}
#if 0
}
#endif
counter++;
// NOTE/BUG: this is only executed if the current block has a header string
#if 0
fwrite(bytes, 512, 1, img);
#endif
}
// NOTE/FIX: this is the correct placement for the write
#if 1
if (img != NULL)
fwrite(bytes, 512, 1, img);
#endif
}
// NOTE/BUG: if the input file had _no_ header, img will be NULL
#if 0
fclose(img);
#else
if (img != NULL)
fclose(img);
#endif
fclose(f);
}
Here's the fully cleaned up and refactored code [without the #if 0
]:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
// Checking if the user entered a correct input:
if (argc != 2) {
printf("You're not using it correctly!\n");
return 1;
}
// Opening the file in argv[1]
FILE *f = fopen(argv[1], "r");
// Validating that there's a file in argv[1]
if (f == NULL) {
printf("File hasn't found\n");
return 1;
}
unsigned char bytes[512];
int counter = 0;
FILE *img = NULL;
while (fread(bytes, 512, 1, f) == 1) {
if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff &&
(bytes[3] & 0xf0) == 0xe0) {
if (img != NULL)
fclose(img);
char filename[8];
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
if (img == NULL) {
printf("Couldn't open file\n");
return 1;
}
counter++;
}
if (img != NULL)
fwrite(bytes, 512, 1, img);
}
if (img != NULL)
fclose(img);
fclose(f);
}
来源:https://stackoverflow.com/questions/63561945/cs50-recover-pset4-images-not-recovered