Как поменять местами две строки двумерного массива и почему он будет работать? - PullRequest
0 голосов
/ 18 марта 2011

Суммирование:

Пожалуйста, проверьте комментарии ниже от Дэвида, Уве и других экспертов.

=============================================== =================================

Следующий код заменяет две строки в двумерном динамическом массиве двойных значений. Мне интересно: (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.

Ответы [ 2 ]

4 голосов
/ 18 марта 2011

Динамический массив реализован как указатель на блок памяти, представляющий этот массив. Таким образом, двумерный динамический массив на самом деле является указателем на массив указателей. Вот почему замена строки (-pointer) на самом деле работает.

См. Ответ Дэвида для более чистого подхода.

Обновление: Если вам разрешено использовать дженерики, вы можете сделать следующее:

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;
4 голосов
/ 18 марта 2011

Вы спрашиваете:

Работает ли следующий код только по счастливой случайности?

Что ж, да, вы полагаетесь на конкретные детали реализации.

На самом деле правильный способ написания совершенно естественен и прост:

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

- это непрерывный блок памяти.

Двухмерный массив динамического размера, как у вас, нет.На самом деле это может быть даже рваный в том смысле, что строки имеют разное количество столбцов.Так что вы можете иметь, скажем, треугольную матрицу.

...