我使用以下方法来移动并操纵AnsiString
。它大部分时间都有效,但有时指向字符串的指针退出运行。给出以下代码:
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>'
之后。这是预期的。
我的真正字符串长达数千个字符。这种在字符串中移动并添加新字段的方法可以工作几十次,然后突然停止工作。调用p
后,Insert()
不再显示字符串前面的插入值。 p
似乎并不知道s
已经改变了......
为什么p
在s
语句后Insert()
正确引用了某个字符,并在拨打Insert()
之后突然停止工作?
(我在打字时发现了我的问题的答案。现在答案显而易见,但在我遇到问题的时候并不是这样。也许发布问题和答案会帮助别人...... )
答案 0 :(得分:7)
当您调用Insert()
时,如果没有足够的额外连续内存来扩展当前内存位置的缓冲区,内存管理器会将AnsiString
移动到内存中的新位置。这使p
指向旧的内存位置,该位置不包含修改后的字符串,并可能导致访问冲突。
在每个p
语句后添加一行代码以重新初始化Insert()
可以解决问题。
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;