2011-04-05 47 views
1

謝謝大家,至今爲止您的意見和建議!C中的文件讀取,隨機錯誤

此外:

經過測試和進一步玩弄,它似乎的FileReader各個呼叫成功。但多次調用FileReader(這些可能是FileReader的單獨版本)會導致問題發生。

末添加

你好,

我有一個非常不尋常的問題[請仔細閱讀本:這一點很重要(代碼:: Blocks的編譯器,Windows Vista家庭)沒有複製代碼]與C文件讀取功能(fread,fgetc)。現在,通常,文件讀取功能將數據正確地加載到自分配和自釋放字符串(並且不是字符串的問題),但這是奇怪的地方(並且量子物理所適用的地方):

錯誤捕獲語句報告EOF發生得太早(IE正在加載的文本文件的開始處的註釋部分)。打印字符串[加載後]報告確實太短(24個字符)(但它有足夠的空間來適應它[〜400],並且沒有分配問題)。該龜etc循環迭代報告它的終止僅爲24(該文件是大約300個字符長)與EOF:這是不言而喻怪誕

暫檢查讀取 - > _基地報告的整個(〜300)個字符被加載 - 在24沒有EOF。困惑,[因爲它是一個fgetc循環]我添加了一個printf來顯示每個字符[作爲%d,所以我可以在每一步發現-1 EOF],所以我可以看到它在做什麼,並對其進行了修改,使其成爲單個字符。它循環很好,達到了300分而不是24分 - 但是隨後會隨機凍結。但是,當我刪除printf時,它又終止於24,並被錯誤捕獲的語句所捕獲。

摘要: 所以,基本上我有一個由「觀察者效應」了量子物理學的影響了一個錯誤:當我嘗試觀察字符我通過的printf從龜etc獲得,這個問題(早期EOF終止於24)消失,但是當我停止查看時,錯誤捕獲聲明報告提前終止。

更奇怪的是,這不是第一次發生。 Fread有一個類似的問題,我無法弄清楚爲什麼,並用fgetc循環代替它。

[代碼不能真正提供,因爲代碼庫的大小是5個頭]。

段:

int X = 0; 
int C = 0; 
int I = 0; 

while(Copy.Array[X] != EOF) 
{ 
    //Copy.Array[X] = fgetc(Read); 
    C = fgetc(Read); 
    Copy.Array[X] = C; 
    printf("%d %c\n",C,C); //Remove/add this as necessary 
    if(C == EOF){break;} 
    X++; 
} 

側面說明:它分解成最簡單的格式不重現錯誤。

+6

當您嘗試調試問題時,或者它們只是間歇性地發生(稱爲相位問題)時,問題就會消失或發生變化,您稱之爲「量子物理效應」是常見的編程問題。有時他們會離開你犧牲工程神。所以你需要提供一些代碼,否則沒有人能夠幫助你。 – 2011-04-05 09:53:33

+3

