C缓冲区内存分配

4

我对C语言还很陌生,请谅解我的无知。我想将一个完整的可执行文件读入缓冲区:

#include <stdlib.h>
FILE *file = fopen(argv[1], "rb");
long lSize;

fseek(file, 0, SEEK_END);
lSize = ftell(file);
fseek(file, 0, SEEK_SET);

char *buffer = (char*) malloc(sizeof(char)*lSize);
fread(buffer, 1, lSize, file);

该文件大小为6144字节(存储在lSize中),但我的缓冲区大小仅为4字节,因此缓冲区中只存储了MZ签名。
为什么在这种情况下malloc只分配4个字节?
编辑:可能是PE文件的MZ头中的第一个0终止了char缓冲区。然而,如果我将缓冲区设置为特定值,整个文件将被存储。如果我将缓冲区设置为int(= 4字节),则缓冲区不会被终止,但当然会更大(比char = 1字节大)。我只想逐字节地复制文件以及空字节。
编辑2:缓冲区当然包含了所有应该包含的内容,但如果我尝试使用fwrite将其写入新文件,则只写入了前四个\ 0(即4个字节)。我只是fwrite用错了。已修正此问题。对不起,问题描述不够清晰。

你认为为什么malloc只分配4个字节? - Kiril Kirov
1
你怎么知道它只分配了4个字节(它不应该只分配4个字节,而且我在你的代码中没有看到任何错误)。你是如何确定只读取/存储了4个字节的? - Mat
你不必使用sizeof来了解char的大小。在C中,"char"和"byte"是同义词,sizeof(char)始终为1。 - tiftik
按照定义,sizeof(char) == 1。如果缓冲区仅包含4个字节,则是因为lSize == 4。 - David Heffernan
1
代码看起来正确。你是否在调试器中以空终止字符串的形式查看缓冲区的内容,并且只看到了4个字节,因为第五个字节是空字节?在调用fread之前和之后尝试在内存窗口中检查缓冲区的内容。 - Dabbler
3个回答

8
如果 lSize 确实等于 6144,那么你的代码确实会分配 6144 字节并读取整个文件的内容。如果你认为只有 4 个字节被读取了,那可能是因为第 5 个字节是零。因此,当缓冲区被解释为以零结尾的字符串时,它在那一点处终止。
你可以通过查看 buffer[4]buffer[5] 等来检查缓冲区的其余部分。
另外,你不需要将 malloc 的返回值强制转换,而且 sizeof(char) == 1 是定义好的。最佳实践是像这样编写 malloc
char *buffer = malloc(lSize);

但这不会改变你的结果。

我认为你可能是正确的。DOS头是\MZ220,因此已终止。但是,如果我手动将缓冲区设置为一个较大的数字,例如buffer[16000],则无论0的数量如何,缓冲区都将包含整个文件。 - Laughingman
我敢打赌你在调试器中把缓冲区看作是以空字符结尾的字符串。使用printf会在0处停止。如果只分配了4个字节,那么可能会在fread上引发段错误。运行一个for循环并逐个字符打印缓冲区,“printf("%c\n", buffer[i]);” - David Heffernan
我不理解你的编辑。你现有的代码将整个文件读入缓冲区中。它已经在那里了。但是你不能将其视为以空字符结尾的字符串。 - David Heffernan

3
为什么在这种情况下malloc只分配4个字节?
因为您忘记了#include (和对malloc()的返回值进行转换)。
不要忘记#include ,以便编译器知道malloc返回一个void*类型的值(而不是假定它返回int类型),并且需要一个size_t类型的参数(而不是假定它是int类型)
另外,请不要转换malloc的返回值。void*类型的值可以赋给任何类型的指针对象。转换返回值会使编译器静默地将int(在未包含时假定)转换为强制类型转换中的类型。请注意,如果没有转换,编译器会抱怨,让您知道您已经忘记了包括。
真正的错误不是malloc分配错误的数量(我认为它将分配正确的数量)。真正的错误是假设malloc返回int,而不是void*。int和void*可以以不同的方式传递(例如寄存器和堆栈),或者它们具有不同的表示形式(int的补码和void*的分段地址),或者其他任何事情(最可能的是sizeof(int)!= sizeof(void*))。

3
哦?你确定吗? - Kiril Kirov
3
将malloc的返回值强制转换后赋值给变量是不好的实践,但是这算错误吗?我怀疑这一点,因为我曾经这样做了无数次(我的背景是C++,在那里它不会被隐式转换)。 - Christian Rau
1
为什么类型转换会成为一个问题? - akappa
6
我理解你抓住这个机会来谈一下 malloc() 函数返回结果的类型转换,但是如果这是问题的根源,则错误在于没有包含 stdlib.h 头文件,而类型转换只是隐藏了一个有用的警告。编辑后:阅读其他评论后,你看到了吗?以这种方式表达会让人困惑。 - Pascal Cuoq
根据注释,真正的错误是未包含正确的头文件。将返回值强制转换是一种使编译器默默接受错误的方法。 - pmg
显示剩余2条评论

1

你是如何检查缓冲区大小的?是使用 sizeof(buffer) 吗?如果是这样,那么你只能看到一个 指向int的指针 的大小,它是4个字节。你无法从指针中获取缓冲区的大小。你必须像你所做的那样将其单独存储(在 lSize 中)。

如果 malloc() 没有返回 NULL,那么你的缓冲区就没问题,大小也是正确的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接