我试图写一个简单的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:好的,没关系。此版本应该适用于其不是我的任何其他计算机。我认为问题在于我的终端在传递参数时,但我刚刚切换操作系统并且它可以工作。
答案 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
可能是signed
或unsigned
。在这种情况下,我猜它默认为signed
。这意味着任何值>=0x80
都将成为负数。这些值不太可能出现在您的英文文本文件中,但很可能出现在图像中!对(int)
的类型转换将使负面消极。因此,代码将使用负数对byteCounts
进行索引,从而导致分段错误。
答案 2 :(得分:0)
可能是由此行引起的
++bytesCount[(int)file[i]];
bytesCount
是256个int的数组。如果file[i]
大于256,则表示您正在访问无效内存,这可能会导致分段错误。