Arrays 如何交换一个二维数组的两行,为什么它可以工作?
总结: 请查看以下David、Uwe和其他专家的评论 ================================================================================ 下面的代码交换双值的二维动态数组中的两行。我想知道:(1)以下代码是否是交换二维数组的两行的最佳实践?如果没有,那么做这类工作的最佳实践是什么?(2) 为什么下面的代码可以工作?我的意思是,二维数组不是一个连续的内存段吗?以下代码是否只有靠运气才能工作?任何建议都将不胜感激Arrays 如何交换一个二维数组的两行,为什么它可以工作?,arrays,delphi,row,swap,Arrays,Delphi,Row,Swap,总结: 请查看以下David、Uwe和其他专家的评论 ================================================================================ 下面的代码交换双值的二维动态数组中的两行。我想知道:(1)以下代码是否是交换二维数组的两行的最佳实践?如果没有,那么做这类工作的最佳实践是什么?(2) 为什么下面的代码可以工作?我的意思是,二维数组不是一个连续的内存段吗?以下代码是否只有靠运气才能工作?任何建议都将不胜感激
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TAADouble = array of array of Double;
TForm5 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form5: TForm5;
procedure SwapRows(arr: TAADouble; row0, row1: Integer);
implementation
{$R *.dfm}
procedure SwapRows(arr: TAADouble; row0, row1: Integer);
var
Tmp: Integer;
begin
{$IFDEF FPC}
Tmp := PtrUInt(arr[row0]);
PtrUInt(arr[row0]) := PtrUInt(arr[row1]);
PtrUInt(arr[row1]) := Tmp;
{$ELSE}
Tmp := Integer(arr[row0]);
Integer(arr[row0]) := Integer(arr[row1]);
Integer(arr[row1]) := Tmp;
{$ENDIF}
end;
procedure TForm5.FormShow(Sender: TObject);
var
tmpArray: TAADouble;
I, J: Integer;
rowStr: string;
begin
SetLength(tmpArray, 10, 10);
rowStr := '';
for I := 0 to 9 do
for J := 0 to 9 do
tmpArray[I][J] := I * J;
for I := 0 to 9 do
begin
rowStr := '';
for J := 0 to 9 do
rowStr := rowStr + FloatToStr(tmpArray[I][J]) + ' ';
OutputDebugString(PWideChar(rowStr));
end;
SwapRows(tmpArray, 3, 4);
for I := 0 to 9 do
begin
rowStr := '';
for J := 0 to 9 do
rowStr := rowStr + FloatToStr(tmpArray[I][J]) + ' ';
OutputDebugString(PWideChar(rowStr));
end;
end;
end.
你问:
以下代码是否仅适用于
运气如何
嗯,是的,您依赖于具体实施的细节
事实上,正确的写作方式是非常自然和简单的:
type
TDoubleArray = array of Double;
TDoubleMatrix = array of TDoubleArray;
procedure SwapRows(M: TDoubleMatrix; Row1, Row2: Integer);
var
Temp: TDoubleArray;
begin
Temp := M[Row1];
M[Row1] := M[Row2];
M[Row2] := Temp;
end;
您需要为行声明一个中间类型TDoubleArray,以便在交换例程中执行对Temp的赋值
二维恒定大小数组
array [1..M] of array [1..N] of TMyType
是一个连续的内存块
您拥有的二维动态大小数组不可用。事实上,它甚至可以是参差不齐的,因为行的列数不同。所以你可以有一个三角形矩阵。一个动态数组被实现为指向表示该数组的内存块的指针。所以二维动态数组实际上是指向指针数组的指针。这就是交换行(-pointer)s实际起作用的原因 请参见David的答案,以获得更清晰的方法 更新: 如果允许您使用泛型,您还可以这样做:
procedure <SomeClassOrRecord>.SwapRows<T>(var arr: TArray<T>; row0, row1: Integer);
var
Tmp: T;
begin
Tmp := arr[row0];
arr[row0] := arr[row1];
arr[row1] := Tmp;
end;
procedure.SwapRows(var-arr:TArray;第0行,第1行:整数);
变量
Tmp:T;
开始
Tmp:=arr[row0];
arr[row0]:=arr[row1];
arr[row1]:=Tmp;
终止
@Xichen不,不是。我想我这样做是出于习惯。没有它,它将完美地工作。我不觉得有什么令人信服的理由可以使用或不使用var,这只是我的习惯。我经常看到参数“错误地”声明为var
,因为开发人员认为他们在修改输入。当对象被传递到方法中时,这种情况尤其常见var
不需要修改对象的状态,但是使用var
实际上意味着可以用完全不同的实例替换对象。这是按引用传递和按值传递之间的细微差别。动态数组总是通过引用传递,因此var
允许您替换整个数组。@Craig是的,这正是我所想的。不过,引用类型是对var和const的嘲弄。不知何故,我认为动态数组具有与字符串相同的“写时复制”行为。简单的测试表明我错了。。。但必须注意的是,对字符串执行等效操作需要使用“var”关键字。此外,使用“const”关键字通常允许编译器进行一些额外的优化,在这种情况下,删除对@DynArrayAddRef@Ken的调用。正是动态数组不执行写时拷贝这一事实使得这一切都可以工作。动态数组的写时复制将是灾难性的,因为它们通常有非常大的内存块作为后盾。@Uwe:非常感谢您的宝贵意见@大卫:你能帮我评论一下你所说的是什么意思吗?如果行的引用计数不同,它就不起作用了。
?@Xichen不,我有点困惑,那句话不正确。大卫的评论消失了,我猜他意识到交换指针也会交换ref计数,因为它们位于数组前面,而不是指向数组的指针。否则裁判计数可能不起作用。@David,@Uwe:谢谢!我将切换到David的方法,因为它不涉及将指针转换为整数,因此我不需要担心integer/Cardinal/NativeInt/NativeUInt/PtrInt/PrtUInt之间的IfDef
,将指针强制转换为整数是不安全的-当64位版本到达时,这将非常失败。。。如果您使用的是最新的Delphi,请使用NativeInt类型,否则请定义您自己的类型,您可以自行设置以匹配指针大小。