IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Работа с динамическим массивом
сообщение
Сообщение #1


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Доброго времени суток ув. форумчане! Обращаюсь к вам со своей проблемой, для начала опишу текущую картину.

Имеется следующий класс :
type
point = class
id : integer;
X : real;
Y : real;
Z : real;
function Point (x : real; y : real; id_get : integer) : integer;
end;

Описание функции этого класса :
function point.Point (x : real; y : real; id_get : integer) : integer;
var id : Integer;
begin
id := - 1;
X := x;
Y := y;
if ( id_get <> -1 ) then id_get := id;
end;

Типы данных :
    init_points : array of integer;
xPos, yPos, zPos : integer;
tab : array of point;

Так же есть функция которая заполняет переменные xPos, yPos, zPos значениями и вызывает функцию добавления точки.
procedure TForm1.GiveValues();
var i : integer;
begin
for i:= Low(init_points) to High(init_points)
do
if ( ( i mod 3 ) = 0 ) then
begin
xPos := init_points[i];
yPos := init_points[i + 1];
zPos := init_points[i + 2] - 150;
AddPoint();
end;
end;


И вот сама ключевая функция AddPoint() :
procedure TForm1.AddPoint();
var deletion : boolean;
dx, dy, dist : real;
i, y : integer;
p : point;
new_point : point;
begin
deletion := FALSE;
if ( ( zPos > 0 ) or ( xPos < 0 ) ) then Exit;
if ( Length(tab) > 0 ) then
begin
for i := Low(tab) to High(tab) do
begin
p := tab[i];
dx := p.X - xPos;
dy := p.Y - yPos;
dist := sqrt (dx * dx + dy * dy);
if (dist < 4) then
begin
deletion := TRUE;
for y := i to High(tab) - 1 do tab[y] := tab[y + 1]; //смещаем на элемент вниз
SetLength(tab, High(tab) - 1); //уменьшаем размер так как убрали 1 элемент
end;
end;
end;
if ( deletion = FALSE ) then
begin
new_point.Point(xPos, yPos, -1);
new_point.Z := zPos + 150; // !!!! Вот тут программа вылетает !!!!
SetLength(tab, High(tab) + 1);
tab[Length(tab)] := new_point; // добавляем в конец новый элемент
end;
end;

Как я отметил в коде, программа вылетает на строке new_point.Z := zPos + 150; с ошибкой EAccessViolation. Мне кажется это связано с неверной работой с динамическими массивами, но более детально я не могу понять суть этой проблемы. Буду рад помощи, заранее спасибо.

Сообщение отредактировано: Tan -


--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Для начала: Point у тебя - класс, и его перед использованием надо что? Правильно, создать. У тебя в коде создания экземпляра класса нет. Как-то вот так:

    if ( deletion = FALSE ) then
begin
new_point := Point.Create; // Да, да. Point.Point - обычная функция, а нужен конструктор

new_point.Point(xPos, yPos, -1);
new_point.Z := zPos + 150; // !!!! Вот тут программа вылетает !!!!
SetLength(tab, High(tab) + 1);
tab[Length(tab)] := new_point; // добавляем в конец новый элемент
end;
Ну, или сделать Point.Point конструктором (не понимаю я этой С++-ной привычки называть конструктор точно так же, как и сам класс. Я больше привык к Create-у) и вызывать соответствующим образом (как принято в Дельфи, а не так, как в Турбо Паскале)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Спасибо за ответ Владимир, идея понятна, есть несколько вытекающих вопросов :
1 - Destroy надо делать каждый раз после того как я уже использовал это значение?
2 - Нет идей почему теперь может писать invalid pointer operation ссылаясь на end в конце функции GiveValues?


--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
Destroy надо делать каждый раз после того как я уже использовал это значение?
Destroy надо делать тогда, когда значение больше не нужно. Чтоб не было утечек. То есть, при уменьшении размера Tab. Кстати, замени там цикл
Цитата
for i := Low(tab) to High(tab) do
на While - негоже внутри цикла For уменьшать динамический массив, это тоже приведет к проблемам, при использовании For значение High(tab) на каждой итерации не пересчитывается, конечное значение вычисляется при входе в цикл, а внутри цикла оно может измениться - будет ошибка...

