Помощь - Поиск - Пользователи - Календарь
Полная версия: Как создать резиновый массив?
Форум «Всё о Паскале» > Pascal, Object Pascal > Теоретические вопросы
Tonic
Синтаксиса не знаю, поэтому объясняю на пальцах:

массив[заранее_не_знаю_сколько_элементов]
i:=0
начало_цикла
 i:=i+1
 элемент_массива[i] = ввод_с_клавы(неск._букв)
 если элемент_массива[i] = 'особый_символ' то
   выйти из цикла
конец_цикла

Вопрос в том, как бы мне менять границы массива по ходу исполнения программы? Есть ли какие варианты? Может быть, использовать не массивы, а ещё что-то?
Vit
В Дельфи легко, в Паскале - не помню - ввели они поддержку открытых массивов или нет. Если нет, то тогда нельзя, можно только через динамическое выделение памяти (оператор new)
ozzy
В тмт есть open arrays
Tonic
А что насчет new? Я бы непротив, да только непонятно как. В книжке написано, что массив все равно заранее надо определить.

Можно ли сделать что-то типа:

a:char;
j:=0;
repeat
 j:=j+1;
 ...
 new(i[j]));
 ReadLn(a);
 ...
until a='q'

Дело в том, что я к динамической памяти обратился сразу, но что-то несрослось. Как можно отодвигать с помощью new границу массива? Или можно создать с помощью new некую абстрацию типа, скажем, 3-х мерного массива?
Alex
В уроке про массивы на pascal.dax.ru посмотри, там есть динамическое выделение памяти под массивы.
Tonic
Все, что я там понял, так это то, как создать массив, занимающий в памяти более сегмента. Это без проблем, согласен. Но массив, хоть и здоровый, все равно нужно объявить. Я же пытаюсь получить ответ на вопрос: как создать конструкцию, к которой можно обращаться с таким же удобством, как к массиву, и которая меняла бы количество своих элементов и границы по ходу программы? Просто скажите: "такое невозможно", и я отвяжусь, или процитируйте кусок кода, который был бы понятен дилетанту в паскале.
___ALex___
говоришь как изменить число элементов массива?
пишешь тип массива по максимуму(то есть с макс-ым числом элементов)удаляешь предыдущий потом создаёшь новый нужно размерности
(GetMem юзай)
при необходимости заполняешь его значениями из предыдущего массива
Some1
Что же до системы с New:
Значит так - каждый элемен массива должен распологаться динамически в памяти, и содержать в себе:
1. Само значение элемента (строка, число, не важно...)
2. Указатель, где в памяти находится следующий элемент.

Таким образом зная указатель на самый первый элемент массива можно прочитать и его значение, и узнать, где находится следующий элемент массива, и так до самого конца. Изменять размер массива можно динамически - это как open arrays, тоесть - хочешь - добавь в конец новый элемент, а в предыдущем укажи ссылку на него, хочешь, вставь между двумя элементами массива ещё один (из предыдущего сделай ссылку на него, а у него сделай ссылку на следующий). Важно, то что при таком методе необходимо в отдельной переменной хранить ссылку на самый первый элемент массива, иначе можно просто потерять весь массив в памяти :)
Вот тебе пример:
Код
Type
  PData = ^TData; {указатель на элемент массива}
  TData = record {Сам элемент массива}
     N: Longint; {Число - содержимое элемента}
     Next: PData; {Указатель на следующий элемент массива}
  End;
Var
 Temp,First: PData; {Два элемента, один из них для работы с текущим элементом, другой для указания, где начинается массив}
 p:word;
