1 / 1 / 0
Регистрация: 18.01.2011
Сообщений: 83

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

29.05.2011, 22:27. Показов 7252. Ответов 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
13116 / 5897 / 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
13116 / 5897 / 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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: показать затраченные материалы за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В качестве. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определённом условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru