问题
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