CS50 Recover作业问题:首个JPEG无效,无法通过check50
Fixing the Corrupted First JPEG in CS50's Recover Assignment
Hey, let's break down why your first JPEG isn't valid while the rest work—your code's logic for handling the first JPEG header is causing it to get cut off prematurely.
The Core Issue in Your Code
When your code detects the first JPEG header, it runs two separate if blocks back-to-back:
- The first
if (!jpgAlreadyNew)block creates000.jpg, writes the 512-byte buffer, setsjpgAlreadyNewtotrue, and incrementsfilenumberto 1. - Immediately after, the second
if (jpgAlreadyNew)block triggers (since you just set the flag totrue), closes000.jpgright away, creates001.jpg, writes the same buffer again, and incrementsfilenumberto 2.
This leaves 000.jpg with only 512 bytes of data—way too short to be a valid JPEG—while the actual first image's data gets dumped into 001.jpg instead. That's why check50 fails on the first file.
Corrected Full Code
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> int main(int argc, char *argv[]) { // Ensure proper usage if (argc != 2) { fprintf(stderr, "Usage: ./recover image\n"); return 1; } // Open memory card file FILE *card_ptr = fopen(argv[1], "r"); if (card_ptr == NULL) { fprintf(stderr, "Could not open %s.\n", argv[1]); return 2; } // Allocate 512-byte buffer (check for allocation success) unsigned char *buffer = malloc(512); if (buffer == NULL) { fprintf(stderr, "Memory allocation failed.\n"); fclose(card_ptr); return 3; } bool jpg_found = false; int file_count = 0; FILE *outfile = NULL; char filename[8]; // Read 512-byte blocks until end of file while (fread(buffer, 1, 512, card_ptr) == 512) { // Check for JPEG header signature if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { // If we already have an open JPEG, close it first if (jpg_found) { fclose(outfile); } else { // Mark that we've found our first JPEG jpg_found = true; } // Create new output file sprintf(filename, "%03i.jpg", file_count); outfile = fopen(filename, "w"); if (outfile == NULL) { fprintf(stderr, "Could not create %s.\n", filename); free(buffer); fclose(card_ptr); return 4; } // Write the current block and increment file counter fwrite(buffer, 1, 512, outfile); file_count++; } else if (jpg_found) { // If we're in the middle of writing a JPEG, keep writing blocks fwrite(buffer, 1, 512, outfile); } // If no JPEG found yet, just skip the block } // Handle any remaining bytes at the end of the card (if we were writing a JPEG) if (jpg_found) { size_t remaining_bytes = fread(buffer, 1, 512, card_ptr); if (remaining_bytes > 0) { fwrite(buffer, 1, remaining_bytes, outfile); } fclose(outfile); } // Clean up resources free(buffer); fclose(card_ptr); return 0; }
Key Fixes & Improvements
- Mutually Exclusive Logic: Replaced the two separate
ifblocks with a single conditional flow—when a JPEG header is found, we either close an existing file (if we've already started writing) or mark that we've found the first JPEG, then create the new file. No more accidental double-processing of the first header. - Memory Allocation Check: Added a check to make sure
mallocdidn't fail, which prevents crashes from a null buffer. - End-of-File Handling: Added code to write any leftover bytes (less than 512) at the end of the memory card, ensuring the last JPEG is complete.
- Clearer Variable Names: Renamed
jpgAlreadyNewtojpg_foundandfilenumbertofile_countfor better readability. - Robust Loop Condition: Changed the loop to check if we read exactly 512 bytes, which is more precise than checking for non-zero (since the last read might return fewer bytes).
How to Verify
Run the corrected code, then check the first JPEG—you should be able to open it normally. When you run check50 cs50/problems/2024/x/recover, all test cases should pass.
内容的提问来源于stack exchange,提问作者Leona
相关产品推荐
相关产品推荐

