如何使用 Move 连接多个字符串?

How to concat multiple strings with Move?

如何使用 Move 连接字符串数组。我试过了,但我就是想不出如何让 Move 操作正常工作。

program Project2;

{$POINTERMATH ON}

procedure Concat(var S: String; const A: Array of String);
var
  I, J: Integer;
  Len: Integer;
begin
  Len := 0;
  for I := 0 to High(A) do
  Len := Len + Length(A[I]);

  SetLength(S, Length(S) + Len);

  for I := 0 to High(A) do
  Move(PWideChar(A[I])[0], S[High(S)], Length(A[I]) * SizeOf(WideChar));
end;

var
  S: String;
begin
  S := 'test';
  Concat(S, ['test', 'test2', 'test3']);
end.

在第二个循环中你忘记了 S 已经有合适的大小来填充所有元素所以你必须使用另一个变量来知道 destination Move

的参数
procedure Concat(var S: String; const A: Array of String);
var
  I, Len, Sum: Integer;
begin
  Len := 0;
  for I := 0 to High(A) do
    Inc(Len, Length(A[I]));
  Sum := Length(S);
  SetLength(S, Sum + Len);
  for I := 0 to High(A) do
  begin
    if Length(A[I]) > 0 then
      Move(A[I][1], S[Sum+1], Length(A[I]) * SizeOf(Char));
    Inc(Sum, Length(A[I]));
  end;
end;  

source 参数转换为 PWideChar 是完全多余的,因为 Move 函数使用 一种旧的通用 语法允许传递您想要的所有内容(无类型的常量参数)。

我会这样写这个函数:

procedure Concat(var Dest: string; const Source: array of string);
var
  i: Integer;
  OriginalDestLen: Integer;
  SourceLen: Integer;
  TotalSourceLen: Integer;
  DestPtr: PChar;
begin
  TotalSourceLen := 0;
  OriginalDestLen := Length(Dest);
  for i := low(Source) to high(Source) do begin
    inc(TotalSourceLen, Length(Source[i]));
  end;
  SetLength(Dest, OriginalDestLen + TotalSourceLen);

  DestPtr := PChar(Pointer(Dest)) + OriginalDestLen;
  for i := low(Source) to high(Source) do begin
    SourceLen := Length(Source[i]);
    Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char));
    inc(DestPtr, SourceLen);
  end;
end;

这是不言自明的。并发症是由空字符串引起的。启用范围检查时,任何索引空字符串字符的尝试都将导致异常。

为了处理这种复杂情况,您可以为 Move 调用中涉及的字符串之一为空的情况添加 if 测试。我更喜欢不同的方法。我宁愿将字符串变量转换为指针。这绕过了范围检查,但也允许省略 if 语句。

Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char));

有人可能想知道如果 Source[i] 为空会发生什么。在这种情况下,Pointer(Source[i])nil,您可能会遇到访问冲突。事实上,没有错误,因为第三个参数指定的移动长度为零,并且 nil 指针实际上从未被取消引用。

另一行注释在这里:

DestPtr := PChar(Pointer(Dest)) + OriginalDestLen;

我们使用 PChar(Pointer(Dest)) 而不是 PChar(Dest)。后者调用代码来检查 Dest 是否为空,如果是,则生成指向单个空终止符的指针。我们要避免执行那段代码,直接获取Dest中保存的地址,即使是nil.