我试图编写一个简单的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 %in", 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:好的,伙计们,没关系。这个版本应该可以在任何其他不是我的计算机上工作。我认为问题出在传递参数时我的终端,但我刚刚切换了操作系统并且它可以工作。
- 请检查
fopen()
和calloc()
是否成功。 - 打印
long
的格式说明符是%ld
,而不是%lu
。 (int)file[i]
对数组索引不利,因为如果所有可以表示为char
的值都可以在int
中表示,则char
转换为int
将保留其值,并且因为如果char
在您的环境(和设置)中签名,它可能会访问负索引,导致超出范围的访问并调用未定义的行为。
应将++bytesCount[(int)file[i]];
更改为++bytesCount[(unsigned char)file[i]];
以防止使用负索引。
另请注意,二进制流(N1570 7.21.9.2 fseek 函数)可能支持带SEEK_END
的ftell()
,因此最好使用fgetc()
逐个读取,以避免未定义的行为并使用更少的内存。
MikeCAT 只是打败了我。 接下来还有更多的解释,以防有帮助。
解决方法:将file
更改为unsigned char *file
,并将增量更改为++bytesCount[file[i]];
。
解释:根据这个答案,一个普通的char
可能是signed
或unsigned
。 在这种情况下,我猜它默认为signed
. 这意味着任何值>=0x80
都将成为负数。 这些值不太可能出现在您的英语文本文件中,但很可能在图像中! 要(int)
的类型转换将保持负数为负数。 因此,代码将使用负数索引byteCounts
,从而导致分段错误。
可能是由此行引起的
++bytesCount[(int)file[i]];
bytesCount
是 256 个整数的数组。如果file[i]
大于 256,则您正在访问无效内存,这可能会导致分段错误。