C 尝试每字节读取一个图像字节时出现分段故障11

C 尝试每字节读取一个图像字节时出现分段故障11,c,image,file,segmentation-fault,fopen,C,Image,File,Segmentation Fault,Fopen,我想写一个简单的C代码,计算一个字节在文件中重复的次数。我们用.txt文件尝试了这段代码,并创造了奇迹(测试的最大大小:137MB)。但是当我们用一个图像(即使很小,2KB)尝试它时,它返回了分割错误11 我做了一些研究,发现了一些特定的图像库,但我不想求助于它们,因为代码不仅适用于图像,而且适用于几乎任何类型的文件。是否有一种方法可以简单地读取每个字节的文件字节,而不考虑任何其他内容(扩展名、元等) 代码如下: #include <stdio.h> #include <std

我想写一个简单的C代码,计算一个字节在文件中重复的次数。我们用.txt文件尝试了这段代码,并创造了奇迹(测试的最大大小:137MB)。但是当我们用一个图像(即使很小,2KB)尝试它时,它返回了分割错误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);
}
#包括
#包括
int main(int argc,字符**argv){
文件*f;
字符*文件;
长numTotalBytes=0;
int字节计数[256]={0};
f=fopen(argv[1],“rb”);
fseek(f,0L,SEEK_END);
numTotalBytes=ftell(f);
倒带(f);
file=calloc(1,numTotalBytes);
fread(文件,numTotalBytes,1,f);
fclose(f);
printf(“numTotalBytes:%ld”,numTotalBytes);//
  • 务必检查
    fopen()
    calloc()
    是否成功
  • 要打印
    long
    的格式说明符是
    %ld
    ,而不是
    %lu
  • (int)文件[i]
    对数组索引不好,因为如果所有可以表示为
    char
    的值都可以在
    int
    中表示,那么将
    char
    转换为
    int
    将保留其值,并且因为如果
    char
    在您的环境中签名(和设置),它可能访问负索引,导致超出范围的访问,并调用未定义的行为
您应该将
++bytescont[(int)文件[i]];
更改为
++bytescont[(无符号字符)文件[i]];
,以防止使用负索引


还要注意的是,二进制流(7.21.9.2 fseek函数)可能支持
ftell()
SEEK\END
,因此最好使用
fgetc()
逐个读取,以避免和使用更少的内存。

这可能是由这一行引起的

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

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

MikeCAT只是抢先一步。如果有帮助,下面会有更多的解释

要修复:将
文件更改为
无符号字符*文件
,并将增量更改为
++bytescout[file[i]];


示例:根据,普通的
char
可能是
有符号的
无符号的
。在这种情况下,我猜它默认为
有符号的
。这意味着任何值
=0x80
都将变成负数。这些值不太可能出现在英语文本文件中,但很可能出现在图像中!转换为
(int)
的类型将保留负数。因此,代码将索引
字节计数
为负数,从而导致分段错误。

扩展名实际上没有任何意义…尝试将
(int)
更改为
(未签名)
。您不需要负索引。
fseek()
ftell()
不是计算文件大小的好方法。您将
long
int
混合用于字节计数和循环,而
calloc
fread
使用type
size\u t
。最好使用
long
,因为这是
ftell
返回的结果。重新编辑时,您仍然有
char*file;
which应该是
未签名的char*文件;
-原始代码已经检查了fopen和calloc,我只是在这里放了一个较小的版本。-将%lu更改为%ld(谢谢!)-访问ByteCount很好,我做了很多调试,将代码行一分为二,有很多打印、强制转换为int、unsigned int、unsigned char等。如果我不使用unsigned(如预期的那样),它们有时会打印负数,但访问还是很好。这是对文件[I]的访问导致分段错误的一个。另一个从不访问低于0或超过255的任何内容。如果有帮助,我可以将脱胶代码放入。
0x80
也可能转换为负数。编辑原始帖子以获得更好的解释。失败的不是字节数[index],而是文件[index]访问导致分段错误。编辑原始帖子以获得更好的解释。失败的不是字节计数[index],而是文件[index]访问导致分段错误。