【问题标题】:Looping through end of data file循环遍历数据文件的末尾
【发布时间】:2016-04-23 15:16:20
【问题描述】:

我一直在为哈佛 CS50 课程解决问题集,我们的任务是从存储卡中恢复 jpeg。该卡按顺序存储 jpg。在编写我的程序时,我决定使用 while 循环来保持循环直到 EOF,但是使用课程中包含的调试器,我发现我的循环永远不会启动。我在下面包含了我的代码,我真的希望有人可以帮助我了解我在循环中出错的地方。

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

int main(int argc, char* argv[])
{
    // Ensure proper Usage
    if (argc != 1)
    {
        printf("This file takes no input commands!\n");
        return 1;
    }

    // open up card data file
    FILE* dataFile = fopen("card.raw", "r");
    if (dataFile == NULL) 
    {
        char* invalidFile = "card.raw";
        printf("Could not open %s.\n", invalidFile);
        return 2;
    }

    // Create variable to keep track of num of output files written
    int numFiles = 0;

    // Create buffer
    int* buffer = (int*)malloc(sizeof(int*) * 512);

    // Create new file conditions
    bool a = buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff;
    bool b = buffer[3] == 0xe0 || buffer[3] == 0xe1|| buffer[3] == 0xe2 || 
             buffer[3] == 0xe3 || buffer[3] == 0xe4 || buffer[3] == 0xe5 || 
             buffer[3] == 0xe6 || buffer[3] == 0xe7 || buffer[3] == 0xe8 || 
             buffer[3] == 0xe9 || buffer[3] == 0xea || buffer[3] == 0xeb || 
             buffer[3] == 0xec || buffer[3] == 0xed || buffer[3] == 0xee || 
             buffer[3] == 0xef;

    // Loop through until all files found         
    while(fread(&buffer, 512, 1, dataFile) == 1)
    {
        if(a && b)
        {
            // Create temporary storage
            char title[999];
            // print new file name
            sprintf(title, "%d.jpg", numFiles);
            // open new file
            FILE* img = fopen(&title[numFiles], "a");
            numFiles = numFiles + 1;
            fwrite(&buffer, sizeof(buffer), 1, img);
            free(buffer);
        }
        else 
        {
            if(numFiles > 0) 
            {

            }
        }
    } 
}

【问题讨论】:

  • 如果您阅读fread 的手册页,您会注意到它的返回值是已读取的字节数。这就是你的问题之一。让我将另一个改写为:为什么你认为一旦你开始循环,ab 将有任何其他值,而不是你在循环之前分配给它们的值.
  • 聪明的你! C 不是解释器,因此 bool a = ... 被评估一次然后使用。但是您希望每次都对其进行评估。然后你在一个带有随机值的缓冲区上评估它!回去学习你的课程材料。
  • @Mathstudent "fread(&buffer, 512, 1, dataFile)" 的返回值是什么?
  • 嘿,感谢 cmets!我的理解是 fread 每次循环都会返回 1,这与 nmemb(3rd entry) 相同。我的文件头条件是我刚刚添加的,我将把它改回原来的方式。

标签: c while-loop cs50


【解决方案1】:

好吧,你可能有不止一个误解。

首先看一下fread手册页

成功时,fread()fwrite() 返回读取或写入的 items 数量。

因此,如果您请求 512 个字节,您应该期望它返回 512。 如果它返回较少,你知道:要么你到达了文件的末尾,要么出了点问题。

如果你指定:

bool a = something;
bool b = somethingElse;

然后:

while(somethingEntirelyElse) {
    // Never update the value of a or b
    if(a && b) { ... }
    // Neither here ...
}

那么你可以称那张支票冗余不是吗?

除非ab 实际上是易失的。但是不要去那里!

在您的情况下,ab 的分配很可能属于while 循环内。

然后你 alloc 你的buffer 一次在循环之外,但每次你实际写下它时释放它。在下一次迭代中,您遇到分段错误

您是否考虑过如果任何图像文件的大小不是 512 字节,并且图像没有正确对齐会发生什么?

更好的方法是保存一个文件的开头位置,一旦遇到 EOF(您并不是真的在寻找...),您就会知道文件的确切大小,以及有多大你的缓冲区必须是。


最后我同意一些评论者的观点,你真的应该看看一些早期的作业,看看你是否可以从中学到一些东西。


类比时间:

假设您有一本书,并且您想要复制上面有图片的每一页。 你告诉自己:哦,我只是遵循一个简单的算法,所以我可以考虑其他事情。

您的算法是:

  • 有复印机

  • 有一个笔记本,您可以在上面记录页面是否包含图像。

  • 看一下(截至目前尚未关闭的书),看看是否有图像。 -> 在笔记本上写下结果

  • 只要下一页页面上正好有一个字母,就开始翻页。 (不多不少)-> 大多数情况下你会立即停止

  • 如果笔记本说:有图片,复制此页(注意,笔记本会说出你第一次在上面写的内容)

  • 如果您只是复制了一张图片,请扔掉您的复印机(不要为下一张图片购买新的)

【讨论】:

  • 谢谢。你的回答很清楚。这对我帮助很大。
【解决方案2】:

在调用malloc 之后,buffer 指向分配的内存(希望;您应该检查buffer != null),但该内存的内容是未定义的。尽管如此,你使用它并将其与0xFF 进行比较,这毫无意义。您首先必须从文件中读取数据。

文件通常由字节组成,而不是整数,因此您的缓冲区应该是unsigned char * 类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 2021-12-26
    相关资源
    最近更新 更多