Цитата
Нет идей почему теперь может писать invalid pointer operation ссылаясь на end в конце функции GiveValues?
Выход за пределы массива - как минимум. Ты ж идешь до High(init_points), так откуда у тебя будет init_points[i + 2]? Вот тебе и вылет программы.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Я переписал указанные места (destroy пока не делал, потому что основная задача сначала скомпилить то, что есть). Теперь компилятор указывает ту же ошибку только в строке dx := p.X - xPos; Вероятно где-то что-то опять я проворонил.

procedure TForm1.AddPoint();
var deletion : boolean;
dx, dy, dist : real;
i, y : integer;
p : point;
new_point : point;
begin
deletion := FALSE;
if ( ( zPos > 0 ) or ( xPos < 0 ) ) then Exit;
if ( Length(tab) > 0 ) then
begin
i := 1;
while ( i <> Length(tab) ) do
begin
ShowMessage(inttostr(Length(tab)));
p := Point.Create; //добавил и тут конструктор
p := tab[i];
dx := p.X - xPos;
dy := p.Y - yPos;
dist := sqrt (dx * dx + dy * dy);
if (dist < 4) then
begin
deletion := TRUE;
for y := i to High(tab) - 1 do tab[y] := tab[y + 1];
SetLength(tab, High(tab) - 1);
end;
i := i + 1;
end;
end;
if ( deletion = FALSE ) then
begin
new_point := Point.Create;
new_point.Point(xPos, yPos, -1);
new_point.Z := zPos + 150;
SetLength(tab, Length(tab) + 1);
tab[Length(tab)] := new_point;
end;
end;

procedure TForm1.GiveValues();
var i : integer;
begin
i := 0;
while ( i < Length(init_points) )
do
begin
xPos := init_points[i];
yPos := init_points[i + 1];
zPos := init_points[i + 2] - 150;
AddPoint();
i := i + 3;
end;
end;


--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Цитата
Я переписал указанные места
Не вижу:

Цитата
  i := 0;
while ( i < Length(init_points) ) // <--- Ну, будет i = Length(init_points) - 1
do
begin
xPos := init_points[i];
yPos := init_points[i + 1];
zPos := init_points[i + 2] - 150; // Тут - попытка обратиться к "запредельному элементу"
AddPoint();
i := i + 3;
end;


Как у тебя изначально инициализируется массив init_points? Какого он размера на момент входа в GiveValues?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Cпасибо за ответ, Владимир. Массив считывает из файла значения, которых 256. Делаю я это так:

procedure TForm1.DataFromFile ();    //pick ups data from file
var num, size, i : Integer;
begin
AssignFile(Points_file, 'Points.txt');
Reset(Points_file);
size := 256;
i := 0;
SetLength(init_points, size);
SetLength(tab, 0);
while not Eof(Points_file) do
begin
Read(Points_file, num);
init_points[i] := num;
i := i + 1;
end;
CloseFile(Points_file);
end;



--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Стоп, стоп... Сразу не посмотрел вот сюда:
Цитата
     i := 1;
while ( i <> Length(tab) ) do
begin
Это ни разу не аналог
for i := Low(tab) to High(tab) do
. Массивы индексируются с 0, а не с 1. Надо делать:

     i := 0;
while ( i < Length(tab) ) do
begin


Еще одно (причина - та же, индексация с 0) :
Цитата
             SetLength(tab, Length(tab) + 1); 
tab[Length(tab)] := new_point;
Это некорректный код. Вылетит запросто. Ибо элемента tab[Length(tab)] в динамическом массиве быть не может. Элементы, которые существуют - от tab[0] до tab[Length(tab) - 1], или от tab[low(tab)] до tab[high(tab)]. Но никак не до Length ...

