Страница 1 из 2

Освобождение выделанной памяти

Добавлено: 28 мар 2009, 22:11
Esgal
Допустим, мне дан довольно большой файл (count строк, но не больше 100000), состоящий из строк произвольной длинны (допустим до 200)

Я выделяю память под массив и под строки

Код: Выделить всё

const count=32000;
type PStr=^string;
       Arr=array[1..1] of PStr;
       PArr=^Arr;
var buf:string;
     i:1..100000;
     DArr:PArr;
begin
  ...
  {Тут было согласование файла f}
  ...
  GetMem(DArr,Count*SizeOf(PStr));
  for i:=1 to count do
  begin
    readln(f,buf);
    GetMem(DArr^[i],length(buf)+1);
    DArr^[i]^:=buf;
  end;
  ...
  {теперь я работаю с полученной структурой, и когда работа заканчивается, приходит время освобождать память}
  ...
end.
Два вопроса

1)Правильно ли я всё сделал;
2)Как теперь проще всего освободить память?
Неужели придётся заново проходить оп массиву, проверять размер каждой из строк, и выгружать каждую строку отдельно?

Re: Освобождение выделанной памяти

Добавлено: 28 мар 2009, 23:05
Naeel Maqsudov
1) Формально все правильно, но может быть сам подход неправильный? Вцелом задача какова?

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

Подумайте, может стоит отказаться от хранения string в динамическом контексте и перейти на PChar?

Re: Освобождение выделанной памяти

Добавлено: 28 мар 2009, 23:49
Esgal
Подумайте, может стоит отказаться от хранения string в динамическом контексте и перейти на PChar?
как это на Pchar

объясните пожалуйста если не затруднит...

задача:
файл состоит из n+1 строк
в первой строке файла число n (1<=n<=100000)
В n следующих срок, строки произвольной длинны

Нужно считать строки со 2 по n+1 в память, при этом нужно занять минимальное количество памяти
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
я тут поэксперементировал

почемуто даже если вообще не выделять память под строки, всё перкрасно работает... т.е.

Код: Выделить всё

  GetMem(DArr,Count*SizeOf(PStr));
  for i:=1 to count do
  begin
    readln(f,buf);
    {раньше в этой строке я выделял память под строку}
    DArr^[i]^:=buf;
  end;
этот код работает... строки из массива DArr^^ прекрасно выводятся на экран, кто объяснить суть явления?
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
Извените за много сообщений, оказывается вышеприведённый код работает только для маленького числа строк (и всё равно непонятно почему)

Re: Освобождение выделанной памяти

Добавлено: 29 мар 2009, 10:50
Naeel Maqsudov
То что этот код работает это просто счастливая случайность. Так как DArr^ - это случайное число. Если его расмотреть как указатель, то оно указывает на случайное место в памяти (а не на место, которое было специально выделено).
Следовательно, DArr^^:=buf; затирает какие-то данные где-то в памяти.
Т.е. даже если это работет, это грубейшая ошибка.

&quot писал(а):как это на Pchar


На какой версии Pascal вы пишете? Начиная с 7 есть специальные функции, для работы с ASCIIZ (null-terminated) строками. Они сами обеспечивают уборку мусора. И есть стандартный тип PChar - указатель на ASCIIZ-строку.

Если используется Pascal 5, то обратите внимание на стандартные процедуры
Mark(p) и Release(p)
Запомнив состояние "кучи" по Mark можно одной командой Repease привести ее в исходное сотояние, освободив всё, что выделялось.

&quot писал(а):задача:
файл состоит из n+1 строк
в первой строке файла число n (1<=n<=100000)
В n следующих срок, строки произвольной длинны
Нужно считать строки со 2 по n+1 в память, при этом нужно занять минимальное количество памяти


Ну размер файла Вы знаете (можете определить), не так ли?
Выделите память одним куском. Считайте весь файл целиком, не тратя память на указатели и фрагментирование памяти.

Дальше можно превратить этот текст как в набор строк, идущих подряд.
Если заменить переводы строк нулями, то получатся ASCIIZ строки.
Если вставить перед каждой строки ее длину, то LASCII, соответствующие паскалевскому String. (Когда первый байт - это длина).

Re: Освобождение выделанной памяти

Добавлено: 30 мар 2009, 11:18
atavin-ta
&quot писал(а):)Как теперь проще всего освободить память?
Неужели придётся заново проходить оп массиву, проверять размер каждой из строк, и выгружать каждую строку отдельно?
[syntax=Delphi]
for i:=1 to count do
FreeMem(DArr^);
[/syntax]

Re: Освобождение выделанной памяти

Добавлено: 30 мар 2009, 13:01
BBB
К слову, если писать на Паскале, то оператор:
GetMem(DArr,Count*SizeOf(PStr));
не прокатит при (Count >= 16384). Т.е. SizeOf(PStr) = 4, а не в 32-битных приложениях нельзя выделить кусок памяти, превышающий размером 64 К.
Не скаже, что именно произойдет в данном случае: или произведение (Count*SizeOf(PStr)) по переполнению даст небольшой результат, и память выделится, но явно меньшего размера, или GetMem даст ошибку. Вообще, надо смотреть тип параметра GetMem. Если это word, то явно должно произойти переполнение его значения.

Re: Освобождение выделанной памяти

Добавлено: 30 мар 2009, 20:05
Esgal
BBB, я тоже думал об этом...

А есть ли вообще способ, адресовать 100 000 строк в Паскале?
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
atavin-ta, резвеу freemem второй параметр не обязателен?

Re: Освобождение выделанной памяти

Добавлено: 31 мар 2009, 09:39
atavin-ta
&quot писал(а):резвеу freemem второй параметр не обязателен?
Точно не помню, но мо-моему нет.

Re: Освобождение выделанной памяти

Добавлено: 31 мар 2009, 15:27
Naeel Maqsudov
&quot писал(а):у freemem второй параметр не обязателен?
Параметр обязателен, что кажется нелогичным. Ведь кучей распоряжается все равно внутренний менеджер кучи.... Надо смотреть system.pas....
&quot писал(а):есть ли вообще способ, адресовать 100 000 строк
Если целым куском нельзя, то надо более мелкими кусками.
Связанные списки, например.
Или (если не хочется дробить данные так мелко) кусками по чуть меньше 64К, но надо будет обработать пограничные условия. Т.е. индекс элемента должен пересчитываться в номер куска и индекс элемента в куске.

Re: Освобождение выделанной памяти

Добавлено: 01 апр 2009, 05:55
atavin-ta
&quot писал(а):Если целым куском нельзя, то надо более мелкими кусками.
Связанные списки, например.
Или (если не хочется дробить данные так мелко) кусками по чуть меньше 64К, но надо будет обработать пограничные условия. Т.е. индекс элемента должен пересчитываться в номер куска и индекс элемента в куске.
Согласен, но только в том случае, когда целиком действительно нельзя или нецелесообразно. И кто сказал, что блок может быть не более 64 к? Можно использовать и 32 разряда.