2

我在 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,但是当我用 new BYTE[lSize] 为它分配内存时,我得到 80 个字节的空间,因此奇怪的序列ээээ««««««««оюою被添加到缓冲区的末尾。你能告诉我如何处理这个吗?

4

4 回答 4

4

后面和上面的称为哨兵。它用于检查您的代码是否超出分配内存的边界。当您的程序覆盖此值时,CRT库将在您释放缓冲区时报告调试消息。

看这里:http: //msdn.microsoft.com/en-us/library/ms220938%28v=vs.80%29.aspx

在此处输入图像描述

于 2012-02-22T07:57:18.053 回答
4

您分配的字节数与您看到的字节数之间存在重要差异。

如果 lsize 为 64,则您确实为自己分配了 64 个字节。这并不意味着在屏幕后面,C++ 运行时将向 Windows 请求正好 64 个字节。在实践中,内存管理器会要求更多的内存,以便他们能够自己做作业。通常这些额外的字节是在你从 new/malloc 返回的指针之前分配的,所以你永远不会看到它们。

然而,这不是你的问题。问题是您使用 fread 从文件中读取 64 个字节。fread 无法知道您正在阅读什么样的数据。它可能是一个结构、一个字符缓冲区、一组双精度数,......它只是为你读取这些字节。

这意味着如果文件包含字符“ABC”,您将得到准确的“ABC”。但是,在 C 中,字符串应该以空字符结尾,因此如果将此缓冲区传递给 printf,它将继续扫描内存,直到找到空字符。

因此,要解决您的问题,请多分配 1 个字节,并将最后一个字节设置为 nul 字符,如下所示:

buffer = new BYTE[lSize+1]; 
buffer[lSize] = '\0';
于 2012-02-22T07:58:42.267 回答
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';

它将确保在返回缓冲区的末尾有一个空终止符。

于 2012-02-22T07:57:06.697 回答
1

分配内存时,它不是基于每个字节的。相反,它被分配在 8 或 16 字节的对齐块中(可能在指针之前的开头带有标头)。除非您创建大量(数百万)小对象,否则这通常不是问题。这在 C 中不一定是问题,甚至在 Java 中也不是主要问题(它不支持在堆栈上分配的对象数组或对象)。

于 2012-02-22T07:52:43.430 回答