我在VS2010 Windows 7中编写c ++。我尝试读取大小为64字节的文件。这是代码:
BYTE* MyReadFile(FILE *f)
{
size_t result;
BYTE *buffer;
long lSize;
if (f == NULL)
{
fputs ("File error", stderr);
exit (1);
}
fseek (f, 0, SEEK_END);
lSize = ftell (f);
rewind (f);
//buffer = (BYTE*) malloc (sizeof(char)*lSize);
buffer = new BYTE[lSize];
if (buffer == NULL)
{
fputs ("Memory error", stderr);
exit (2);
}
result = fread (buffer, 1, lSize, f);
if (result != lSize)
{
fputs ("Reading error",stderr);
exit (3);
}
fclose (f);
return buffer;
}
当我得到文件大小时它是64,但是当我用新的BYTE [lSize]为它分配内存时,我得到80个字节的空间,因此奇怪的序列ээээ««««««««оюою被添加到缓冲区的末尾。你能告诉我怎么办吗?
答案 0 :(得分:4)
背后的内容称为sentinel。它用于检查您的代码是否超出已分配内存的边界。当您的程序覆盖此值时,CRT库将在您释放缓冲区时报告调试消息。
请看这里:http://msdn.microsoft.com/en-us/library/ms220938%28v=vs.80%29.aspx
答案 1 :(得分:4)
您分配的字节数与您看到的字节数之间存在重要差异。
如果lsize为64,那么你确实为自己分配了64个字节。这并不意味着在屏幕后面C ++运行时将向Windows提出正好64个字节。在实践中,记忆管理员要求稍微多一点的记忆,这样他们就可以做自己的功课。通常这些额外的字节是在从new / malloc返回的指针之前分配的,所以你永远不会看到它们。
然而,这不是你的问题。问题是您使用fread从文件中读取64个字节。 fread无法知道您正在阅读的数据类型。它可以是一个struct,一个char缓冲区,一组double,......它只是为你读取这些字节。
这意味着如果文件包含字符“ABC”,您将获得完全“ABC”。但是,在C中,字符串应该以空字符结尾,因此如果将此缓冲区传递给printf,它将继续扫描内存,直到找到一个空字符。
因此,要解决您的问题,请再分配1个字节,并将最后一个字节设置为nul字符,如下所示:
buffer = new BYTE[lSize+1];
buffer[lSize] = '\0';
答案 2 :(得分:3)
虽然这可能看起来像是一个内存问题,但它实际上是一个打印问题(正如@Mystical指出的那样)。如果要将任何内容打印为字符串,则需要设置空终止,否则在遇到一个内存(即UB)之前,内存将会被大量读取。
请改为尝试:
buffer = new BYTE[lSize + 1];
if (buffer == NULL)
{
fputs ("Memory error", stderr);
exit (2);
}
result = fread (buffer, 1, lSize, f);
if (result != lSize)
{
fputs ("Reading error",stderr);
exit (3);
}
buffer[lSize] = '\0';
它将确保在返回的缓冲区末尾有一个空终止符。
答案 3 :(得分:1)
分配内存时,不是基于每个字节。相反,它被分配在8或16字节的对齐块中(可能在开始时,在指针之前有一个头)。除非您创建大量(数百万)小对象,否则这通常不是问题。这不一定是C中的问题,甚至不是Java中的主要问题(它不支持在堆栈上分配的对象或对象的数组)。