Как удалить элемент из динамического массива c
Перейти к содержимому

Как удалить элемент из динамического массива c

  • автор:

Как удалить элемент из динамического массива c

***
Такая к вам просьба. Мне нужны функции для добавления/удаления
элементов массивов в Си (не C++). Я так понимаю что допустим для
добавления элемента надо сделать его копию. А это как то криво.
Уверен что у многих уже есть такие функции. Если вам не жалко
киньте мне пожалуста их на адрес antonov21@inbox.ru.
Так же нужны любые другие функции для работы с элементами массивов.
Реализующие динамическое распределение памяти для элементов и т.п.
Ну вы понимаете. Спасибо большое. Считаю этот форум очень толковым.
В Поиске найти ничего по этому поводу не смог. Поэтому спрашиваю. Еще
раз всем спасибо.
***

Спрашивал на других форумах — никто не помог.
Может здесь помогут — очень надеюсь.

Я имею ввиду функции для работы с элементами массивов (вставить элемент, добавить, удалить).
А также любые другие функции которые будут полезны при работе с массивами.
Включая динамическое распределение памяти для элементов и т.п.

Re: Добавление/удаление элементов массива в Си

От: Алексей Владимирович Миронов
Дата: 05.02.03 01:44
Оценка:

Здравствуйте, Alexey_Antonov, Вы писали:

AA>Я так понимаю что допустим для добавления элемента надо сделать его копию. А это как то криво.

Согласен. С точки зрения производительности лучше заранее заказать память «с запасом», и не перераспределять ее при каждом добавлении элемента. Если «запаса» не хватило, то при очередном добавлении стОит сделать «запас» побольше.

На «чистом C» набор функций общего назначения для работы с массивами списками, деревьями, очередями и прочим есть, например, в GTK+ (смотреть в сторону Glib).

P.S. Может, лучше все-таки на C++ с использованием STL? Просто, достаточно эффективно, широко применяется, много знающих людей, в т.ч. на этом форуме.

Re[2]: Добавление/удаление элементов массива в Си

От: VCoder http://wxbar.sf.net
Дата: 05.02.03 07:11
Оценка:

АВМ>P.S. Может, лучше все-таки на C++ с использованием STL? Просто, достаточно эффективно, широко применяется, много знающих людей, в т.ч. на этом форуме.

Я тоже советую обратить внимание на C++ с использованием STL.

С уважением,
Дмитрий.
Re[2]: Добавление/удаление элементов массива в Си

От: _wqwa
Дата: 05.02.03 13:02
Оценка:

Здравствуйте, Алексей Владимирович Миронов, Вы писали:

АВМ>На «чистом C» набор функций общего назначения для работы с массивами списками, деревьями, очередями и прочим есть, например, в GTK+ (смотреть в сторону Glib).

Вот как раз все остальное, кроме массивов в Glib есть. А их-то и нету.

Если связный список или хеш не устроит, то придется изгалиться ручками.
Так что остается применить советы Саттера (если не ошибаюсь) и выделять память с запасом, напр. 30%. При переполнении массива — выделить еще на треть больше и т.д.

Re: Добавление/удаление элементов массива в Си

От: VVV
Дата: 05.02.03 13:57
Оценка:

Здравствуйте, Alexey_Antonov, Вы писали:

..
AA>Я имею ввиду функции для работы с элементами массивов (вставить элемент, добавить, удалить).
AA>А также любые другие функции которые будут полезны при работе с массивами.
AA>Включая динамическое распределение памяти для элементов и т.п.

Конечно, такой библиотеки у меня нет, но с помощью функции realloc это очень просто реализуется.
Не компилил, не проверял, просто идея:

typedef struct ARRAY< int num_; int size_ int top_; char arr_[1]; >ARRAY; #define SIZEARRAYMEM(n, s) ((n)*(s)+sizeof(ARRAY)) char *CreateArray(int numElem, int sizeElem) < ARRAY *pa=(ARRAY*)malloc(SIZEARRAYMEM(numElem, sizeElem)); pa->num_=numElem; pa->size_=sizeElem; pa->top_=0; return pa->arr_; > void DestroyArray(void *pa) < pa=((char*)pa)-offsetof(ARRAY, arr_); free(pa); > void AddElem(void **parr, void *pe) < ARRAY *pa=(ARRAY*)(((*(char**)parr))-offsetof(ARRAY, arr_)); if(pa->top_ == pa->num_) < int num=pa->num_*2; pa=(ARRAY*)realloc(pa, SIZEARRAYMEM(num, pa->size_)); pa->num_=num; > memcpy(pa->arr_+pa->top_*pa->size_, pe, pa->size_); pa->top_++; *parr=pa; > int GetCount(void *parr) < ARRAY *pa=(ARRAY*)(((char*)parr)-offsetof(ARRAY, arr_)); return pa->top_; >

Re[3]: Добавление/удаление элементов массива в Си

От: Алексей Владимирович Миронов
Дата: 05.02.03 15:08
Оценка: 3 (1)

Здравствуйте, _wqwa, Вы писали:

W>Вот как раз все остальное, кроме массивов в Glib есть. А их-то и нету.

Как же так? На странице документации Glib 2.0 перечислены следующие типы данных, поддерживаемые Glib:

Memory Chunks — efficient way to allocate groups of equal-sized chunks of memory.
Doubly-Linked Lists — linked lists containing integer values or pointers to data, with the ability to iterate over the list in both directions.
Singly-Linked Lists — linked lists containing integer values or pointers to data, limited to iterating over the list in one direction.
Double-ended Queues — double-ended queue data structure.
Trash Stacks — maintain a stack of unused allocated memory chunks.
Hash Tables — associations between keys and values so that given a key the value can be found quickly.
Strings — text buffers which grow automatically as text is added.
String Chunks — efficient storage of groups of strings.
Arrays — arrays of arbitrary elements which grow automatically as elements are added.
Pointer Arrays — arrays of pointers to any type of data, which grow automatically as new elements are added.
Byte Arrays — arrays of bytes, which grow automatically as elements are added.
Balanced Binary Trees — a sorted collection of key/value pairs optimized for searching and traversing in order.
N-ary Trees — trees of data with any number of branches.
Quarks — a 2-way association between a string and a unique integer identifier.
Keyed Data Lists — lists of data elements which are accessible by a string or GQuark identifier.
Datasets — associate groups of data elements with particular memory locations.
Relations and Tuples — tables of data which can be indexed on any number of fields.
Caches — caches allow sharing of complex data structures to save resources.
Memory Allocators — allocates chunks of memory for GList, GSList and GNode.

Я не говорю, что эти массивы подойдут на все случаи жизни. Но автор оригинального сообщения и не говорил, какие именно массивы ему нужны. А зря.

Re[4]: Добавление/удаление элементов массива в Си

От: _wqwa
Дата: 05.02.03 16:02
Оценка:

Как удалить элемент из динамического массива c

Пусть надо удлить элемент с индексом K
в цикле сдвигаете все элементы K+1 на место предыдущего.
после чего изменяете размер массива.

for i:=K+1 to Length(Valies)-1 do Valies[i-1] := Valies[i]; SetLength(Valies, Length(Valies) - 1);

Внимание. Вообще операции изменения размера динамического массива ресурсоёмкие. А тут ещё и цикл (представьте, Вы удаляете 2-й элемент в массиве из миллиона элементов. Надо 999998 элементов переместить в памяти. Это весьма не быстро.

Поэтому рекомендую посмотреть в сторону связных динамиских списков. Там опреция удаления сводится к изменению ссылки(или пары ссылок) и очистке памяти одного элемента. Это практически мгновенно происходит (т.е. не затрагивает остальные элементы этой динамической структуры)

Последний раз редактировалось Serge_Bliznykov; 14.05.2011 в 12:34 .

Serge_Bliznykov
Посмотреть профиль
Найти ещё сообщения от Serge_Bliznykov

Регистрация: 03.01.2011
Сообщений: 2,508

если порядок не важен, вместо сдвига можно менять местами с последним элементом

Length(Valies)

возвращает количество элементов в массиве, а нумеруются они с 0. Так что или — 1 добавить, или лучше использовать high().

«Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего.»
Последний раз редактировалось veniside; 14.05.2011 в 11:47 .
Регистрация: 09.01.2008
Сообщений: 26,238

Length(Valies)
возвращает количество элементов в массиве, а нумеруются они с 0. Так что или — 1 добавить, или лучше использовать high().

согласен. важное замечание. Это я ошибся.
исправил в исходном сообщении

если порядок не важен, вместо сдвига можно менять местами с последним элементом

и с этим согласен. Хотя мне связные списки всё равно как-то больше нравятся

Serge_Bliznykov
Посмотреть профиль
Найти ещё сообщения от Serge_Bliznykov

Форумчанин
Регистрация: 26.07.2009
Сообщений: 489
Сообщение от mrCloud
Есть тип например

TValues = record Price,term:integer; end;

и по нему создан динамический массив

var Valies:array of TValues

Вопрос: как удалить элемент с заданным индексом?

Удалить из массива элемент просто так нельзя (потому что элементы массива всегда хранятся в соседних ячейках памяти), это делается при помощи того, что заново перераспределяют память на массив, но как было сказано, это сильно влияет на производительность.
Но лучшим (по производительности, но не по размеру памяти) сделать поле флаг, который будет означать, обрабатывать или нет этот элемент массива

TValues = record Price,term:integer; Exist: Boolean; end; . for I := 0 to High(Valies) do begin if Valies[I].Exist then begin // Обработка end; end;

И для «удаления» (исключения из обработки) присваиваем Valies[I].Exist := False;

Но если все-таки хочешь удаление, то

 TValues = record Price, Term:integer; end; TValuesArr = array of TValues; var Form1: TForm1; V: TValuesArr; function DeleteEl(V: TValuesArr; Index: Integer): TValuesArr; implementation function DeleteEl(V: TValuesArr; Index: Integer): TValuesArr; var NewSize: Integer; I, Ind: Integer; begin NewSize := Length(V) - 1; if Index > NewSize then raise Exception.Create('Указанный элемент не существует'); SetLength(Result, NewSize); Ind := 0; for I := 0 to High(V) do begin if I <> Index then begin Result[Ind] := V[I]; Inc(Ind); end; end; end; procedure TForm1.Button1Click(Sender: TObject); begin SetLength(V, 5); V := DeleteEl(V, 4); end;

Если в глубине души вы программист, то, следуя своим наклонностям, вы захотите написать кусок кода.
Последний раз редактировалось chertovich; 14.05.2011 в 15:04 .

chertovich
Посмотреть профиль
Найти ещё сообщения от chertovich

C++ удаления элементов с динамического массива

В деструкторе класса Array я хочу сделать сначала итерацию по всем элементам массива и для каждого отдельно вызвать delete , так как все они были созданы с помощью оператора new , а только после этого вызвать delete[] arr . Но такая конструкция не работает:

for(int i = 0; i

Ошибка: отсутствует оператор *, соответствующий этим операндам.

Вопрос: Как реализовать удаления указателей из динамического массива?
Отслеживать
220k 15 15 золотых знаков 120 120 серебряных знаков 233 233 бронзовых знака
задан 26 июл 2018 в 13:39
2,904 20 20 серебряных знаков 45 45 бронзовых знаков
delete arr[i]; ?
26 июл 2018 в 13:42
delete arr[i]; нужно
26 июл 2018 в 13:43
@gil9red arr[i] — не указатель, какой уж тут delete .
26 июл 2018 в 13:49
delete arr[i] не работает. там друга ошибка.
26 июл 2018 в 13:53

Ничего не понятно. «В деструкторе класса Array я хочу сделать сначала итерацию по всем элементам массива. «. Какого массива. Класс Array не имеет никакого отношения к массиву arr , ничего о нем не знает и, разумеется, никак не может итерировать по его элементам в своем деструкторе. (Не говоря уже о том, что ни о каком delete для элементов arr речи быть не может).Так о каком массиве идет речь?

26 июл 2018 в 14:23

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

arr[0] = *arr0; arr[1] = *arr1; 

вы скопировали (присвоением) объекты. При удалении массива для этих копий деструкторы будут вызваны автоматически. А чтоб удалить исходные объекты —

delete arr0; delete arr1; 

к вашим услугам.

Вот если бы вы делали

Array ** arr = new Array*[2]; Array* arr0 = new Array(); Array* arr1 = new Array(); arr[0] = arr0; arr[1] = arr1; 

тогда дело другое, тогда перед удалением массива надо было бы выполнить

delete a[0]; delete a[1]; 

Отслеживать
ответ дан 26 июл 2018 в 13:43
220k 15 15 золотых знаков 120 120 серебряных знаков 233 233 бронзовых знака

Я понял, спасибо. Получается, если бы я хотел, чтобы оно работало, как я написал, то надо перегрузить оператор = ? Я просто не хотел, отдельно писать delete для каждого созданного объекта. Думал, может это можно сделать как-то в цикле.

26 июл 2018 в 13:52

Ну тогда, как я написал в «Вот если бы» — делайте массив не объектов, а указателей. И переписывать оператор присвоения нужно только если поверхностное копирование (которое по умолчанию) не годится. Ну не получится переписать так, чтоб ваш исходный код заработал — потому что вы храните объекты. Даже если напишете перемещение — все равно удалять выделенную память придется. Извращение типа хранить в скопированном объекте адрес исходного и при удалении удалять и его — не рассматриваю 🙂

26 июл 2018 в 13:56

Вроде как понял, но не точно, но основную ошибку точно понял)) еще раз спасибо. Сделал через массив указателей, так работает.