Пересмотри еще раз всю программу, с учетом того, что ты теперь знаешь о начале отсчета с 0, а не с 1...
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Спасибо Владимир, я смог скомпилировать код - основная моя проблема была в том, что я по массиву не с 0 шёл.
У меня остался последний вопрос по моему коду - в моём первом посте описана функция Point. В этой функции каждрому экземпляру класса point должно быть присвоено значение X и Y, которое передаётся через параметр этой функции через x и y. Но когда в моём случае создаётся экзсемпляр new_point, и после вызова функции new_point.Point(параметры) значения new_point.X и new_point.Y равны 0 (по крайней мере я так заметил) - я сделал вывод что каким-то образом эти значения не передаются вне функции. Если я не ошибаюсь, то в паскале для таких случае перед параметром функции требовалось написать var, мне очень интересно что для этого надо сделать на Delphi.


--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Так что чему в функции присваивается? Одинаковые имена полей класса и параметров - зло. Хотя бы перед именем поля поставь Self, чтобы было понятнее, что происходит...

Цитата
Но когда в моём случае создаётся экзсемпляр new_point, и после вызова функции new_point.Point(параметры) значения new_point.X и new_point.Y равны 0 (по крайней мере я так заметил) - я сделал вывод что каким-то образом эти значения не передаются вне функции.
Бррр... Теперь я не понял. А что должно вернуться? Где инициализация полей класса? Если добавишь Var (да, в Дельфи точно так же, как и в Паскале) - что должно вернуться из функции? Где вообще возврат результата? Функция не возвращает ничего. Компилятор должен выбрасывать предупреждение...

 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> не понимаю я этой С++-ной привычки называть конструктор точно так же, как и сам класс

Она, кстати, не всегда выполняется.
Вообще это неудобно.

> Кстати, замени там цикл на while

Не надо заменять его на while, потому что там останется тот же дурацкий алгоритм за квадрат.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Я хочу чтобы внутри функции Point формировались значения для new_point.X и new_point.Y. Для этого я делаю там присваивание X := x, Y := y, но значения не присваиваются и равны 0 (внутри функции они верные), вне функции new_point.X и new_point.Y - 0.

Сообщение отредактировано: Tan -


--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Гуру
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской
Ада: Разработчик
Embarcadero Delphi: Сторонник
Free Pascal: Разработчик

Репутация: -  627  +


Я ж написал:
Цитата
Хотя бы перед именем поля поставь Self

Т.е., вот так:
function point.Point (x : real; y : real; Var id_get : integer) : integer;
begin
{Self.}id := - 1;
self.X := x;
self.Y := y;
if ( id_get <> -1 ) then id_get := {Self.}id;

Point := { чему равен результат функции??? }
end;
(Паскаль, как и все языки его группы, не делает разницы между X и x, это для него одна и та же переменная. И то, что ты делаешь - это присвоение параметру самого себя. Смысла - никакого, поле класса вообще не затрагивается).

Если перед id_get не поставишь Var, то изменение ее значения внутри Point.Point наружу не выйдет. Только смысла в этом параметре вообще ноль: "если id_get не (-1), то присвоить его значению id, которое в самом начале принудительно ставится в (-1). Если же оно и так (-1) - то ничего не делать" Вдумайся, что тут написано. Это именно то, что ты запрограммировал.

Цитата
Не надо заменять его на while, потому что там останется тот же дурацкий алгоритм за квадрат.
Там останется не "тот же дурацкий", а корректно работающий (в отличие от For-а, я написал почему) алгоритм за квадрат...

Сообщение отредактировано: IUnknown -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> а корректно работающий (в отличие от For-а, я написал почему) алгоритм за квадрат...

Хорошая отмаза.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15


Профи
****

Группа: Пользователи
Сообщений: 559
Пол: Мужской
Реальное имя: Бруно

Репутация: -  10  +


Спасибо огромное за помощь, ввиду некоторых жизненных обстоятельств мне пришлось вернуться к Delphi - из-за того, что давно там не работал - оттуда и все вытекающие ошибки, на которые вы указали.


--------------------
Цитата
Imagination is more important than knowledge.
Albert Einstein
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 29.03.2024 20:05
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name