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;
好的代码像粥一样,都是用时间熬出来的