无法理解CS50第4周的代码:恢复

u3r8eeie  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(131)

因此,虽然我理解了恢复的大部分代码......我在理解它的某些部分时遇到了麻烦。我已经写了一个我认为在代码中发生的事情的总结,如果有人能纠正我,如果我的解释是错误的,我将不胜感激。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    // Check how many input commands
    if (argc != 2)
    {
        printf("Invalid Usage. Try ./recover IMAGE\n");
        return 1;
    }

    // Open file and make sure input file is valid
    FILE* input_file = fopen(argv[1], "r");
    if (input_file == NULL)
    {
        printf("Could not open file.\n");
        return 2;
    }

    // Buffer to read through each block of memory
    uint8_t buffer[512] = {0};

    // Count number of images
    int count_image = 0;

    // Creating output file
    FILE* output_file = NULL;

    // Allocating space for output file name
    char* filename = malloc(sizeof(char));

    // Reading through the input file
    while (fread(buffer, sizeof(uint8_t), 512, input_file))
    {
        // Checking for JPEG header
        if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0))
        {

            // Write JPEG filename
            sprintf(filename, "%03i.jpg", count_image);

            // Open output file
            output_file = fopen(filename, "w");

            // Increment image
            count_image++;

        }

        // If file hasn't been been used yet
        if (output_file != NULL)
        {
            fwrite(buffer, sizeof(uint8_t), 512, output_file);
        }

    }

    free(filename);
    fclose(output_file);
    fclose(input_file);

    return 0;
}

字符串
因此,在这个问题中,我们应该恢复JPEG的。存储卡有一堆512字节大小的块。JPEG可以使用多个512大小的块,任何多余的空间都用0填充。
我们首先做一些标准的事情,确保输入是有效的,并且输入文件打开时没有任何错误。然后我们初始化一个缓冲区来存储512字节大小的块,这样我们就可以一次遍历存储卡的一个块。然后我们初始化count-image来计数图像,以及一个名为output-file的空指针。最后,我们初始化另一个指针filename,为存储输出文件的文件名腾出空间。
现在我们打开while循环。这里我使用了uint8_t,这意味着我们将迭代512字节块中的每个字节,直到文件结束。如果我们到达文件的末尾,并且一个字节不能再被读取,fread将返回0,while循环将退出。所以现在我们有了buffer,它是一个大小为512的数组,由512个8位元素组成。
现在,我们检查缓冲区的第一个、第二个、第三个和第四个元素是否与JPEG标头的序列匹配。如果是,我们使用sprintf将该文件的名称存储在filename指向的内存中。
由于我们已经开始阅读JPEG,我们现在将空指针output-file分配给一个新文件,我们使用filename中存储的字符串打开该文件。我的问题是...fopen是否创建新文件
然后我们增加计数器。这样,我们打印的图像从0到49,而不是0到50,如果我们要在sprintf之前计数图像。
然后,由于我们已经分配了指针,它不再是null,我们进入下一个if语句,并将缓冲区中存储的任何内容写入输出文件。
现在我们检查下一个512字节块。如果它没有以JPEG头开始,那么我们继续将其写入同一个输出文件,因为这意味着它是第一个图像的延续。
当我们找到第二个JPEG标头时,sprintf将“1”存储在filename所指向的地址处。然后我们以写模式打开一个新文件,新文件名为“1”。然后在递增计数器之后,我们现在开始写入新文件,因为指针现在指向新文件。
然后我们重复相同的过程,直到文件结束,创建50个文件,每个文件由一个JPEG图像组成,命名为0.jpg到49.jpg。(问题中提到,总共有50张图片)
运行这段代码似乎产生了一个内存泄漏….是因为我没有在打开下一个输出文件之前关闭每个输出文件吗?

z18hc3ub

z18hc3ub1#

1.是的,如果fopen(filename,"w")不存在,则fopen(filename,"w")创建filename,如果存在,则将其截断为0字节(参见man page)。
1.你说得对。在打开一个新文件之前不关闭output_file是一个bug,会导致内存泄漏。
1.这一行是错误的:char* filename = malloc(sizeof(char));。它只分配一个字节,但你至少需要8个字节,包括'\0'(假设你最多找到999张图像)

相关问题