Как использовать объявить и использовать указатель на массив const в записи const? - PullRequest
0 голосов
/ 07 октября 2009

У меня есть несколько константных массивов одного базового типа, но разных размеров, и мне нужно указать на них в константных записях. Код ниже компилируется успешно, но заканчивается с ошибкой.

type
  Toffsets = array of integer;

  Trec = record
             point1: Tpoint;          //complete size
             point2: Tpoint;
             aOffsets:  ^Toffsets;
           end;

const
  cOffsetsA: array [0..3] of integer = (7, 4, 2, 9);
  cOffsetsB: array [0..5] of integer = (1, 2, 3, 4, 5, 6);

  cRec1: Trec = (
    point1:   (x: 140; y: 46);
    point2:   (x: 5; y: 7);
    aOffsets: @cOffsetsA;
  );

  cRec2: Trec = (
    point1:   (x: 40; y: 6);
    point2:   (x: 5; y: 7);
    aOffsets: @cOffsetsB;
  );

В моем коде мне нужно получить доступ к данным из массивов cOffsetsA / B, имеющих указатель на запись. Я пытался сделать это так:

var pMyRec: ^Trec;
...
pMyRec := @cRec1;
...
i := pMyRec^.aOffsets^[0];

и это вызывает ошибку - «Нарушение прав доступа ... чтение адреса 000000 ...»

Кто-нибудь может объяснить, что здесь не так и как это исправить, как это сделать?

Возможно, мне также придется добавить в запись поле _length, которое будет содержать размер массива, на который указывает указатель; это не проблема.

С наилучшими пожеланиями, LUK

Ответы [ 3 ]

1 голос
/ 07 октября 2009

Хотя использование таких констант в Delphi приемлемо, я просто хочу добавить, что вообще-то не очень хорошая идея так поступать. Лично, если этот код в каком-то модуле, я бы использовал что-то вроде этого: (D2007 и выше)

type
  Toffsets = array of integer;
  Trec = record
    point1: Tpoint; //complete size
    point2: Tpoint;
    aOffsets: ^Toffsets;
    constructor Create(X1, Y1, X2, Y2: Integer; Offsets: array of integer);
  end;

Таким образом, запись получает конструктор, который заполнит ее правильными данными. Недостатком является то, что вы больше не можете объявить его как const, если хотите использовать конструктор для его заполнения данными. Однако вы можете решить эту проблему, используя следующий код в разделе Инициализация:

var
  cRec1: Trec;

initialization
  cRec1 := Trec.Create(140, 6, 5, 7, cOffsetsA);

Этот код объявит запись как глобальную переменную вместо константы и заполнит ее вашими данными.

Ваш конструктор может выглядеть так:

constructor Trec.Create(X1, Y1, X2, Y2: Integer; Offsets: array of integer);
var
  I: Integer;
begin
  point1.X := X1;
  point1.Y := Y1;
  point2.X := X2;
  point2.Y := Y2;
  new(aOffsets);
  SetLength(aOffsets^, 0);
  for I in Offsets do
  begin
    SetLength(aOffsets^, Succ(Length(aOffsets^)));
    aOffsets^[Pred(Length(aOffsets^))] := I;
  end;
end;

Который заполнит запись вашими данными. Однако вам не нужно использовать конструктор для создания записей таким образом! Это просто добавленная функция.

Чтобы сделать его еще более интересным, вы можете добавить свойства для двух точек и массива, сделав сами поля приватными и объявив только метод чтения для свойств. Таким образом, вы все равно можете убедиться, что его содержимое доступно только для чтения и доступно только для чтения.

Но каков риск использования вашего кода? Ну, так как вы объявляете их как константы, риск невелик, если вы не разрешите присваивать типизированные константы ({$ J +} объявляется ...) В этом случае фрагмент кода может изменить значение в cOffsetsA, а также изменить в cRec1. Это то, что вы хотите?

В любом случае, используя конструктор и инициализируя их в коде, вы делаете свой код более динамичным. Однако он по-прежнему остается простым типом записи, и дополнительные свойства и методы не изменят его структуру или размер.

Для этого вам понадобится Delphi 2007 или лучше, хотя ...

0 голосов
/ 07 октября 2009

Должно работать следующее:

<code>
i:=TOffsets(pMyRec^.aOffsets)[0];
0 голосов
/ 07 октября 2009

Похоже, я нашел ответ сам:

type
  Toffsets = array of integer;

- это динамический тип массива, и setLength должен использоваться с любой переменной этого типа для выделения памяти. Мне нужен указатель на существующий константный массив, поэтому единственное, что нужно изменить, чтобы решить проблему, - это объявление этого типа. Это должно выглядеть так:

type
  Toffsets = array [0..0] of integer;

и да, я должен добавить поле _length в записи, так как low (pMyRec ^ .aOffsets ^), high (...) и length (...) не работают.

С наилучшими пожеланиями, LUK

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...