尝试读取每个字节的图像字节时的分段错误11

时间:2016-06-17 15:33:13

标签: c image file segmentation-fault fopen

我试图写一个简单的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完全返回Segmentation Fault(我正在使用的文件是aprox 163KB,因此file [i]应该接受访问aprox文件[163000])。
  - 对于txt文件工作完美。无论文件大小如何,都会逐个读取字节并按预期计算它们   - 我在Mac上(你永远不知道......)

//编辑:我已经编辑了一个更具说明性和解释性的代码,因为有些人告诉我我已经尝试过的事情。

// EDIT_2:好的,没关系。此版本应该适用于其不是我的任何其他计算机。我认为问题在于我的终端在传递参数时,但我刚刚切换操作系统并且它可以工作。

3 个答案:

答案 0 :(得分:4)

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

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

另请注意,ftell() SEEK_END可能会支持二进制流(N1570 7.21.9.2 fseek函数),因此最好逐个阅读fgetc()以避免undefined behavior并减少使用内存。

答案 1 :(得分:1)

MikeCAT只是打败了我。如果有帮助,可以进行更多解释。

要解决此问题:将file更改为unsigned char *file,将增量更改为++bytesCount[file[i]];

Exaplanation:根据this answer,普通char可能是signedunsigned。在这种情况下,我猜它默认为signed。这意味着任何值>=0x80都将成为负数。这些值不太可能出现在您的英文文本文件中,但很可能出现在图像中!对(int)的类型转换将使负面消极。因此,代码将使用负数对byteCounts进行索引,从而导致分段错误。

答案 2 :(得分:0)

可能是由此行引起的

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

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