Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.59/32: Рейтинг темы: голосов - 32, средняя оценка - 4.59
1 / 1 / 0
Регистрация: 18.01.2011
Сообщений: 83

Удаление элемента из дин. массива дин. массивов.

29.05.2011, 22:27. Показов 6935. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть динамический массив динамических массивов. Когда я удаляю элемент с этого массива, то с последнего элемента пропадают все данные, а потом вообще появляются абсолютно левые числа. Это в случае, если элемент не является последним. Если удаляю последний элемент то вроде все норм.
Тип элементов массива.
Delphi
1
2
3
4
5
6
7
8
9
TYPE
  TArc = RECORD
  Index: SmallInt;
  Cost: SmallInt;
  END;
  TArcArray = ARRAY OF TArc;
 
VAR
  ArcArray: ARRAY OF TArcArray;
Так я удаляю элемент массива.
Delphi
1
2
3
4
5
      L := High(ArcArray);
      IF I < L THEN
        Move(ArcArray[I + 1], ArcArray[I],
          (L - I) * SizeOf(ArcArray[I]));
        SetLength(ArcArray, L);
В чем может быть проблема?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
29.05.2011, 22:27
Ответы с готовыми решениями:

Дин. массив
Всем доброго утра. Помогите разобраться с задачкой. &quot;Составить функцию для определения среднего арифметиче¬ского значения тех элементов...

Дин. массив (Delphi)
Как в Делфи реализовать одновременно ручное и рандомное заполнение массива? И что сделать, чтобы можно было менять размеры СтринГрида? ...

Дин.переменные,Указатели (Delphi)
type str = string; spk=^zvn; zvn = record Elm:str; Next:spk; end; Описать и...

5
 Аватар для IamPugalo
28 / 28 / 3
Регистрация: 14.04.2011
Сообщений: 101
29.05.2011, 22:48
Больно наварочено. При чем здесь Move. Я в свое время удалял так, правда массив интежер:
Code
1
2
3
4
5
6
7
8
procedure TArrInt.Delete(I:integer);//Удалить элемент
var k:integer;
begin
if i<fSize then
for k:=i to FSize-1 do fItems[k]:=fItems[k+1]
else exit;
SetLength(fItems,FSize-1);FSize:=Length(fItems);
 end;
0
1 / 1 / 0
Регистрация: 18.01.2011
Сообщений: 83
30.05.2011, 10:44  [ТС]
Цитата Сообщение от IamPugalo Посмотреть сообщение
Я в свое время удалял так, правда массив интежер:
Намного больше операций выходит.

Добавлено через 11 часов 6 минут
проблема в удалении строки в двумерном динамическом массиве...

Добавлено через 18 минут
Вот данные которые хранятся в массиве. Скажем я хочу удалить элемент под номером 250.

Строка 249: 237 248 250
Строка 250: 238 249 251
Строка 251: 239 250 252
Строка 252: 240 251
С помощью след. кода я сдвигаю все элементы после 249 на 1 позицию, элемент 250 ставится на последнее место и его значение становится равным элементу, который был последним.
Delphi
1
2
3
4
5
      I := 249;
      L := High(ArcArray);
      IF I < L THEN
        Move(ArcArray[I + 1], ArcArray[I],
          (L - I) * SizeOf(ArcArray[I]));