begin
 temp:=nil; {укажем, что первый элемент пока не заполнен}
 Repeat
    ReadLn(X);
    If X = 0 then Break; {Если мы ввели ноль, то всё.. больше элементов не надо}
    If temp = nil then {если это самый первый элемент, то...}
    begin
      New(temp); {Создадим его}
      first:=temp; {Запомним где он находится в first}
    end else {Иначе это уже не первый}
    begin
      New(temp^.Next); {Создадим новый}
      temp:=Temp^.next; {Перенесёмся в него. temp теперь уже новый}
    end;
    temp^.N := X; {Занесём в него значение}
    data^.Next := nil; {Укаджем, что следующего ещё нет}
 Until False;
 {Теперь выведем все значения, чтоб тебе было более понятно}
 temp:=first; {Установим первый элемент}
 p:=0; {Номер текущего элемента}
 while temp<>nil do {Пока мы находим элемент}
 begin
   inc(p); {наращиваем номер текущего элемента}
   writeln('a(',p,')=',temp^.N); {выводим его}
   temp:=temp^.Next; {Переносимся в следующий элемент}
 {Если следующий элемент nil, то temp тоже странет nil, и цикл while закончится}
 end;
end.
___ALex___
Some1:
хе односвязный список проповедуешь,
фигня он)слишком маленькая скорость доступа
хотя для мелких массивов это не заметишь
Some1
Я не проповедую,  и не большой любитель односвязный массивов. Просто даю человеку необходимую информацию.
Если ты посмотришь на первое сообщение, то там у него в предпологаемом алгоритме присутствует ввод с клавиатуры, который я думаю уже предплолгает, что массив будет "относительно" не большой.
Ант
Я это делал так:
прописываешь процедуру, а в ее var-е создаешь массив от 1 до какого-то n, которое вводишь как параметр процедуры.
Обычно работало, но только все равно остаеться ограничение памяти.
8)
Altair
Резиновым массивом иногда называют динамические структуры данных: стеки, очереди и т.д
если неизвестно, сколько элементов будет, лучше использовать однонаправленный список.
Nemo
Зачем самим мучаться с динамическим выделением памяти, когда есть все готовое? Просто работай с массивом как с коллекцией: тип TCollection модуля Objects. Очень мощная штука.
Atos
Да, с обычным массивом такое делать нельзя. С динамическим , по-моему, тоже. Разве что каждый раз, когда надо менять размер массива, создавать новый и копировать в него влезшие элементы старого smile.gif . В голову лезут всякие списки, стеки,... деревья smile.gif . Пожалуй, есть одна более подходящая идея: реализовать многомерный динамический вектор. Это указатель на массив примерно [0..9] указателей на массив [0..9] указателей... ...на массив [1..10] элементов. Должно храниться общее число элементов. В таком n-мерном векторе может поместиться до 10^n элементов. Доступ, скажем, к 143-му элементу будет выглядеть p^[0]^[0]^[1]^[4]^[3]. Это будет намного быстрее, чем в списке. Памяти на вектор уйдёт больше, чем на обычный массив, но не так уж намного. Дело в том, что она не выделяется сразу для всех 10^n эл-тов, а по мере их добавления, так что, если не ошибаюсь, для хранения m элементов потребуется m div 10 + m div 100 +... + m div 10^(n-1) + n указателей. Менять границы можно new или delete соответствующего кол-ва указателей. Конечно, реализация несколько сложна, но всё вполне нормально пишется.
SKVOZNJAK
Цитата(Tonic @ 19.02.03 13:06)
Как можно отодвигать с помощью new границу массива? Или можно создать с помощью new некую абстрацию типа, скажем, 3-х мерного массива?

Какая разница NEW, или что-то ещё? И разве без списков, коллекций, объектов нельзя написать прогу небольшого размера ;) Главное, чтобы доступ к памяти был, а уж для облекчения доступа к нему завсегда функцию написать можно. Самый прикольный вариант, когда для инициализации массива, изменения размеров, чтения, записи используется одна и та же функция smile.gif
Код

FUNCTION FDSGDS(FDS,POKE,PEEK:BYTE; ADREES:LONGINT):BYTE;
....................
BEGIN
CASE FDS OF
1: ................
2: ..................
3:..........................
4:................................
.....................
END;


Вместо не нужных параметров пишутся фиктивные - нули, или любой другой мусор. На какие параметры реагировать и какую продукцию выдавать smile.gif ф-ция решает исходя из ключа FDS - инициализирует или закрывает новые сегменты памяти, читает, записывает или форматирует диск ;) Конечно, преподы за такой подход голову оторвут, или что-нибудь ещё <_< Но штука прикольная и полиморфная.

ЗЫ: Без ГОТО такая конструкция выглядит как соль без сахара.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.