使用Delete()时出现访问冲突00000000。

3
我尝试删除字符串开头的非字母字符,但是当字符串中只有非字母字符(如“!!”或“?!?”)时,它会产生访问冲突错误。以下是我的代码:
  // The Log(); is a routine that adds stuff to my log memo.
  Log('Begin Parse');
  while not IsLetter(ParsedName[1]) do
   begin
     Log('Checking Length - Length is '+IntToStr(Length(ParsedName))+' ...');
     if Length(ParsedName) <> 0 then
     Begin
     Log('Deleting Char ...');
     Delete(ParsedName,1,1);
     Log('Deleted Char ...');
     End;
     Log('Checking Length - Length is now '+IntToStr(Length(ParsedName))+' ...');
   end;
   // It never reaches this point!
   Log('End Parse');

这是我的日志生成的内容:
21:51:19: Checking Length - Length is 2 ...
21:51:19: Deleting Char ...
21:51:19: Deleted Char ...
21:51:19: Checking Length - Length is now 1 ...
21:51:19: Checking Length - Length is 1 ...
21:51:19: Deleting Char ...
21:51:19: Deleted Char ...
21:51:19: Checking Length - Length is now 0 ...
21:51:19: Access violation at address 007A1C09 in module 'Project1.exe'. Read of address 00000000 

如您所见,这是在所有字符都被删除后发生的。我猜问题在于我试图访问不存在的东西,但是我不知道我是怎么做到的。

编辑:是的,我知道这是一个愚蠢的问题和所有那些东西 - 我只是忽略了一些细节。别告诉我你从来没有过这种情况 ;)


4
@Jeff,当你为故障排除添加日志时是非常好的。但是,如果你要添加记录代码,应该学会实际阅读日志条目。从日志的倒数第二行中,很明显可以得出你问题的答案:“21:51:19:检查长度 - 长度现在为0 ...”。很明显,如果长度现在为0,则访问ParsedName [1]将失败,因为不再存在ParsedName []。 - Ken White
7
如果你开启了范围检查,就不会出现访问冲突问题。请进入编译选项并立即打开它,然后永远不要关闭它。与你在解决问题上花费的时间相比,程序运行时额外花费的时间微不足道。 - Rob Kennedy
1
根据Ken的评论,更仔细地阅读日志也会告诉你,你没有理由得出Delete是罪魁祸首的结论,因为在调用它后,你的程序能够记录另外两条消息。问题出现在“长度现在是”消息和“长度是”或“结束解析”消息之间。这两者之间唯一的东西是IsLetter,所以在那里设置一个断点,看看是否能够找出为什么它可能会在该迭代中具有特定值的ParsedName上崩溃。 - Rob Kennedy
1
+1 低估了,不知道为什么有-1票,看起来是一个有效的问题。即使这个bug很傻/星期一早晨类型,答案得到了+9,所以显然这是一个好问题,如果答案那么好的话,对吧? - Johan
1
+1 不断地提问,你会从中学到东西的。欢迎。 - Najem
显示剩余5条评论
2个回答

13

这个问题与“删除”无关。即使你让它删除不存在的字符,它也可以正常工作。

这行代码:

while not IsLetter(ParsedName[1]) do

试图访问ParsedName[1],因此该字符最好存在。你的代码并不特别优美,但一个简单的解决方法是

while (length(ParsedName) > 0) and not IsLetter(ParsedName[1]) do

你可以只做这样

while (length(ParsedName) > 0) and not IsLetter(ParsedName[1]) do
  Delete(ParsedName, 1, 1);

正是我所需要的 - 谢谢!你的代码并不特别美观。只是出于兴趣,你会怎么做呢? - Jeff
另外,我添加删除的原因是因为我认为那是出了问题的地方。 - Jeff
看一下 SysUtils 中 Trim 的代码,并对 IsLetter(..) 做同样的操作 - 这样会快得多。 - Edelcom
@Edelcom:我知道。事实上,当人们在循环中使用“Delete”时,我通常会抱怨。但在这种情况下,我相信OP更关心学习算法的基础知识,而不是性能。我也不认为这段代码将用于非常大的字符串。 - Andreas Rejbrand
@Edelcom:请参考https://dev59.com/qFTTa4cB1Zd3GeqPv9XX。 - Andreas Rejbrand

3
您还需要在While测试中添加检查字符串长度> 0的检查。
在检查字符串长度之前,您要先检查它是否为数字。或者,您可以将字符删除后将字符串长度检查移到“之后”。无论如何,都可以这样做 :)

我相信我已经做到了 - 如果 Length(ParsedName) <> 0 then - Jeff
是的,我刚刚更新了答案,以指明需要的地方。对此感到抱歉 :) - James
我的做法不对吗?你介意修改一下我的代码以反映你的更改吗?谢谢! :) - Jeff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接