Ошибка в delphi при работе с функциями и массивами - PullRequest
0 голосов
/ 02 апреля 2020

image

Эта ошибка возникает, когда я заполняю массив с помощью функции. Функция заполняет массив всеми деталями, хранящимися в текстовом файле. Код работает при заполнении массива, но когда я попытался использовать его в функции, он не работает.

type
  DynamicArray = array of string; 

Function fillarr(ArrParm: DynamicArray; FileName: String): DynamicArray;
Var
  tf: TextFile;
  sWord: String;
  i: Integer;
begin
  i := 0;
  SetLength(ArrParm, 1);
  AssignFile(tf, FileName);
  Reset(tf);
  while not eof(tf) do
  begin
    Readln(tf, sWord);
    ArrParm[i] := sWord;
    Inc(i);
    SetLength(ArrParm, i + 1);
  end;
  SetLength(ArrParm, i - 1);
  Result := ArrParm;
end;

procedure TForm4.FormShow(Sender: TObject);
Var
  arrPictures: DynamicArray;
begin
  FillArr(arrPictures, 'NameOfTheTextFile.txt');
  ShowMessage(arrPictures[1]); // Error occurs here

1 Ответ

4 голосов
/ 02 апреля 2020

Вы должны понимать, что dynamici c массивы являются ссылочными типами, но ссылки передаются по значению.

В TForm4.FormShow у вас есть переменная массива динамического c arrPictures. Несмотря на то, что это переменная local , она инициализируется, потому что это динамический массив c, который является управляемым типом. В частности, это nil ( динами нулевой длины c массив ) в начале. Следовательно, второй элемент arrPictures[1] не существует в начале этого метода.

Вы пытаетесь заполнить массив своим вызовом FillArr. Однако, когда вы передаете arrPictures этому методу, ссылка передается по значению, поэтому FillArr получает копию указателя на динамический c объект кучи массива.

Теперь процедура SetLength перераспределяет объект кучи динамического массива c, поэтому указатель на него должен измениться. Другими словами, значение переменной ArrParm изменяется, чтобы указывать на новый dynamici c объект кучи массива. Начальный, о котором знает TForm4.FormShow, остается без изменений. (Но в этом случае он вообще не существовал, потому что массив был nil нулевой длины.)

Следовательно, когда возвращается fillarr, arrPictures по-прежнему nil, и arrPictures[1] до сих пор не существует. Таким образом, вы получаете AV, пытающийся его прочитать.

Решение состоит в том, чтобы сделать параметр массива параметром var, чтобы переменная массива dynamici c передавалась по ссылке. Таким образом, когда FillArr изменяет значение указателя, это изменение будет видимым для переменной в TForm4.FormShow:

function fillarr(var ArrParm: DynamicArray; FileName: string): DynamicArray;

(fillarr является функцией, и на самом деле возвращает новый массив. Но когда вы вызываете эту функцию в TForm4.FormShow, вы отбрасываете значение результата, так что вы ничего не получаете, будучи функцией. Но это означает, что другое решение было бы не отбрасывать значение результата Но тогда вы можете полностью удалить параметр. Вам не нужно или не нужно два способа, чтобы подпрограмма возвращала одно и то же значение. Либо пусть это будет процедура с var или out параметр, или пусть это будет функция без параметров.)


Помимо этой проблемы, существуют другие проблемы с кодом. Например, попробуйте подумать о том, как вы читаете файл. Можете ли вы сделать это с меньшим количеством вызовов SetLength?

(Но в реальном приложении вообще не следует использовать устаревший Pascal ввод-вывод, а "никогда" увеличить размер динамического c массива или строки по одному элементу за раз.)

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