2013-12-18 18 views
2

我得到一個I/O 998錯誤,我的任務是重寫從文件到數組的數字,並找到最大值和最小值。我做錯了什麼?如何找到我的錯誤(delphi)

implementation 

var 
    f2: file of Real; 
    m: array of Real; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    f: Real; 
    max, min: Real; 
    i, j: Integer; 
begin 
    AssignFile(F2, 'test3.dat'); 
    Rewrite(f2); 

    for i := 1 to 50 do 
    begin 
    f := RandomRange(-100, 100); 
    Randomize; 
    Write(f2, f); 
    end; 

    CloseFile(f2); 

    i := 0; 

    Reset(f2); 

    while not Eof(f2) do 
    begin 
    SetLength(m, i); 
    Read(f2, m[i]); 
    Inc(i); 
    end; 

    CloseFile(f2); 

    max := m[1]; 
    min := m[1]; 

    for j := 1 to i do 
    if m[j] > max then 
     max := m[j] 
    else 
    if m[j] < min then 
     min := m[i]; 
+1

未發佈您的所有代碼。每次調用Randomise循環都會破壞你的隨機性。帕斯卡I/O?爲什麼?超出範圍數組訪問不能幫助。最小/最大循環上錯誤的索引也是一個壞消息。坦率地說,這段代碼是一場災難。 –

+0

您應該初始化i:= 1而不是i:= 0否則當您執行Setlength(m,i)時,您將始終擁有比您需要的數組小1的元素。 –

+0

[block read error]可能的重複(http://stackoverflow.com/questions/9493522/block-read-error) – Im0rtality

回答

2

很多錯誤,請參閱代碼中的註釋。

  • Randomize應該在程序啓動時調用一次。
  • 動態數組有開始索引爲0
  • CloseFile發佈的文件句柄
  • 定義循環前的動態數組的長度,否則你將得到的I/O錯誤。
  • High(m)將獲得動態數組的最大索引。
  • 分配最小值的索引變量是j。

implementation 

var 
    f2: file of Real; 
    m: array of Real; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    f: Real; 
    max, min: Real; 
    i, j: Integer; 
begin 
    AssignFile(F2, 'test3.dat'); 
    Rewrite(f2); 

    for i := 1 to 50 do 
    begin 
    f := RandomRange(-100, 100); 
    //Randomize; <-- Call this once at program start 
    Write(f2, f); 
    end; 

    //CloseFile(f2); <-- Don't close yet. 

    Reset(f2); 
    SetLength(m, 50); // <-- Define length of dynamic array 
    i := 0; 
    while not Eof(f2) do 
    begin 
    // SetLength(m, i); // <-- Moved to before while loop, or use SetLength(m,i+1); 
    Read(f2, m[i]); 
    Inc(i); 
    end; 

    CloseFile(f2); 

    max := m[0]; // <-- Dynamic arrays start with index 0 
    min := m[0]; // <-- Dynamic arrays start with index 0 

    for j := 1 to High(m) do // <- Max index 
    if m[j] > max then 
     max := m[j] 
    else 
    if m[j] < min then 
     min := m[j]; // <-- j is correct index variable 
+0

'CloseFile'不是一個錯誤,只是一個多餘的調用。 'CloseFile'釋放以前獲得的只寫句柄。如果沒有'CloseFile',後續的'Reset'在獲取讀寫句柄之前會做同樣的事情。 –

+0

@FreeConsulting,文檔說'CloseFile'終止文件變量和磁盤文件之間的關聯。此外:與F關聯的外部文件被完全更新,然後關閉,釋放文件句柄以供重用。因此,Reset()在內部關閉文件並交換爲讀寫模式的事實被認爲是實現細節,並且是最好的這裏的練習是按照文檔給出的規則來玩。 –

+0

然後,最正確的方法(以確保外部文件完全更新)將帶來['CloseFile'](http://www.freepascal.org/docs-html/rtl/system/close.html)回調而不是依賴於描述的「重置」行爲,對吧? –

2
i := 0; 

    Reset(f2); 

    while not Eof(f2) do 
    begin 
    SetLength(m, i); 
    Read(f2, m[i]); 
    Inc(i); 
    end; 

上述代碼設置一個動態數組的爲0(i)的長度,並試圖讀入它的不存在的元素。這會導致RTL將無效緩衝區傳遞給ReadFile api。操作系統返回'0'表示函數失敗,並將最後一個錯誤設置爲'998' - 這是ERROR_NOACCESS。 RTL設置輸入/輸出錯誤代碼並將其提升。

至於答案,請使用調試器。調試器引發異常時中斷。在下一次運行中,在錯誤語句中放置一個斷點,然後追蹤代碼(本例中爲RTL)。另外,如果你在編譯器選項中有'範圍檢查',你會得到一個範圍檢查錯誤而不是I/O錯誤,在這種情況下你可能會很快看到錯誤。

+1

你可以通過編寫SetLength(m,i + 1)來修復該部分;'... – TLama

+0

'i + 1'的問題是什麼? – ALZ

+0

@ALZ - 我不明白你的問題。 –