Вот что получилось:
Строка 249: 237 248 250
Строка 250: 239 250 252
Строка 251: 240 251
Строка 252: 240 251
Как можно увидеть, все прошло нормально. Далее, если я хочу освободить память от последнего элемента, будь то функции:
Delphi
1
2
SetLength(ArcArray, L);
ArcArray[L] := NIL;
То последний элемент стает равный фиг знает чему. Протер я штаны в свое время на парах, и теперь не знаю что делать. Гугль что-то не помогает. Догадываюсь что проблема в том из-за указателей.
Строка 248: 236 247 249
Строка 249: 237 248 250
Строка 250: 239 250 252
Строка 251: 22
Добавлено через 10 минут
Я так понимаю, что после перестановки элементов, последний и предпоследний элементы указываются на один и тот же массив указателей (дин. массив - это ведь массив указателей на элементы типа этого массива?). Когда убиваем последний элемент, то массив, на который он указывает тоже помирает, а предпоследний указывает теперь на хз что. Если сделать примерно вот так, то все будет ок. Способ правда мне не очень нравится, мб есть и получше?
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure TMainForm.Button2Click(Sender: TObject);
var l,i:integer; a: tarcarray;
begin
      I := 249;
      L := High(ArcArray);
      IF I < L THEN
        Move(ArcArray[I + 1], ArcArray[I],
          (L - I) * SizeOf(ArcArray[I]));
          for i := 0 to high(ArcArray[L - 1]) do
          begin
            SetLength(a, Length(a) + 1);
            A[I] := ArcArray[L - 1][I];
          end;
          ArcArray[L - 1] := a;
        SetLength(ArcArray, L);
end;
0
 Аватар для Mawrat
13113 / 5894 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
30.05.2011, 13:15
Цитата Сообщение от ZaxarPal Посмотреть сообщение
Далее, если я хочу освободить память от последнего элемента, будь то функции:
Delphi
1
2
3
4
1
2
SetLength(ArcArray, L);
ArcArray[L] := NIL;
То последний элемент стает равный фиг знает чему.
Конечно, именно так и получается. Сейчас расскажу. Перед удалением, на последнюю строку (на последний элемент в первой размерности массива) ссылается вот этот указатель: ArcArray[L]. Потом мы удаляем один элемент таким образом, что просто все элементы сдвигаем на одну позицию в строну начала массива. И делаем это с помощью вызова функции Move(). Что теперь получилось? А получилось то, что теперь на последний элемент ссылается ещё один элемент массива, вот этот: ArcArray[L - 1]. Т. е., теперь первой особенностью сложившейся ситуации является то, что на один и ту же строку ссылаются 2 элемента: ArcArray[L] и ArcArray[L - 1]. Второй особенностью является следующее: менеджер памяти Delphi не знает о том, что теперь на один и тот же массив ссылаются 2 переменные, а не одна. Не знает он об этом потому что он не в курсе о том, как влияет на массив функция Move(). Менеджер памяти по прежнему считает, что указатель на строку только один. Поэтому у строки (массива по второй размерности) счётчик ссылок равен 1 (равен единице). Далее, последняя строка уничтожается: ArcArray[L] := nil. При этом действии менеджер памяти Delphi уменьшает счётчик ссылок на единицу, в результате счётчик оказывается обнулён. А в случае обнуления счётчика ссылок менеджер памяти удаляет такой динамический объект (массив) из памяти.
Именно поэтому, после такого удаления строки и присваивания ArcArray[L] := nil, элемент ArcArray[L - 1] будет ссылаться на область освобождённой памяти. И в этой области уже может быть мусор. Либо эта область может быть отдана системе, тогда вообще возникнет исключение Access Violation (память не может быть Read или Wrire).

---
Более того, та строка (тот массив по второй размерности), который мы якобы удалили, не удалён на самом деле и остался в памяти. Т. е., произошла утечка памяти. Как я уже говорил, менеджер памяти Delphi не может отследить что делает с указателями процедура Move(). Поэтому счётчик ссылок на ту строку которую мы хотели удалить не поменялся, а значит менеджер памяти её не удалил из памяти. В добавок при сдвиге мы потеряли указатель на ту строку и теперь никак не сможем освободить память из под той строки.
---
Кроме этого, сама последовательность операций неверная:
Цитата Сообщение от ZaxarPal Посмотреть сообщение
Delphi
1
2
SetLength(ArcArray, L);
ArcArray[L] := NIL;
После выполнения SetLength(ArcArray, L) в массиве уже нет элемента ArcArray[L]. Здесь ошибка не возникает только потому что менеджер памяти ещё не освободил память из под элемента ArcArray[L] - или не успел, или не освободил из соображений оптимизации.
---
Удалять в этом случае надо так:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  I := ...;
  L := High(ArcArray);
  if I < L then
    //Удаляем из памяти именно тот элемент, который мы, собственно,
    //и намереваемся удалить.
    Finalize(ArcArray[I]);
    //Теперь выполняем сдвиг.
    Move(
      ArcArray[I + 1], ArcArray[I],
      (L - I) * SizeOf(ArcArray[I])
    );
    //Умененьшаем размер массива.
    SetLength(ArcArray, L);
    //Если нужно, уменьшаем индекс последнего элемента.
    //Dec(L);
 
    //Операция удаления завершена.
  end;
