2013-02-22 20 views
1

我使用以下方法來移動並操作AnsiString。它大部分時間都在工作,但有時指向字符串的指針停止工作。考慮下面的代碼:德爾福AnsiString操縱 - PAnsiChar變得腐敗?

var 
    s: AnsiString; 
    p: PAnsiChar; 
    offset, idx, cnt: Integer; 
begin 
    s := 'some>very>long>string>with>field>delimiters>'; 
    p := @s[1]; 
    offset := 1; 

    // find the 5th field 
    cnt := 5; 
    repeat 
    idx := AnsiString.AnsiPos('>', p); 
    Inc(p, idx); 
    Inc(offset, idx); 
    Dec(cnt); 
    until cnt = 0; 

    // insert a new field after the 5th field 
    Insert(AnsiString('something new>'), s, offset); 

    // skip other fields 
    // insert other values 
    // repeat 
end; 

調試時,剛過repeat..until循環結束,你可以看一下檢查,看到p = 'field>delimiters>'。在檢查員Insert()聲明後,s = 'some>very>long>string>with>something new>field>delimiters>'p = 'something new>field>delimiters>'。這是預期的。

我的真實字符串是幾千個字符長。這種移動字符串並添加新字段的方法可以運行數十次,然後突然停止工作。在調用Insert()後,p不再顯示字符串前面的插入值。 p似乎不知道s已經改變...

爲什麼p正確地引用一個字符上sInsert()語句後,突然停止了一些呼籲Insert()後的工作?

(我發現了回答我的問題,打字時不起來。現在答案似乎是顯而易見的,但不能因此而我這個問題掙扎。也許張貼問題和答案將幫助別人......)

+2

只是供參考:在你的問題和你的答案中,你永遠不會在循環中使用它之前初始化'offset'。因此,您將隨機存儲器內容開始,並且每次通過循環時用'idx'的值遞增。 – 2013-02-22 02:47:55

+0

如果存在,您真正可以使用的是「AnsiPosEx」,這是一個將AnsiPos的MBCS感知與PosEx的可配置開始索引相結合的函數。那麼你根本就不需要'p',那麼每次你傳遞'p'作爲期望AnsiString的參數並且編譯器自動完成自動轉換時,就可以節省你創建和銷燬幾千個字符長的字符串您。如果您的搜索字詞確實是一個字符,請考慮使用AnsiStrScan。 – 2013-02-22 03:31:06

+0

好評。多謝你們。我的實際代碼初始化'offset' - 我在這裏忽略了它。我會看看AnsiPosEx和AnsiStrScan。謝謝! – 2013-02-22 06:05:27

回答

7

當你調用Insert(),內存管理器將AnsiString移動到新位置的內存,如果沒有足夠的額外的連續內存在其當前存儲位置擴展緩衝。這會使p指向舊內存位置,該位置不包含修改的字符串,並且可能會導致訪問衝突。

在每個Insert()語句修復問題後,添加一行代碼以重新初始化p

var 
    s: AnsiString; 
    p: PAnsiChar; 
    offset, idx, cnt: Integer; 
begin 
    s := 'some>very>long>string>with>field>delimiters>'; 
    p := @s[1]; 
    offset := 1; 

    // find the 5th field 
    cnt := 5; 
    repeat 
    idx := AnsiString.AnsiPos('>', p); 
    Inc(p, idx); 
    Inc(offset, idx); 
    Dec(cnt); 
    until cnt = 0; 

    // insert a new field after the 5th field 
    Insert(AnsiString('something new>'), s, offset); 
    p := @s[offset];         // <- this fixes the issue 

    // skip other fields 
    // insert other values 
    // repeat 
end; 
+0

哎呀,這很微妙! – 2013-02-22 08:02:12