2012-02-22 74 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