2
1 / 1 / 0
Регистрация: 18.01.2011
Сообщений: 83
30.05.2011, 15:15  [ТС]
Большое спасибо. Если вам не трудно, скопируйте ваш пост в эту тему
Динамические массивы в Delphi
думаю многим будет полезно

Хм, все равно бывают потери данных с использованием такого способа удаления
1
 Аватар для Mawrat
13113 / 5894 / 1708
Регистрация: 19.09.2009
Сообщений: 8,809
31.05.2011, 10:54
Лучший ответ Сообщение было отмечено как решение

Решение

Цитата Сообщение от ZaxarPal Посмотреть сообщение
Хм, все равно бывают потери данных с использованием такого способа удаления
Хм... вроде ясно в чём дело. Потеря последней строки происходит из-за этой операции:
Delphi
1
SetLength(ArcArray, L);
Ведь менеджер памяти в обязательном порядке отслеживает вызовы SetLength(). Т. к., менеджер "не заметил" копирования указателей через Move(), то он считает, что на последнюю строку ссылается только один элемент: ArcArray[L]. И счётчик ссылок у этой строки равен единице. Теперь, если мы исключаем этот элемент из массива через вызов: SetLength(ArcArray, L), то менеджер, видя, что на последнюю строку удалена ссылка, уменьшает счётчик ссылок этой строки на единицу. В результате, счётчик ссылок обнуляется и менеджер эту строку удаляет.
---
Вывод такой - следует отказаться от применения процедуры Move() в этом коде удаления. И заменить её на такой код:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
procedure ShiftArr(var aArr : TArcArray; const aI1, aI2 : Integer);
const
  SelfName = 'ShiftArr()';
var
  i, j, h : Integer;
begin
  if aI1 < aI2 then begin
    raise ERangeError.Create(SelfName + '. Ошибка! aI1 не должен быть меньше, чем aI2.');
  end;
  if aI1 = aI2 then Exit;
  
  h := High(aArr);
  j := aI2;
  for i := aI1 to h do begin
    aArr[j] := aArr[i];
    Inc(j);
  end;
  SetLength(aArr, j);
end;
С учётом этого кода, удаление будет выполняться через вызов процедуры ShiftArr():
Delphi
1
2
3
  I := ...;
  ShiftArr(ArcArray, I + 1, I);
  //Операция удаления завершена.
Менеджер памяти, в этом случае, правильно отследит изменения ссылок и удалит из памяти только те строки, которые в самом деле планируется удалить.
Цитата Сообщение от ZaxarPal Посмотреть сообщение
Если вам не трудно, скопируйте ваш пост в эту тему
Динамические массивы в Delphi
Да, надо будет добавить туда этот материал.
3
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
31.05.2011, 10:54
Помогаю со студенческими работами здесь

Ограничение ввода в дин-ком Edit
Всем привет! Хотелось бы услышать ваши подсказки на то, как решить проблемку одну. В общем, имеется форма, на которой в динамическом...

Утечка памяти JSON + дин.массив
При каждом последующем выполнении процедуры потребление оперативной памяти увеличивается Ломал голову несколько часов, но так и не смог...

Последовательность отображения компонентов при дин. создании
Здравствуйте! Столкнулся с такой проблемой: Есть панелька (TPanel). При нажатии, допустим, кнопки, на неё добавляются ещё панельки с...

из дин. дека в дин. стек (Borland С++)
Доброй ночи. Никак не получается сделать из динамического дека - стек. Помогите разобраться где именно и что необходимо изменить, что бы...

Добавление и удаление элементов дин массива
Задание: Создать класс «машина», имеющая марку, число цилиндров, мощность и цену. Определить конструктор и функцию печати. Создать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru