程序从卡中恢复JPEG,但未通过CS50检查(pset4)

程序从卡中恢复JPEG,但未通过CS50检查(pset4),c,segmentation-fault,jpeg,cs50,recover,C,Segmentation Fault,Jpeg,Cs50,Recover,嘿,所有强大的程序员,恢复程序似乎工作得很好。我读过其他帖子。。。让Valgrind运行,并显示无泄漏。我有从000到049的所有50张照片。所以,我没有主意了。你们有吗?对不起,我的评论太多了,但我需要逐字逐句地跟踪发生了什么 #包括 #包括 #包括 //修复我们需要从中恢复的文件的名称 #定义名称\u原始\u文件“card.RAW” //块大小为512 #定义块大小512 //“jpg.000”+/n=>8个字符 #定义JPEG\u名称\u长度8 //jpeg文件名的格式,使用3个整数加0

嘿,所有强大的程序员,恢复程序似乎工作得很好。我读过其他帖子。。。让Valgrind运行,并显示无泄漏。我有从000到049的所有50张照片。所以,我没有主意了。你们有吗?对不起,我的评论太多了,但我需要逐字逐句地跟踪发生了什么

#包括
#包括
#包括
//修复我们需要从中恢复的文件的名称
#定义名称\u原始\u文件“card.RAW”
//块大小为512
#定义块大小512
//“jpg.000”+/n=>8个字符
#定义JPEG\u名称\u长度8
//jpeg文件名的格式,使用3个整数加0
//看https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm 
#定义JPEG文件格式“%03d.jpg”
//bool检查报头是否是jpg的报头
bool是_jpeg(无符号字符头[])
{
/*这相当于说if(condition),return TRUE。return返回函数
*表达式范围内的任何值,在本例中,如果
*验证了具有等价性的表达式,否则为false*/
返回(头[0]==0xff
&&标题[1]==0xd8
&&标题[2]==0xff
&&(头[3]&0xf0)==0xe0);
}
int main(int argc,char*argv[])
{
如果(argc!=1)
{
//程序名后没有命令行参数
fprintf(stderr,“用法:./recover\n”);
返回1;
}
//打开存储卡文件
FILE*raw_FILE=fopen(名称为“r”);
if(原始文件==NULL)
{
fprintf(stderr,“无法打开文件%s。\n”,名称为\u原始\u文件);
返回1;
}
//存储新的JPG名称并对其进行计数
字符jpeg_文件名[jpeg_名称_长度];
int jpeg_已恢复_计数器=0;
//我们正在写入的当前打开的文件
FILE*jpeg\u FILE=NULL;
/*我们需要另一个缓冲区来存储card.raw中的jpg数据
*我们使用无符号字符,因为它基本上等同于
*说字节*/
无符号字符缓冲区[块大小];
/*在存储卡的每个块上循环,直到EOF。
*这个循环的作用是检查fread函数
*返回大小为1的512字节,并断开
*当存在小于512字节的块时:文件结束*/
while(fread(缓冲区,1,块大小,原始文件)=块大小)
{
//检查块的前4个字节是否对应于jpg
如果(是jpeg(缓冲区))
{
//是否有以前打开的jpg文件?如果是,请将其关闭。
//这不会关闭设置为NULL的第一个jpg文件
//在第43行。
如果(jpeg_文件!=NULL)
{
fclose(jpeg_文件);
}
//此行创建将存储的自定义文件名
//在jpeg_文件名数组中
sprintf(jpeg_文件名、jpeg_文件格式、jpeg_恢复计数器++);
//现在,我已将文件名存储在jpeg_文件名中
//我在读写模式下以该名称打开一个文件
jpeg_file=fopen(jpeg_文件名,“w+”);
//检查jpeg_文件是否已成功打开
如果(jpeg_文件==NULL)
{
fclose(原始文件);
fprintf(标准格式,“恢复:%s:创建文件时出错”,jpeg_文件名);
返回1;
}
}
/*在此阶段,如果未找到jpeg,则未打开jpeg_文件。
*因此,我创建了一个条件来跳过任何不属于
*通过检查是否有jpeg\u文件打开来创建jpeg。如果有jpeg
*打开文件,然后写入其中*/
如果(jpeg_文件!=NULL)
{
/*所以,如果我打开了一个jpeg文件,那么我想写入它
*但我也想确保写作成功,所以我将
*在检查
*函数(块大小)。如果写入未成功,则关闭所有内容
*和打印错误*/
if(写入(缓冲区,1,块大小,jpeg文件)!=块大小)
{
fclose(jpeg_文件);
fclose(原始文件);
fprintf(stderr,“恢复:%s:写入文件时出错”,jpeg\u文件名);
返回1;
}
}
}
//关闭上次打开的文件,检查我们是否打开过一个(想象一下card.raw没有jpeg!)
如果(jpeg_文件!=NULL)
{
fclose(jpeg_文件);
}
//从卡中读取时出错了吗?
if(ferror(原始文件))
{
fclose(原始文件);
fprintf(stderr,“恢复:%s:读取文件时出错,\n”,argv[0]);
返回1;
}
//否则,一切都好。
fclose(原始文件);
返回0;
}

