Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работа с динамическими массивами, не используя стандартных средств 
:(
    Опции темы
EKoshelev
Дата 21.3.2013, 15:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



Доброго дня.

Возник вопрос: можно ли сделать класс (или набор процедур и функций) работающий с любыми динамическими массивами. То есть имея динамический массив типа Integer, или типа какой-нибудь хитрой структуры я бы при помощи одних и тех же средств мог добавлять элемент, удалять искать и т. п.

Чуть конкретнее.
Массивы будут создаваться по стандартной схеме:
arr1: array of integer;
arr2: array of TObject;
arr3: array of record
  a, b, c: double;
  b: array [0..4] of boolean;
end;
Далее я буду передавать arr1, arr2 и arr3 в какие-то функции, и с ними будут происходить необходимые преобразования. При этом во всех трёх случаях, например, для добавления элемента я буду вызывать одну и ту же процедуру.

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

Дело в том, что если массивы с разными элементами будут передаваться в одну процедуру, то процедура должна будет воспринимать как указатели (по крайней мере, лично я других вариантов не вижу). При этом воспользоваться функцией SetLength я не смогу (хотя вот прямо сейчас подумал, что можно попробовать извратиься). Короче, если бы знать как изменить длину массива не используя SetLength, то, вероятно, все мои проблемы решились бы.

Короче, если кто-то может чем-то помочь, то я был бы благодарен. Ну, естественно, если уже есть решения, то ссылки были бы не лишними.


Заранее спасибо.



--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
AndreyIQ
Дата 21.3.2013, 15:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 185
Регистрация: 5.2.2007

Репутация: нет
Всего: 8



Вам точно массив нужен? Может TList проще будет?
PM MAIL   Вверх
EKoshelev
Дата 21.3.2013, 15:52 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



AndreyIQ, Ну а как без напрягов в TList'е можно хранить int64 или структуры? Если только по ссылкам. При этом (если я ошибаюсь - поправь) постоянно нужно будет преобразовывать типы. Я как-то (с помощью TList) накидал класс хранящий interger'ы, и вместо Pointer'ов хранил integer'ы. Получилось удобно, но не скоро. Каждый раз писать новый класс для нового типа - не охота и долго. А при таком подходе, полагаю, можно всё будет сделать довольно быстро.


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
AndreyIQ
Дата 21.3.2013, 16:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 185
Регистрация: 5.2.2007

Репутация: нет
Всего: 8



Начиная с Delphi 2009 (если не ошибаюсь) появилась поддержка дженериков. Очень удобно в использовании.
PM MAIL   Вверх
Чучмек
Дата 21.3.2013, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 14
Всего: 41



Цитата(EKoshelev @  21.3.2013,  15:30 Найти цитируемый пост)
При этом воспользоваться функцией SetLength я не смогу 

Почему?
Код

type
 TArrayType=(atByte,atWord,atInt,atString);
 TByteArray=array of Byte;
 TWordArray=array of Word;
 TIntArray=array of Integer;
 TStringArray=array of String;

procedure MySetLength(var m;length:integer;ArrayType:TArrayType);
begin
case ArrayType of
  atByte:   SetLength(TByteArray(m),length);
  atWord:   SetLength(TWordArray(m),length);
  atInt:    SetLength(TIntArray(m),length);
  atString: SetLength(TStringArray(m),length);
 end;
end;

Код

var
 m:array of integer;
begin
MySetLength(m,32,atInt);
Caption:=inttostr(length(m));



--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
CynicRus
Дата 21.3.2013, 20:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 248
Регистрация: 31.5.2012

Репутация: нет
Всего: 5



Вот кусочек кода  библиотеки Fundamentals, содержит функции для работы с динамическими массивами. Правда автор использовал не указанный выше механизм, а перегрузку функций. 
PM MAIL   Вверх
EKoshelev
Дата 22.3.2013, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



AndreyIQ, Спасибо. Не знал. Можно будет глянуть.


ЧучмекCynicRus, Ребята, ну вы предлагаете рассматривать массивы с элементами известных типов. Мне бы хотелось уметь работать с массивами элементов любых типов. Даже неизвестных заранее.

На сколько я сумел выяснить на данный момент, динамический массив - это некая структура.
Если у нас есть массив Arr: array of SmthType, то 
Pointer(Arr) указывает на первый (или нулевой) элемент массива
integer(Pointer(Arr - 4)) хранит ссылку на переменную с к-вом элементов массива
integer(Pointer(Arr - 12)) хранит ссылку на к-во байтов занимаемое массивом минус четырнадцать.
Т. е. из двух последних значений можно получить sizeof элемента массива (SizeOf(SmthType)).

Короче, для изменения длины массива, вероятно, нужно как-то изменить эту структуру. И вот хотелось бы знать как.


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
EKoshelev
Дата 22.3.2013, 08:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 509
Регистрация: 1.9.2004

Репутация: нет
Всего: нет



Короче, зная о структуре то, что уже я знаю изменение длины массива можно (казалось бы) сделать так:
1. Создать при помощи GetMem фрагмент памяти нужной длины.
2. Перенаправить на него Pointer хранящийся по адресу Pointer(Arr)
3. Изменить длину в ячейке Pointer(Arr - 4);
4. Изменить длину в ячейке Pointer(Arr - 12);
5. И (!) освободить старый массив (FreeMem).

Вот на пятом пункте вылетает ошибка: "Invalid pointer operation".


--------------------
Вежливым и адекватным предлагаю общаться на "ты".
PM MAIL   Вверх
bems
Дата 22.3.2013, 08:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



а что ты отдаешь во FreeMem? память выделяется одни махом и на сам массив и на служебную информацию, соответственно освобождать нужно так же. Еще прими во внимание что никто тебе не обещал что структура по отрицательному смещению от нулевого элемента будет стабильной между версиями дельфи (например с некоторых пор там есть счетчик ссылок как у строк, хотя раньше небыло).
При таких исследованиях сильно помогает чтение исходников юнита System (ну и прочих внутренностей rtl), ты это делал?

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

Это сообщение отредактировал(а) bems - 22.3.2013, 08:39


--------------------
Обижено школьников: 8
PM MAIL   Вверх
bems
Дата 22.3.2013, 08:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



щас посмотрел system.pas от ХЕ2 и увидел что вот это
Цитата(EKoshelev @  22.3.2013,  08:19 Найти цитируемый пост)
Изменить длину в ячейке Pointer(Arr - 12);
неправильно

на х64 Arr - 12 используется просто для выравнивания, а на х32 служебная структура динамического массива занимает всего 8 байт (два четырехбайтовых целых Arr - 4 и Arr - 8)
Если ты действительно увидел что по смещению -12 лежит поинтер на длину в байтах, то вероятно это служебные данные менеджера памяти, и относятся они не к самому массиву, а к блоку памяти, как его знает менеджер. Короч не нужно освобождать 12 байт перед массивом, нужно 8

Добавлено через 9 минут и 27 секунд
И кстати если ты говоришь именно про освобождение, то (по крайней мере в ХЕ2) процедура DynArrayClear доступна для прямого вызова из твоего кода.

Это сообщение отредактировал(а) bems - 22.3.2013, 09:00


--------------------
Обижено школьников: 8
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0828 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.