2012-02-22 21 views
2

我在VS2010 Windows 7中编写C++。我尝试读取大小为64字节的文件。下面的代码:新的和malloc分配额外的16个字节

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,但是当我分配内存为它与新的字节[lSize所]我得到80个字节的空间,从而奇怪的序列ээээ«««««在缓冲区的末尾添加«««系统。你能告诉我如何处理这个问题吗?

+3

你是如何打印出来?如果它是一个C字符串,则需要NULL结束。 – Mysticial 2012-02-22 07:51:44

+0

在result = fread(buffer,1,lSize,f)后插入'int buffSize = ftell(buffer)';'告诉我buffSize的值。另外为什么你混合使用c(fseek,ftell等)和C++(new)?你为什么不坚持这个或那个? – Alexander 2012-02-22 07:56:45

+2

@Mysticial:空终止,而不是空终止('NULL'是一个空指针常量)。 – 2012-02-22 08:07:18

回答

4

有您已经分配的字节数,而你看到的字节数之间的一个重要区别。

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

但是,那不是你的问题。问题是你使用fread从文件读取64个字节。 fread没有办法知道你正在阅读什么样的数据。它可能是一个结构,一个char缓冲区,一组双打......它只是为你读取这些字节。

这意味着如果文件中包含字符“ABC”,则会返回完全“ABC”。但是,在C中,字符串应该是零终止的,所以如果您将此缓冲区传递给printf,它将继续扫描内存直到找到一个空字符。

所以,解决你的问题,分配1个字节以上,并在最后一个字节设置为空字符,像这样:

buffer = new BYTE[lSize+1]; 
buffer[lSize] = '\0'; 
+0

+1我明白你的意思了。稍后在一些随机存储器中,他依靠存在'\ 0'。如果没有他会得到一个巴士错误试图打印它。 – 2012-02-22 08:08:41

+0

它工作。但是,你能告诉我正确的方式来读/写数据到/从文件中的c + +? – forik 2012-02-22 08:55:11

+1

使用std:ifstream和std :: ofstream。有关介绍和示例,请参阅http://www.cplusplus.com/reference/iostream/。 – Patrick 2012-02-22 09:16:32

1

当分配内存时,它不是以每个字节为基础。相反,它被分配在8或16字节的对齐块中(可能在指针前面有一个头部的头部)。这通常不是一个问题,除非你创造了很多(数百万)小物件。这在C中并不是一个问题,甚至不是Java中的主要问题(它不支持在堆栈中分配对象或对象的数组)。

+1

正确,但与此问题无关。 – Patrick 2012-02-22 07:59:12

+0

有两种解决方案;不用担心,您不需要知道使用了更多的空间(16个字节或临时空间在任何PC上微不足道),或者在没有此问题的堆栈上分配。 – 2012-02-22 08:06:29

+0

@帕特里克我明白你的观点。 – 2012-02-22 08:08:55

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'; 

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

+0

新的伪造之后进行NULL检查。 operator new抛出异常,并且如果内存分配失败,将不返回null。 – Ajay 2012-02-22 08:28:35

+0

@Ajay:我只是复制了他的代码并修复了这个问题,同时,某些编译器/ CRT impl's *会*返回NULL并抛出一个异常:http://msdn.microsoft.com/en-us/library /kftdy56f(v=vs.71).aspx – Necrolis 2012-02-22 08:35:50