尝试以二进制模式打开文件,例如“rb”而不是“r”。同样,对于编写,您显然会向程序传递一个参数,第一个if块将在该程序上执行。@samgak谢谢,但不起作用。我不明白。
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

//fix the name of the file we need to recover from
#define NAME_RAW_FILE "card.raw"

//block size is 512
#define BLOCK_SIZE 512

// "jpg.000" + /n   => 8 chars
#define JPEG_NAME_LENGTH 8 

// Format of the jpeg file name, using 3 integers padded with 0's
// see https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm 
#define JPEG_FILE_FORMAT "%03d.jpg"

// bool checking if the header is the one of a jpg
bool is_jpeg (unsigned char header [])
{
    /* this is equivalent to saying if(condition), return TRUE. Return gives back to the function 
     * any value that comes out of the expression in its scope, in our case the value is TRUE if the 
     * expression with the equivalences is verified, else false. */
    return (header[0] == 0xff 
            && header[1] == 0xd8 
            && header[2] == 0xff 
            && (header[3] & 0xf0) == 0xe0);
}

int main(int argc, char *argv[])
{
    if (argc != 1)
    {
        //no command line argument after programme name
        fprintf(stderr, "Usage: ./recover\n");
        return 1;
    }

    // open memory card file 
    FILE* raw_file = fopen(NAME_RAW_FILE, "r");
    if (raw_file == NULL)
    {
        fprintf(stderr, "Could not open file %s.\n", NAME_RAW_FILE);
        return 1;
    }

    // Store new JPG name and count them 
    char jpeg_filename[JPEG_NAME_LENGTH];
    int jpeg_recoverd_counter = 0;

    // Currently opened file we're writing to 
    FILE* jpeg_file = NULL; 

    /* we need another buffer to store our jpg data from card.raw  
     * we use unsigned chars because it's basically equivalent to 
     * saying bytes */
    unsigned char buffer [BLOCK_SIZE];

    /* loop over every block of the memory card until EOF.
     * What this loop does is checking if the fread function
     * returned 512 bytes of size 1, and breaks 
     * when there is a block of less than 512 bytes : end of file */
    while (fread (buffer, 1, BLOCK_SIZE, raw_file) == BLOCK_SIZE)
    {
        // checks if the first 4 bytes of the block corresponds to a jpg 
        if (is_jpeg (buffer))
        {
            // Is there a previous jpg file open? If so, close it.
            // This won't close your first jpg file which is set to NULL
            // at line 43. 
            if (jpeg_file != NULL)
            {
                fclose(jpeg_file);
            }

            // This line creates a custom filename that will be stored 
            // in the jpeg_filename array
            sprintf(jpeg_filename, JPEG_FILE_FORMAT, jpeg_recoverd_counter++);

            // Now that I have the name of the file stored in jpeg_filename
            // I open a file in reading and writing mode with that name
            jpeg_file = fopen(jpeg_filename, "w+");

            // Check that jpeg_file opened successfully
            if(jpeg_file == NULL)
            {
                fclose(raw_file);
                fprintf(stderr, "recover: %s: Error creating file", jpeg_filename);
                return 1;
            }
        }

        /* At this stage, if no jpeg was found then no jpeg_file was opened. 
         * so I create a condition to skip any initial bytes not belonging to 
         * a jpeg by checking if there is a jpeg_file open. If we do have a jpeg 
         * file open, then write into it */

        if (jpeg_file != NULL)
        {
            /* So, if I do have a jpeg file opened, then I want to write into it
             * but I also want to make sure that the writing succeeds, so I encase 
             * fwrite function in a if condition that checks the return value of the
             * function (BLOCK_SIZE). If the writing did not succeed then close everything 
             * and print error. */
            if(fwrite(buffer, 1, BLOCK_SIZE, jpeg_file) != BLOCK_SIZE)
            {
                fclose(jpeg_file);
                fclose(raw_file);
                fprintf(stderr, "recover: %s : Error writing the file\n", jpeg_filename);
                return 1;
            }
        }
    }

    // Close last file open, checking that we ever opened one (imagine card.raw had no jpeg!)
    if(jpeg_file != NULL)
    {
        fclose(jpeg_file);
    }

    // Was there an error reading from the card?
    if(ferror(raw_file))
    {
        fclose(raw_file);
        fprintf(stderr, "recover: %s: Error reading file\n", argv[0]);
        return 1;
    }

    // Else, all good. 
    fclose(raw_file);
    return 0;
}