作者dirkc (raise(11))
看板C_and_CPP
標題Re: [問題] fscanf讀txt檔大量數值錯誤問題
時間Tue Mar 18 16:53:34 2014
原來的作法是:
int **data;
data
= (
int**)
new char [height
* sizeof(
int *)
+ width
* height
* sizeof(
int)];
for (i
= 0; i
< height; i
++)
data[i]
= (
int *)data
+ height
+ i
* width;
其中這一行 data[i]
= (
int *)data
+ height
+ i
* width;
在64位元的電腦應該會造成記憶體出問題,假設sizeof(int)是4而sizeof(int*)是8,
(int*)data+1和(int*)(data+1)是不一樣的。
前者加sizeof(int)後者加sizeof(int*) ,因為data是int**。
所以可以考慮改成:
data[i]
= (
int*)data
+ height
*(
sizeof(
int*)
/sizeof(
int))
+ i
* width;
另一種作法,利用sizeof(char)是一個byte:
ddata[i]
= (
int*)((
char*)(data
+ height)
+ i
* width
* sizeof(
int));
總而言之,記憶體爬格子是個需要小心的工作...
越來越多電腦買來的時候就是裝64位元的,所以這類的狀況應該滿容易碰到。
另外一件事就是,記憶體配置錯誤還是可能寫值進去,而且電腦沒報錯。
可能的原因包括測試的迴圈被最佳化忽略掉,或者剛好被覆寫的記憶體沒被使用等。
這些只是根據原PO提供的資訊所作的猜測,如果code原本已經是正確寫法,
或者確定coding的環境沒有這個問題,那可以直接忽略我這一篇。
--
謝謝uranusjr提供的highlighter
http://bbshighlighter.uranusjr.com/
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 111.249.181.204
推 yvb:若是64位元電腦,可能是發生資料錯亂,而不是堆積損毁程式掛掉; 03/18 18:37
→ yvb:反而是32位元電腦搭上double,造成後面資料讀超出配置範圍掛掉. 03/18 18:38
→ dirkc:不知道yvb說的堆積損和資料錯亂的差別?不過在我x64 linux上 03/18 21:36
→ dirkc:是segmentation fault,遞迴data[x]就會寫到錯誤位址了 03/18 21:38
→ dirkc:再deref就會seg fault 03/18 21:38
→ dirkc:雖然用debugger就可以,我還是寫了一個測試 03/18 22:08
→ dirkc:阿遞迴應該說迭代,錯誤中文用詞 03/18 22:29
推 yvb:抱歉, 一時沒想清楚, 以為64位元搭配int只是指標指的範圍太小, 03/19 12:44
→ yvb:在data內重疊, 可能重覆蓋寫資料, 造成資料錯亂而已; 沒考慮到 03/19 12:45
→ yvb:讀取資料時, 會蓋寫到 data[i], 而可能讓 data[i] 指向錯誤; 03/19 12:45
→ yvb:當然, 若運氣超好, 讀進 (&data[i]) 的資料值恰巧指向合法位址 03/19 12:45
→ yvb:也可能純粹搞亂資料而已, 而未造成 segfault. 03/19 12:46
→ yvb:相對32位元搭配double, 則是在設定 data[i] 指標時就超出範圍; 03/19 12:46
→ yvb:但如果在讀入 data 前又額外配置記憶體, 也可能後續的讀取只是 03/19 12:46
→ yvb:蓋寫後來配置區域的資料, 而不會發生 segfault. 03/19 12:47
→ yvb:至於堆積損毁, 其實是原PO附圖中的詞, 也就是heap corruption, 03/19 12:47
→ yvb:有幾種情況, 其中之一就是指標錯誤又去存取資料而發生的. 03/19 12:48