2011-11-22 64 views
2

好吧,我一直在試圖找出我犯的每一個可能的錯誤,但我放棄了......我需要幫助!我正在寫的是一個應用程序來管理我的工作的租金,當日期過去時,我的應用程序從2個文本文件中刪除名稱。我寫了3個小函數(過程)來完成這個工作。這裏:德爾福for循環和StringList錯誤

這一個從dates.dat文件加載並刪除包含該僱員的名稱的行。

procedure remDate(emp: String);/// Removes employee from date file 
var 
    pos1, i: integer; 
    dateList: TStringList; 
begin 
    dateList:=TStringList.Create; 
    dateList.LoadFromFile('Data\dates.dat'); 
    for i:=0 to dateList.Count-1 do begin 
    pos1:=AnsiPos(emp, dateList[i]); 
    if pos1<>0 then begin 
     dateList.Delete(i); 
     dateList.SaveToFile('Data\dates.dat'); 
    end; 
    end; 
    dateList.Free; 
end; //eo remDate 

這一行從perm.dat文件中刪除包含員工姓名的行。

procedure remPerm(emp: String);/// Removes employee from perm file 
var 
    pos1, i: integer; 
    permList: TStringList; 
begin 
    permList:=TStringList.Create; 
    permList.LoadFromFile('Data\perm.dat'); 
    for i:=0 to permList.Count-1 do begin 
    pos1:=AnsiPos(emp, permList[i]); 
    if pos1<>0 then begin 
     permList.Delete(i); 
     permList.SaveToFile('Data\perm.dat'); 
    end; 
    end; 
    permList.Free; 
end; //eo remPerm 

這一個堅持在一起。 isDue是一個簡單的函數,它比較兩個日期,如果日期是今天或已過去,則返回TRUE。

procedure updatePerms; 
var 
    empList: TStringList; 
    i: integer; 
begin 
    empList:=TStringList.Create; 
    empList.LoadFromFile('Data\employes.dat'); 
    for i:=0 to empList.Count-1 do begin 
    if isDue(empList[i]) then begin 
     remDate(empList[i]); 
     remPerm(empList[i]); (*) Here is where the error points. 
    end; 
    end; 
    empList.Free; 
end; 

時,它得到的updatePerms過程remPerm我得到的錯誤是。(*) 我得到一個錯誤EStringList,越界(#)。通過很多嘗試發現,只有當員工的截止日期是今天才會發生。請評論,如果你需要更多的信息! 在此先感謝,任何幫助真的很感激!

+0

哦,順便說一句,員工只能在一個文件中一次。 – Gab

回答

18

問題是您正在使用for循環。 for循環的終點僅在進入循環時評估一次。那時你可能有100個項目,但是一旦你開始刪除,就會少一些。這將導致列表索引出界出錯。

簡單的解決方法是扭轉for循環:

procedure remDate(emp: String); 
/// Removes employee from date file 
var 
    pos1, i: integer; 
    dateList: TStringList; 
begin 
    dateList := TStringList.Create; 
    dateList.LoadFromFile('Data\dates.dat'); 
    for i := dateList.Count - 1 downto 0 do 
    begin 
    pos1 := AnsiPos(emp, dateList[i]); 
    if pos1 <> 0 then 
    begin 
     dateList.Delete(i); 
     dateList.SaveToFile('Data\dates.dat'); 
    end; 
    end; 
    dateList.Free; 
end; // eo remDate 

如果發生一次以上的員工這將工作。

然而,如果員工確實只發生一次,就可以使用break從環路早退出:

procedure remDate(emp: String); 
/// Removes employee from date file 
var 
    pos1, i: integer; 
    dateList: TStringList; 
begin 
    dateList := TStringList.Create; 
    dateList.LoadFromFile('Data\dates.dat'); 
    for i := 0 to dateList.Count - 1 do 
    begin 
    pos1 := AnsiPos(emp, dateList[i]); 
    if pos1 <> 0 then 
    begin 
     dateList.Delete(i); 
     dateList.SaveToFile('Data\dates.dat'); 
     Break; // <-- early exit 
    end; 
    end; 
    dateList.Free; 
end; // eo remDate 

另一種解決方案是使用while循環。

+0

非常感謝!不僅你糾正了我,而且讓我明白了我的錯誤!認爲這可能是,但沒有看到這麼遠。我改變了我爲:= 0到...「downto」,它完全工作。我還注意到「休息」;備查!再次感謝! – Gab

+0

當我不得不從列表中刪除東西時(stringlist,tlist),我總是使用'while'循環。從未想過爲此使用'for..downto 0'。 +1好 –