我遇到了一个处理StrPCopy()的奇怪问题。请查看以下示例代码:
procedure TForm2.butnTestClick(Sender: TObject);
var
s : string;
begin
//-- assign string this way will cause AV when trying to StrPCopy()
s := 'original string';
//-- assign string this way works!!!!!!!
//s := Trim('original string');
//-- AV error when trying to alter the string
StrPCopy(PChar(s), PChar('changed'));
//-- should come back with "changed"
Memo1.Lines.Add(s);
end;
我正在使用Delphi 10 Seattle。如果我试图改变" s"使用StrPCopy()我会得到AV错误。但是,我用Trim()包围我的字符串声明,它会起作用。
似乎通过周围的字符串声明与Trim()触发编译器来关闭对该特定字符串的某种排序优化。我只是不知道那是什么。请帮忙。
答案 0 :(得分:3)
当s
引用文字时,它指向只读内存。因此访问违规。
当您使用Trim
创建可写字符串时,可以覆盖它而不会出现运行时错误。也就是说,你仍然销毁了字符串,因为空终结符和长度不匹配。
这里的主要问题是将Delphi字符串与空终止的C字符串混合。停止滥用,你的问题就会消失。你根本没有理由打电话给StrPCopy
。一旦你停止使用本机Delphi字符串就不会遇到任何此类问题。
编写代码的正确方法如下:
s := 'changed';
答案 1 :(得分:1)
使用StrPCopy()调用是不安全的 - 无论使用通过Trim()赋值创建的新字符串消除了AV。
字符串数据类型比PChar更复杂。它有一个长度组件,它神奇地位于指针和字符数据之前。施放到PChar可以工作,但只能用于阅读。
通过将字符串强制转换为PChar,您可以让StrPCopy爆炸“变形”。字符串到内存的那一部分。在您的示例中,您将以较小的字符串进行复制,因此您可以按内存方式进行复制。结果是一个非常混乱的字符串(长度不匹配字符串,中间有一个空字符),但你在其范围内。
如果您的代码类似......
StrPCopy(PChar(s), PChar('changed to this string'));
...然后你的代码覆盖了字符串的内存占用 - 通常没有立即AV。你可以逃避这一点。你可能没有。