(你爲什麼試圖把英語變成LISP?)這在任何情況下都是不常見的。通常有一個名字:這是一個[heisenbug](http://www.catb.org/jargon/html/H/heisenbug.html)。 – 2011-04-05 09:54:17

+0

從技術上講,你所描述的稱爲[Heisenbug](http://en.wikipedia.org/wiki/Unusual_software_bug#Heisenbug):) – GrahamS 2011-04-05 09:55:55

回答

0

您可能正在進行一些堆損壞。沒有看到代碼就不可能說。

+0

我將如何檢查? – SightS2 2011-04-05 10:04:49

+0

你還有關於堆腐敗的更多信息嗎?如果我造成這種情況,我肯定會在將來避免它。 – SightS2 2011-04-05 10:06:18

+0

你必須檢查一切!用斷言填充你的代碼,比如聲明你沒有寫入NULL指針,你沒有寫太多的數據到緩衝區等等。 – James 2011-04-05 19:56:29

5

這是書中最古老的錯誤之一。

由於EOF常數不適合,所以不能使用char類型的變量來讀取字符(!)。

您需要:

int C; 

此外,while條件看上去很恐怖,你是在循環遞增X,然後檢查(新)的位置,這是正確的初始化?在開始循環之前,您不會顯示如何設置Copy.Array

我建議完全刪除它,這是非常奇怪的代碼。

事實上,我不明白你爲什麼要循環讀取單個字符,爲什麼不使用fread()來讀取你需要的?

+0

令人驚訝的是它的工作原理。 Char在此編譯器上被視爲已簽名(-127至127)。但是,char C(它是一個int C)純粹用於觀察 - 將其更改爲int仍然意味着存在錯誤。 – SightS2 2011-04-05 10:15:02

+0

@ SightS2:好的,所以有更多的錯誤。但是你必須改變它,因爲(很明顯)EOF符號和所有8位字節值都不能用8位字符表示,所以肯定會有碰撞,這是一個非常壞的消息。 – unwind 2011-04-05 11:02:48

1

首先,unwind的答案是一個有效的點,儘管我不確定它是否解釋了您所看到的問題。

其次,

printf("%d %c\n",C,C); //Remove/add this as necessary 

可能是一個問題。 %d%c格式說明符預期int是參數,您只傳遞一個char。取決於你的編譯器,這可能意味着它們太小了。


這是我認爲這個問題是:

你是如何分配Copy.Array?在開始之前,你確定所有元素都已清零嗎?如果你malloc它(malloc只是留下任何垃圾在內存中它返回),並且一個元素恰好包含0xFF,你的循環會過早退出,因爲你的while條件測試Copy.Array [X]之前,你已經放置了一個字符位置。

這是爲數不多的情況下,我讓自己放在一個條件的分配之一,因爲該模式

int c; 
while ((c = fgetc(fileStream)) != EOF) 
{ 
    doSomethingWithC(c); 
} 

是非常常見的


編輯

剛閱讀你的「額外」評論。我認爲你很可能超出你的輸出緩衝區。我想你應該改變你的代碼是這樣的:

int X = 0; int C = 0; int I = 0; 
    while(X < arraySize && (C = fgetc(Read)) != EOF) 
    { 
     Copy.Array[X] = C; 
     printf("%d %c\n", (int)C, (int)C); 
     X++; 
    } 
    printf("\n"); 

注意,我假設你有一個名爲arraySize變量被設置爲可以寫入陣列沒有超越它的字符數。還請注意,我不寫你的陣列的EOF。

+0

+1用於提示一個更理想的循環條件。 – GrahamS 2011-04-05 10:44:55

+0

謝謝。 Copy.Array使用malloc。然而,我認爲,上面的例子中沒有使用Copy.Array(我使用int C來測試它沒有Copy.Array) - 並且ergo不能出錯。出於某種原因,Printf本身不知怎麼......改變了這一點,但我並沒有把握如何或爲什麼。 – SightS2 2011-04-05 10:46:36

+0

@ SightS2:在您的示例中使用了Copy.Array **。查看while關鍵字後的代碼位。你的循環條件是錯誤的。另請參閱我對printf的評論。 – JeremyP 2011-04-05 10:51:41

0

不知道這是你的錯誤,但這樣的代碼:

C = fgetc(Read); 
Copy.Array[X] = C; 
if(C == EOF){break;} 

意味着你加入EOF值到您的陣列 - 我敢肯定你不想這樣做,尤其是你的陣列大概是charEOFint,所以你實際上最終會得到一些其他值(這可能會導致後來的循環等)。

相反,我建議你換個順序,以便C僅把數組中,一旦你知道它是不是EOF

C = fgetc(Read); 
if(C == EOF){break;} 
Copy.Array[X] = C; 
+0

使用EOF以便函數可以搜索它並用NULL替換它。默認情況下,NULL被添加到讀取字符數量的末尾,但對於所有意圖,數據被視爲字符串/文件流混合。 – SightS2 2011-04-05 10:51:30

+0

@ SightS2:如果'Array'是一個'char'數組,那麼通過它搜索'EOF'將永遠不會成功 - 並且您的循環條件也不會成功 - 因爲'EOF'是一個'char'範圍之外的int常量正如@unwind正確地說的那樣。 – GrahamS 2011-04-05 10:58:53

0

雖然這不是我稱之爲一個「完整」的答案(因爲bug仍然存在),這確實解決了「觀察者效應」元素:我發現,出於某種原因,printf以某種方式「固定」了代碼,並且使用std :: cout似乎(好吧,我不能說'修復'問題)阻止了觀察者效應的發生。也就是說,使用std :: cout而不是printf(因爲printf是觀察者效果的起源)。

在我看來,printf在較低級別的內存中執行某些操作,似乎部分地糾正了確實似乎是內存分配錯誤的內容。