为什么我使用 Mike Heydon 的 TStringBuilder 类会遇到访问冲突?

发布于 2024-11-28 09:06:08 字数 907 浏览 1 评论 0原文

我正在使用从 .Net 移植到 Delphi 7 的 TStringBuilder 类

这是我的代码片段:

procedure TForm1.btn1Click(Sender: TObject);
const
  FILE_NAME = 'PATH TO A TEXT FILE';
var
  sBuilder: TStringBuilder;
  I: Integer;
  fil: TStringList;
  sResult: string;
  randInt: Integer;
begin
  randomize;
  sResult := '';
  for I := 1 to 100 do
  begin
    fil := TStringList.Create;
    try
      fil.LoadFromFile(FILE_NAME);

      randInt := Random(1024);

      sBuilder := TStringBuilder.Create(randInt);
      try
        sBuilder.Append(fil.Text);
        sResult := sBuilder.AsString;
      finally
        sBuilder.free;
      end;

      mmo1.Text := sResult;
    finally
      FreeAndNil(fil);
    end;
  end;
  showmessage ('DOne');
end;

我遇到 AV 错误。当我创建大小为 1024 倍的内存时,可以缓解这个问题,但有时它仍然会发生。

我做错了什么吗?

I am using a TStringBuilder class ported from .Net to Delphi 7.

And here is my code snippet:

procedure TForm1.btn1Click(Sender: TObject);
const
  FILE_NAME = 'PATH TO A TEXT FILE';
var
  sBuilder: TStringBuilder;
  I: Integer;
  fil: TStringList;
  sResult: string;
  randInt: Integer;
begin
  randomize;
  sResult := '';
  for I := 1 to 100 do
  begin
    fil := TStringList.Create;
    try
      fil.LoadFromFile(FILE_NAME);

      randInt := Random(1024);

      sBuilder := TStringBuilder.Create(randInt);
      try
        sBuilder.Append(fil.Text);
        sResult := sBuilder.AsString;
      finally
        sBuilder.free;
      end;

      mmo1.Text := sResult;
    finally
      FreeAndNil(fil);
    end;
  end;
  showmessage ('DOne');
end;

I am experiencing AV errors. I can alleviate the problem when I create memory with the size multiple by 1024, however sometimes it still occurs.

Am I doing something wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

和我恋爱吧 2024-12-05 09:06:08

你的代码没问题。您使用的 TStringBuilder 代码有错误。考虑这种方法:

procedure TStringBuilder.Append(const AString : string); 
var iLen : integer; 
begin 
  iLen := length(AString); 
  if iLen + FIndex > FBuffMax then _ExpandBuffer; 
  move(AString[1],FBuffer[FIndex],iLen); 
  inc(FIndex,iLen); 
end;

如果未来的长度对于当前缓冲区大小来说太长,则扩展缓冲区。 _ExpandBuffer 将缓冲区的大小加倍,但一旦完成,它就不会检查新的缓冲区大小是否足够。如果原始缓冲区大小为 1024,并且您要加载的文件为 3 KB,则将缓冲区大小加倍到 2048 仍然会使 Append 中的缓冲区太小,最终会覆盖超出缓冲区末尾 1024 个字节。

Append 中的 if 更改为 while

Your code is fine. The TStringBuilder code you're using is faulty. Consider this method:

procedure TStringBuilder.Append(const AString : string); 
var iLen : integer; 
begin 
  iLen := length(AString); 
  if iLen + FIndex > FBuffMax then _ExpandBuffer; 
  move(AString[1],FBuffer[FIndex],iLen); 
  inc(FIndex,iLen); 
end;

If the future length is too long for the current buffer size, the buffer is expanded. _ExpandBuffer doubles the size of the buffer, but once that's done, it never checks whether the new buffer size is sufficient. If the original buffer size is 1024, and the file you're loading is 3 KB, then doubling the buffer size to 2048 will still leave the buffer too small in Append, and you'll end up overwriting 1024 bytes beyond the end of the buffer.

Change the if to a while in Append.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文