【问题标题】:Segmentation Fault 11 when trying to read an image byte per byte尝试按字节读取图像字节时出现分段错误 11
【发布时间】:2016-06-17 15:33:13
【问题描述】:

我正在尝试编写一个简单的 C 代码来计算一个字节在文件中重复的次数。我们尝试了带有 .txt 文件的代码并创造了奇迹(测试的最大大小:137MB)。但是当我们用一张图片(甚至很小,2KB)尝试它时,它返回了 Segmentation Fault 11

我做了一些研究,发现了一些特定的图像库,但我不想求助于它们,因为它不仅适用于图像,而且适用于几乎任何类型的文件。有没有一种方法可以简单地读取每个字节的文件字节,而不管其他任何内容(扩展、元等)。

这是代码:

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

int main(int argc, char **argv) {

    FILE *f;
    char *file;
    long numTotalBytes = 0;
    int bytesCount[256] = {0}; 

    f = fopen ( argv[1], "rb");
    fseek(f, 0L, SEEK_END);
    numTotalBytes = ftell(f);
    rewind(f);

    file = calloc(1, numTotalBytes);    
    fread(file, numTotalBytes, 1, f);
    fclose(f);

        printf("numTotalBytes: %ld", numTotalBytes); //<- this gives the right output even for images

    unsigned int i;
    for (i=0; i<numTotalBytes; ++i) {
        unsigned char pointer = file[i]; //<- This access fails at file[1099]
        int pointer_int = (int)pointer;
        printf("iteration %i with pointer at %i\n", i, pointer_int); //<- pointer_int is never below 0 or above 255
        //++bytesCount[(int)file[i]];
        ++bytesCount[pointer_int];
    }

    free(file);
}

一些额外的信息:
- 将 img 的扩展名更改为 .txt 不起作用。
- 代码在迭代 1099 时准确返回分段错误(我使用的文件是 aprox 163KB,因此文件 [i] 应该接受对 aprox 文件 [163000] 的访问)。
- 对于 txt 文件,效果很好。无论文件大小如何,逐个读取字节并按预期计数。
- 我在 Mac 上(你永远不知道...)

//编辑:我已经编辑了代码以获得更简洁和解释性的代码,因为你们中的一些人告诉我我已经尝试过的事情。

//EDIT_2:好吧,伙计们,没关系。这个版本应该在它不是我的任何其他计算机上工作。我认为问题出在我的终端传递参数时,但我只是切换了操作系统并且它可以工作。

【问题讨论】:

标签: c image file segmentation-fault fopen


【解决方案1】:
  • 请检查fopen()calloc() 是否成功。
  • 打印long 的格式说明符是%ld,而不是%lu
  • (int)file[i] 对数组索引不利,因为如果所有可以表示为 char 的值都可以在 int 中表示,并且因为如果在您的环境中签名了 char,则将 char 转换为 int 将保留其值(和设置),它可能会访问负索引,导致超出范围的访问并调用未定义的行为

您应该将++bytesCount[(int)file[i]]; 更改为++bytesCount[(unsigned char)file[i]]; 以防止使用负索引。

还要注意ftell()SEEK_END可能支持二进制流(N1570 7.21.9.2 fseek函数),所以最好使用fgetc()逐一读取,以便避免undefined behavior 并使用更少的内存。

【讨论】:

  • - 原始代码已经检查了 fopen 和 calloc,我只是在这里放了一个较小的版本。 - 将 %lu 更改为 %ld(谢谢!)。 - 对 bytesCount 的访问效果很好,我做了很多调试,将代码行分成两部分,有很多打印,强制转换为 int、unsigned int、unsigned char 等。如果我不使用它们有时会打印负数未签名(如预期的那样),但无论如何访问都很好。这是对文件 [i] 的访问,导致分段错误。另一个从不访问低于 0 或超过 255 的任何内容。如果有帮助,我可能会放上去光的代码。
【解决方案2】:

MikeCAT 刚刚击败了我。如果有帮助,下面再做一点解释。

修复:将file 更改为unsigned char *file,并将增量更改为++bytesCount[file[i]];

解释:根据this answer,普通的char 可能是signedunsigned。在这种情况下,我猜它默认为signed。这意味着任何值&gt;=0x80 都将变为负数。这些值不太可能出现在您的英语文本文件中,但很可能出现在图像中!对(int) 的类型转换将保持否定否定。因此,代码会将byteCounts索引为负数,导致分段错误。

【讨论】:

  • 0x80 也可以转换为负数。
  • 编辑了原始帖子以获得更好的解释。它不是 bytesCount[index] 失败,而是文件 [index] 访问导致分段错误。
【解决方案3】:

可能是这条线造成的

++bytesCount[(int)file[i]];

bytesCount 是 256 个整数的数组。如果file[i] 大于 256,则您正在访问无效内存,这可能会导致分段错误。

【讨论】:

  • 编辑了原始帖子以获得更好的解释。它不是 bytesCount[index] 失败,而是文件 [index] 访问导致分段错误。
猜你喜欢
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2019-12-05
相关资源
最近更新 更多