26 июл 2018 в 14:06

получается, когда я делаю arr[0] = *arr1 , то происходит копирование, а значит объект который уже будет лежать в массиве под индексом arr[0] фактически будет находиться не в хипе, а в стеке и по этому вызов delete для него не работает?

26 июл 2018 в 14:10

Он будет находиться в хипе — но в том месте, которое выделено не Array* arr0 = new Array(); , а Array *arr = new Array[2]; Когда вы будете удалять delete[]arr , будут вызваны деструкторы для всех элементов массива, так что отдельно удалять ничего не нужно.

Сдвиг элементов динамического массива после удаления элемента

Потом мне к примеру нужно удалить второй элемент в RecRec и остальные сдвинуть влево без потери данных…
Как это правильно сделать ?

PaHaNjkee

Аватар

procedure TForm1.Button1Click(Sender: TObject); 
type TRecStruct = record
WTable: array of DWORD;
HTable: DWORD;
end;
var RecRec: array of TRecStruct;
i,j: Integer;
procedure PutToMemo;
var s: String;
m,n: Integer;
begin
for m:=0 to High(RecRec) do begin
s:='';
for n:=0 to High(RecRec[m].WTable) do s:=s+Format('%d,',[RecRec[m].WTable[n]]);
s:=s+Format(' HTable=%d',[RecRec[m].HTable]);
Memo1.Lines.Add(s);
end;
Memo1.Lines.Add('');
end;
begin
SetLength(RecRec,6);
for i:=0 to High(RecRec) do begin
SetLength(RecRec .WTable,i+1);
for j:=0 to High(RecRec .WTable) do RecRec .WTable[j]:=10*i+j;
RecRec .HTable:=i;
end;
PutToMemo;
//удаление по индексу 2
for i:=3 to High(RecRec) do begin
RecRec[i-1].WTable:=Copy(RecRec .WTable);
RecRec[i-1].HTable:=RecRec .HTable;
end;
SetLength(RecRec,5);
PutToMemo;
end;

Похожие статьи

  • Как сигнатура узнает какие байты РЕ файла соотвествуют ее частям?
  • Как передать динамический массив Tbitmap в процедуру
  • Выделить память под динамический массив
  • Динамические массивы Turbo Pascal
  • Использование нетипизированного указателя для передачи массива
  • Как создать двумерный динамический массив?
  • Загрузка из записи в listbox
  • Как узнать тип поля в DBGrid?
  • Функции для работы с динамическими массивами
  • Пример заполнения динамического массива

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *