如何复制数组?

11

我在Delphi中遇到了一个非常基础的问题,但是我无法解决它。

我的代码:

注意:下面方法中的DataR是局部变量,但通常它是类变量。只是为了概念上它是局部的。

class procedure TCelebrity.BeginRead(var input:Array of byte);
var DataR:Array of byte;
begin
  VirtualFree(@DataRead,High(DataRead),MEM_RELEASE);
  SetLength(DataR,Length(input));
  Move(input,DataR,Length(input));
end;

这段代码可以编译通过,但在执行Move()函数后,DataR被置为了nil。

第二次尝试:

class procedure TCelebrity.BeginRead(var input:Array of byte);
var DataR:Array of byte;
begin
  VirtualFree(@DataRead,High(DataRead),MEM_RELEASE);
  SetLength(DataR,Length(input));
  DataR := Copy(input,0,Length(input));
end;

这段代码根本无法编译。第三行(DataR := Copy(input ....))会显示“不兼容的类型”。

问题在哪里?它们都是字节数组!


4个回答

9

试试这个

type
  TByteDynArray = array of Byte;

function CopyData(const Input:array of Byte):TByteDynArray;
begin
  SetLength(Result, Length(Input));
  Move(input[0], Result[0], Length(Input));
end;

5
一个正确的答案。但为了使其成为一个“好”的答案,你应该解释一下为什么你所做的更改很重要。否则,这只是一个魔法咒语。 - Rob Kennedy
5
如果我说错了,请纠正我,但值得注意的是,这仅适用于“字节数组”。如果数组不同,比如“整数数组”,那么你需要使用“Move(input[0], Result[0], Length(Input) * SizeOf(Integer))”。只是这样说而已。 - Richard A
@Rob Kennedy:Delphi中的Move()函数类似于C语言中的memcpy()/memmove()函数。 - dns
1
我知道,@Dns。那又怎样? - Rob Kennedy

8

为什么不用FOR语句?

SetLength(DataR,Length(input));
for i:=Low(input) to High(input) do
  DataR[i]:=input[i];

顺便说一下:如果您想将数组作为参数传递,您应该声明它们的类型,例如:

type
  TMyArray = array of byte;

并使用TMyArray作为参数类型。

编辑:我被通知i的初始值更小。在我的原始帖子中,它是针对i:=0的,但i:=Low(input)更安全、更纯净。


我有一个问题。VirtualFree总是返回false,那么我该怎样释放当前使用的DataR内存?注意,DataR不是本地变量,而是原始代码中的类变量。感谢您提前回答! - Ivan Prodanov
不,你没有免费的简单数组。这样的数组会自动释放(例如当你的类被销毁时)。注意:如果你有一个对象引用的数组,则必须手动释放这些对象,因为只有数组会被 Delphi 释放。 - smok1
请注意,SetLength会重新分配整个数组,因此请避免频繁使用此过程。当您使用SetLength使数组变长时,当前内容保持不变,但是当您使其变短时,一些内容将会丢失。 - smok1
2
回答“为什么不使用FOR?”我的唯一理由是如果存在真正的性能问题。如果您要执行此操作很多次,那么我认为Move会更快。 - Richard A
使用Move()函数,它类似于C语言中的memcpy()/memmove()。永远不要使用FOR循环来复制数组。 - dns

2

尝试:

class procedure TCelebrity.BeginRead(var input:Array of byte);
var DataR:Array of byte;
begin
  VirtualFree(@DataRead,High(DataRead),MEM_RELEASE);
  SetLength(DataR,Length(input));
  Move(input[0],DataR,Length(input));
end;

VirtualFree() 调用似乎有点多余。 - JensG

1

Move过程不会移动内存的一部分。它会复制Count字节。这样,您将获得两个不同但相同的数组:Input和DataR。

procedure CopyData(const Input: Array of Byte);
var 
    DataR: Array of Byte;
begin
    SetLength(DataR, Length(Input));
    Move(Input[0], DataR[0], SizeOf(Byte)*Length(Input));
end;

顺便提一下,使用静态数组时,您可以使用SizeOf(Input)而不是SizeOf(Byte)*Length(Input)。Byte可以替换为其他数据类型。


为什么不使用SizeOf(Input[0])代替硬编码的数据类型? - TmTron

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