Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
ВнизВыделение памяти под запись с динамическим массивом Найти похожие ветки
← →
dm_member © (2012-09-19 22:04) [0]А точнее, реально ли изменять размер динамического массива, являющегося полем записи?
PTRec=^TRec;
TRec=record
s: string;
arr: array of string;
end;
var rec: array of PTRec;
Запись создаётся в памяти обычным getmem, массив rec легко наращивается через SetLength. Но при попытке установить первоначальную длину массива arr в записи rec[i], выдаётся ошибка access violation. Я могу предположить, что изменение длины массива arr требует динамического "растягивания" памяти под запись, что может оказаться невозможным. Можно ли эту проблему решить? Примерные решения были бы полезны.
← →
Германн © (2012-09-19 22:08) [1]
> динамического массива, являющегося полем записи
В поле записи нет ничего, кроме ссылки на массив.
← →
dm_member © (2012-09-19 22:14) [2]
> Германн © (19.09.12 22:08) [1]
Я где-то ошибся?
Вообще, реальная запись выглядит так:
PTRec=^TRec;
TRec=record
s: string;
arr: array of PTRec; - я эту строчку упростил для примера
end;
Так или иначе, в программе необходимо увеличивать длину массива arr, но SetLength сразу выдаёт ошибку доступа.
← →
Pavia © (2012-09-19 22:18) [3]FillChar нулями сделай, ошибка пропадёт.
← →
Медвежонок Пятачок © (2012-09-19 22:18) [4]а сама запись остается всегда одной и той же длины.
независимо от длины обоих этих элементов.
Я могу предположить, что изменение длины массива arr требует динамического "растягивания" памяти под запись,
а я могу предположить что в массиве rec нету элемента с индексом i.
и буду прав.
← →
Юрий Зотов © (2012-09-19 22:21) [5]После SetLength новым элементам массива rec нужно присвоить адреса новых записей и только потом к ним можно будет обращаться.
GetMem(P, SizeOf(TRec)); // Создали новую запись
SetLength(rec, Length(rec) + 1); // Добавили элемент массива
i := High(rec); // Получили индекс нового элемента
rec[i] := P; // Проинициализировали новый элемент
// Теперь с новым элементом можно работать
rec[i].s := "Мама мыла раму";
SetLength(rec[i].arr, 20);
for j := 0 to 19 do
rec[i].arr[j] := IntToStr(j);
← →
Pavia © (2012-09-19 22:23) [6]
> GetMem(P, SizeOf(TRec)); // Создали новую записьSetLength(rec,
> Length(rec) + 1); // Добавили элемент массива
Ошибка во 2 строчке.
← →
Медвежонок Пятачок © (2012-09-19 22:23) [7]но SetLength сразу выдаёт ошибку доступа.
а ты убери сетленс но оставь обращение к rec[i].
и проверь, пропадет ли AV.
И поймешь, что сетленс не причина ошибки
← →
Юрий Зотов © (2012-09-19 22:27) [8]
> Pavia © (19.09.12 22:23) [6]
Какая?
← →
dm_member © (2012-09-19 22:32) [9]
> Медвежонок Пятачок © (19.09.12 22:23) [7]
Я делаю так:
rec[length(rec)-1].s:=Edit1.Text;
Edit2.text:=rec[length(rec)-1].s;
Ошибок не возникает, пока не использую SetLength и не обращаюсь к массиву arr.
> Юрий Зотов © (19.09.12 22:21) [5]
Я попробую.
← →
Pavia © (2012-09-19 22:32) [10]Со строчкой промахнулся так как сплю.
Ладно расскажу.
GetMem выделяет не иницированную памчять в результате которой в
TRec будет муссор.
SetLength() видит что arr отличит от 0 и пробует выполнить перераспределение памяти.
Так как arr содержит мусор, то во время перераспределения памяти под новый массив происходит исключение.
Поэтому структуру TRec надо запулить и сделать это можно при помощи FillChar.
← →
Pavia © (2012-09-19 22:33) [11]PS. arr своего рода указатель.
← →
dm_member © (2012-09-19 22:55) [12]
> Pavia © (19.09.12 22:32) [10]
Понял, попробую заполнять нулями сначала.
← →
DevilDevil © (2012-09-19 23:33) [13]> dm_member © (19.09.12 22:55) [12]
ну и вопросики ты задаёшь )
1) чтобы обращаться к памяти по указателю, нужно чтобы указатель указывал на конкретные данные. Либо на глобальную переменную, либо на локальную переменную, либо на переменную вообще где-то, либо выделяя память в Куче (динамическая память)
2) выделить память в куче можно двумя способами.
GetMem (удаление FreeMem)
New (удаление Dispose)
GetMem просто выделяет память, New выделяет память и инициализирует сложные данные
3) сложные данные - это особые типы данных, которые особым образом инициализируются и удаляются внутри Delphi, без явного участия программиста. К сложным типа относят строки (кроме ShortString), Variant, Interface, динамические массивы. Или структуры/массивы, которые внутри себя содержат сложные типы.
4) если выделяешь память по New(), то автоматическая инициализация произойдёт без твоего участия. Если по GetMem, то тебе надо занулить сложные переменные. Либо FillChar/ZeroMemory, либо в твоём случае:GetMem(pointer(r), sizeof(TRec));
pointer(r.s) := nil;
pointer(r.arr) := nil;
5) важно понимать, что сложные типы должны быть очищены. Каким-либо образом. Иначе будут утечки памяти.
← →
dm_member © (2012-09-20 07:23) [14]
> DevilDevil © (19.09.12 23:33) [13]
ну и вопросики ты задаёшь )
Да, с указателями я мало знаком.
Советы помогли. Можно предварительно обнулять память или использовать new/dispose. Я дальше почитаю об этом что-нибудь, чтобы лучше понимать.
← →
MBo © (2012-09-20 07:29) [15]>Да, с указателями я мало знаком.
А в данном случае они на самом деле нужны?
← →
dm_member © (2012-09-20 07:48) [16]
> MBo © (20.09.12 07:29) [15]
> >Да, с указателями я мало знаком.
> А в данном случае они на самом деле нужны?
Да, нужны. Каждая запись должна быть связана с некоторыми другими записями.
← →
dm_member © (2012-09-20 07:49) [17]Спасибо за помощь всем.
← →
Dimka Maslov © (2012-09-20 08:02) [18]А потом мы получим утечку памяти. Надо пользоваться TList и TStringList.
← →
MBo © (2012-09-20 08:09) [19]>Да, нужны. Каждая запись должна быть связана с некоторыми другими записями.
Из этого не следует необходимость.
В первую очередь стоит подумать о более высокоуровневых средствах рализации проблемы, например, о предложении в [18]
← →
DevilDevil © (2012-09-20 09:27) [20]> Dimka Maslov © (20.09.12 08:02) [18]
> MBo © (20.09.12 08:09) [19]
а как же связанные списки, деревья ?
чувак по моему на правильном пути
← →
MBo © (2012-09-20 09:37) [21]>DevilDevil
Связанные списки имеют весьма ограниченную область применения.
Для деревьев - да, такая техника вполне подходит (хотя и необязательна).
А насчёт правильного пути - тут трудно судить. Если задачу можно решить готовыми средствами быстро и без ошибок - то зачем хардкорный путь проходить?
← →
DevilDevil © (2012-09-20 09:42) [22]> MBo © (20.09.12 09:37) [21]
ну во-первых, автор сказал что ему нужна вложенность
а во-вторых, реализацию в целях образования никто не отменял
← →
Dimka Maslov © (2012-09-20 09:55) [23]
> а как же связанные списки, деревья
Дело не а связанных списках и деревьях, а в финализации строк и динамических массивов, которая автоматически может и не случиться. Особенно при неправильном подходе к мероприятию.
← →
DevilDevil © (2012-09-20 10:22) [24]> Dimka Maslov © (20.09.12 09:55) [23]
Dispose ?
и см [13]
← →
Dimka Maslov © (2012-09-20 10:40) [25]Банальный Move или обнуление указателя и готово
← →
Плохиш © (2012-09-20 11:17) [26]В описании типа record заменить на class и наступит счастье у ОРД.
Хотя для наступления счастья всё-таки придётся почитать описание используемого языка.
← →
dm_member © (2012-09-20 19:02) [27]
> MBo © (20.09.12 08:09) [19]
> >Да, нужны. Каждая запись должна быть связана с некоторыми
> другими записями.
>
> Из этого не следует необходимость.
Выбор уже сделан ранее в пользу указателей по ряду причин и я намерен его придерживаться, а не перебегать от одного варианта к другому без весомых причин. Иначе это превратится в исследовательский проект по анализу плюсов и минусов тех или иных методов построения системы данных.
Могу сказать пока только, что необходимость использования TList или TStringList точно ни из чего не следует.
← →
Inovet © (2012-09-20 19:17) [28]> [27] dm_member © (20.09.12 19:02)
Классы придуманы как раз для большего удобства.
← →
Dimka Maslov © (2012-09-20 19:21) [29]
> Могу сказать пока только, что необходимость использования
> TList или TStringList точно ни из чего не следует
Следует хотя бы из того, что с ними а) нет проблем с выделением, освобождением памяти, финализацией, меньше проблем с утечками б) нет проблем с чтением, записью в) класс лучше чем record г) Strings.LoadFromFile/SaveToFile лучше чем BlockRead/BlockWrite, которые суть рудименты для обратной совместимости с кодом 20-30 летней давности.
А для построения системы данных давно придуманы базы данных (да, именно для этого) или на худой конец XML, который через IXMLDocument делает всё, что надо. Но для этого следует таки прочитать про новые веяния, чтобы не получалось почти как в одной пестне "ring-a-ring-a Rosie, as the light decays, I remember Delphi in the rare auld times"
← →
dm_member © (2012-09-20 20:25) [30]
> Dimka Maslov © (20.09.12 19:21) [29]
> Следует хотя бы из того, - исходя из содержания моей идеи, не следует ни из чего
Далее по пунктам:
а) повышение эффективности работы с памятью - вопрос будущего и точно не средствами TStrings.
б) думаю, что это решаемо и без замены агрегатов :)
в) одного только "класс лучше чем record" мало для принятия конкретного решения. В целом, не спорю, но на данном этапе record полностью устраивает.
г) ещё раз, TStringList со своими LoadFrom/SaveTo ничем не помогут. Объект представляет из себя не просто список строк, а совокупность полей с разнотипными данными с динамически изменяемыми размерами, которые все надо записывать в один файл. Объект ссылается на другие такие же объекты, которые в свою очередь ссылаются на прочие и т.д. Это огромная сеть динамических, определённым образом взаимосвязанных объектов. Кроме того, BlockRead/Write я не использую.
И кстати, это не база данных и не субд.
Мы так можем долго рассуждать, что лучше.
← →
Dimka Maslov © (2012-09-20 21:06) [31]
> Объект представляет из себя не просто список строк, а совокупность
> полей с разнотипными данными с динамически изменяемыми размерами,
> которые все надо записывать в один файл. Объект ссылается
> на другие такие же объекты, которые в свою очередь ссылаются
> на прочие и т.д. Это огромная сеть динамических, определённым
> образом взаимосвязанных объектов
Судя по описанию, это таки база данных. И всё это легко пишется на Xml. И даже через TStringList. А использовать записи с финализируемым типом здесь - прямая дорога к утечкам памяти и конфликтам доступа. А также к ошибкам чтения-записи, из-за которых вся огромная сеть упадёт и восстановить её будет невозможно. В отличие от годами проверенных систем и алгоритмов.
← →
Jeer © (2012-09-20 21:54) [32]"Неотъемлемое свойство человеков - изобретать очередной велосипед и падать, падать, падать" (С)
Да, некоторые, таки обучаются не падать :)
С годами.
← →
Baks (2012-09-20 23:04) [33]
> dm_member ©
Прочти хотя бы это: http://podgoretsky.com/Redir.aspx?id=155&DownloadFile=~/ftp/Docs/Delphi/D5/Delphi5vol1.pdf
← →
dm_member © (2012-09-21 10:43) [34]Удалено модератором
← →
Игорь Шевченко © (2012-09-21 10:48) [35]
> Объект представляет из себя не просто список строк, а совокупность
> полей с разнотипными данными с динамически изменяемыми размерами,
> которые все надо записывать в один файл. Объект ссылается
> на другие такие же объекты, которые в свою очередь ссылаются
> на прочие и т.д. Это огромная сеть динамических, определённым
> образом взаимосвязанных объектов
Форма (TForm которая) тоже представляет из себя "совокупность полей разнотипными данными, которую надо записывать в файл".
Для наследников TComponent в Delphi придуман механизм сериализации. Готовый.
TStream.ReadComponent, TStream.WriteComponent
← →
dm_member © (2012-09-21 11:00) [36]
> Dimka Maslov © (20.09.12 21:06) [31]
>
Судя по описанию, это таки база данных. И всё это легко пишется на Xml. И даже через TStringList. А использовать записи с финализируемым типом здесь - прямая дорога к утечкам памяти и конфликтам доступа. А также к ошибкам чтения-записи, из-за которых вся огромная сеть упадёт и восстановить её будет невозможно. В отличие от годами проверенных систем и алгоритмов.
Это не база данных по следующим причинам:
1) проект не имеет цели удовлетворения информационных потребностей пользователя и не содержит средств вывода агрегированной информации;
2) информация не относится к какой-либо конкретной предметной области;
3) информация не имеет чёткой схемы построения, взаимосвязи носят гибкий характер и могут меняться, усложняться, упрощаться. И т.д.
← →
Компромисс © (2012-09-21 11:35) [37]dm_member © (21.09.12 11:00) [36]
Кроме реляционных СУБД существуют еще и объектные. Cache, например.
← →
Inovet © (2012-09-21 12:12) [38]Учить не хочу - то что мне надо и так знаю.
Советы ваши не слушаю - они неправильные.
Хочу делать свою поделку, но вы мне помогите.
С чего ты взял, что классы это только TList и прочие готовые? Тебе говорят - сделай свой. Ты в ответ - Нет, мне не надо, мне не подходит, я хочу посложнее сделать с косяками, чтобы потом выгребать. Помогайте мне. И это даже не вникнув в смысл совета.
Снова хамить начнёшь? Так я не для того пишу этот пост, чтобы тебя задеть.
← →
dm_member © (2012-09-21 13:13) [39]
> Inovet © (21.09.12 12:12) [38]
> Учить не хочу - то что мне надо и так знаю.
> Советы ваши не слушаю - они неправильные.
> Хочу делать свою поделку, но вы мне помогите.
Я просто задал вопрос и хотел, чтобы мне подсказали, в чём может быть проблема в данном КОНКРЕТНОМ случае. А вместо этого некоторые считают своим долгом сказать, что моей проблемой является мой выбор, "неправильный" с их точки зрения. Это мой выбор, а если у кого-то другой взгляд на подход к идее (которую они даже не знают), это их личное дело.
← →
Плохиш © (2012-09-21 13:56) [40]Гланды можно вырезать не только через рот.
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.06 c