Delphi 动态数组、静态数组、TBytes 的区别

结论:

1. 动态数组

dArr1: array of byte,数组的名称是一个地址,该地址和数组的第一个元素的地址不一样。该地址的值是第一个元素的地址。

dArr3: TBytes,和array of byte一样,只是一个别名,但是,有些函数的参数类型就是TBytes,你如果传array of byte的参数进去,会发生错误。

2. 静态数组(定义时即指定大小)

dArr2: array[0..9] of byte,数组的名称是一个地址,该地址和数组的第一个元素的地址重合。

3. TMemorySteam

列出内存流的原因是因为,通过内存流读写数组时,非常容易出错。而且,array of byte的参数和TBytes参数会指向不同的函数体,所以需要重点列出。

演示界面:

 代码

procedure TForm1.Button1Click(Sender: TObject);
var
  sArr : array[0..9] of Byte; //静态数组
  pB : ^Byte;
  i : Integer;
  sTmp : string;
begin
  Memo1.Lines.Append('');
  for i := 0 to 9 do
    sArr[i] := ord('a') + i;

  sTmp := '';
  for i := 0 to Length(sArr)-1 do
    sTmp := sTmp + IntToStr(sArr[i]) + ' ';
  Memo1.Lines.Append('静态数组的内容');
  Memo1.Lines.Append(sTmp);

  pB := @sArr;
  sTmp := '静态数组的地址:' + IntToStr(Integer(pB));
  Memo1.Lines.Append(sTmp);

  pB := @(sArr[0]);
  sTmp := '静态数组第一个元素的地址:' + IntToStr(Integer(pB));
  Memo1.Lines.Append(sTmp);

  pB := @sArr;
  sTmp := '';
  for i := 0 to Length(sArr)-1 do
  begin
    sTmp := sTmp + IntToStr(pB^) + ' ';
    pB := Pointer(LongWord(pB) + 1); //相当于 Inc(pB)
  end;
  Memo1.Lines.Append('以指针访问静态数组的内容');
  Memo1.Lines.Append(sTmp);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  dArr : array of byte;       //动态数组
  pB : ^Byte;
  i : Integer;
  sTmp : string;
  nValue : Integer;
begin
  Memo1.Lines.Append('');
  SetLength(dArr, 10);
  for i := 0 to Length(dArr)-1 do
    dArr[i] := ord('A') + i;
  sTmp := '';
  for i := 0 to Length(dArr)-1 do
    sTmp := sTmp + IntToStr(dArr[i]) + ' ';
  Memo1.Lines.Append('动态数组的内容');
  Memo1.Lines.Append(sTmp);

  pB := @dArr;
  sTmp := '动态数组的地址:' + IntToStr(Integer(pB));
  Memo1.Lines.Append(sTmp);

  //可以看到,动态数据其实是一个地址,这个地址存放的值是数据第一个元素的地址
  nValue := (PInteger(pB))^ ;
  sTmp := '动态数组地址中的内容:' + IntToStr(nValue);
  Memo1.Lines.Append(sTmp);

  pB := @(dArr[0]);
  sTmp := '动态数组第一个元素的地址:' + IntToStr(Integer(pB));
  Memo1.Lines.Append(sTmp);

  pB := @(dArr[0]);
  sTmp := '';
  for i := 0 to Length(dArr)-1 do
  begin
    sTmp := sTmp + IntToStr(pB^) + ' ';
    Inc(pB);
  end;
  Memo1.Lines.Append('以指针访问动态数组的内容');
  Memo1.Lines.Append(sTmp);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  stream : TMemoryStream;
  dArr1 : array of Byte;       //动态数组
  dArr2 : array of Byte;
  //TBytes其实就是array of Byte,但是有了新名字,编译器就可找到以TBytes为参数
  //类型的重载函数了,这就是重新定义一个名字的意义
  //dArr1 : TBytes;       //动态数组
  //dArr2 : TBytes;
  i : integer;
  sTmp : string;
  offset : Integer;
  count :  Integer;
begin
  Memo1.Lines.Append('');
  SetLength(dArr1, 10);
  for i := 0 to Length(dArr1)-1 do
    dArr1[i] := ord('A') + i;

  stream := TMemoryStream.Create;
  stream.SetSize(Length(dArr1));

  //注意,由于参数是 var类型,所以会取传入变量的地址进行作业,
  //所以dArr1[0]是正确的
  //而dArr1只是一个地址,这个地址的值才是数组的地址,所以传dArr1是错误的
  //w
  //stream.Write(dArr1[0], Length(dArr1));       //OK
  //stream.Write(dArr1, Length(dArr1));          //NG
  //stream.Write(Pointer(dArr1)^, Length(dArr1));//OK
  //stream.Write(TBytes(dArr1), Length(dArr1));  //OK
  //当参数的动态数组用TBytes转化时,实际执行的是下面这个函数,所以也不会出错
  //function TStream.Write(const Buffer: TBytes; Count: Longint): Longint;
  //begin
  //Result := Write(Buffer, 0, Count);
  //end;
  //所以,下面这样调用也是OK的
  stream.Write(TBytes(dArr1), 0, Length(dArr1)); //OK

  SetLength(dArr2, 10);
  stream.Position := 0;
  stream.Read(dArr2[0], 10);           //OK
  //stream.Read(Pointer(dArr2)^, 10);  //OK
  //stream.Read(TBytes(dArr2), 10);    //OK
  //stream.Read(TBytes(dArr2), 0, 10); //OK

  //dArr2被定义成TBytes,OK; 定义为 array of byte, NG
  //stream.Read(dArr2, 10);
  //stream.Read(dArr2, 0, 10);

  sTmp := '';
  for i := 0 to Length(dArr1)-1 do
  begin
    sTmp := sTmp + IntToStr(dArr1[i]) + ' ';
  end;
  Memo1.Lines.Append('数组1的内容');
  Memo1.Lines.Append(sTmp);

  sTmp := '';
  for i := 0 to Length(dArr2)-1 do
  begin
    sTmp := sTmp + IntToStr(dArr2[i]) + ' ';
  end;
  Memo1.Lines.Append('内存流读出的内容');
  Memo1.Lines.Append(sTmp);
end;
原文地址:https://www.cnblogs.com/CipherLab/p/13324324.html