Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Object Pascal: кроссплатформенные технологии > Динамический массив


Автор: Proxin 2.3.2010, 15:26
делаю массив так:
Код

type ma:array[0..0] of integer;mp:^ma;
var m:mp;
begin
getmem(m,4*sizeof(integer));
// и так далее, данными заполняю.

А как добавить ещё одни элемент, чтобы размер массива стал на одни элемент больше? Пока придумал только делать через функцию со вторым вспомогательным массивом, но наверняка есть какой-то способ проще. Пишу на borland tp7.0.

Автор: ФедосеевПавел 2.3.2010, 16:20
Нет. Проще никак. Можно только выделять вспомогательный массив не на один элемент больше, а  с небольшим запасом (на 5, на 10, на 100).

Автор: Proxin 2.3.2010, 16:36
это печально. получается, в турбе нет нормальных динамических массивов.
спасибо.
и ещё вопрос - как узнать индекс последнего элемента в массиве? high не подходит.

Автор: ФедосеевПавел 2.3.2010, 18:53
Но ты же сам его определяешь. Храни в отдельной переменной.

Автор: volvo877 2.3.2010, 19:09
Proxin, больше НИКОГДА так не делай. Ты потерял возможность обращаться к какому-либо элементу дин.массива, отличному от 0, при включенном режиме {$R+} (а этот режим при отладке вообще не вздумай выключать, если хочешь, чтобы программа работала, и выдавала правильные, а не какие-попало результаты). Смотри:
Код
{$R+}
type
  ma = array[0..0] of integer;
  mp = ^ma;

var
  m: mp;
  i: integer;
begin
  getmem(m,4*sizeof(integer));
  for i := 0 to 3 do
  begin
    m^[i] := i;
  end;
end.
Должно работать, да? А не будет:
Код
Turbo Pascal  Version 7.0  Copyright (c) 1983,92 Borland International
Runtime error 201 at 0000:0040.
, потому как ты описал тип-массив с индексами от 0 до 0, и тут же выходишь за пределы диапазона.

Я делаю так:
Код
{$R+}
type
  T = integer;
  ma = array[0 .. pred(65520 div sizeof(T))] of T;
  mp = ^ma;
И волки сыты (имеешь возможность обращаться к любому элементу массива) и овцы - целы (Range Check не отключен, и позволит тебе ловить другие вылеты за границы диапазона в программе).

Добавлено через 10 минут и 18 секунд
Цитата(Proxin @  2.3.2010,  14:26 Найти цитируемый пост)
Пока придумал только делать через функцию со вторым вспомогательным массивом
Навскидку - как минимум два варианта, избавляющих тебя от доп. массива и постоянных перераспределений памяти:
1) напиши свою реализацию через связный список, тогда будешь добавлять/удалять элементы легко
2) воспользуйся TCollection для хранения данных вместо дин. массива.

Третий вариант (перейти на FPC, где динамические массивы, и не только, есть) не озвучиваю, хотя очень хочется smile

Автор: Proxin 2.3.2010, 21:49
Можно пример реализации через связанные списки, или где почитать?

Автор: Frees 5.3.2010, 23:29
ma = array of integer;
и
SetLength()

или так только в делфи?

Автор: volvo877 5.3.2010, 23:46
Цитата(Frees @  5.3.2010,  22:29 Найти цитируемый пост)
или так только в делфи?
Так - в любом 32 битном компиляторе. В Turbo Pascal-е вот так:
Код
type
  T = integer;

type
  ptlistitem = ^listitem;
  listitem = object
    info : record
      index: integer;
      value: T;
    end;
    next : ptlistitem;

    constructor init(the_index: integer);
    destructor done;
  end;

  tdynarr =
  object
  private
    len: integer;
    head, tail: ptlistitem;
    function At(atIndex: integer): ptlistitem;
    procedure append;

  public
    constructor init;
    destructor done;

    procedure put(atIndex: integer; value: T);
    function get(atIndex: integer): T;

    procedure setlength(the_len: integer);
  end;

constructor listitem.init(the_index: integer);
begin
  info.index := the_index; info.value := 0;
  next := nil;
end;
destructor listitem.done;
begin end;


constructor tdynarr.Init;
begin
  head := nil; tail := nil;
  len := -1;
end;
destructor tdynarr.Done;
var p, pt: ptListItem;
begin
  p := head;
  while p <> nil do begin
    pt := p;
    p := p^.next;
    dispose(pt, done);
  end;
end;

procedure tdynarr.append;
var
  new_elem: ptListItem;
begin
  inc(len);
  new_elem := new(ptListItem, init(len));

  if head = nil then head := new_elem
  else tail^.next := new_elem;

  tail := new_elem;
end;

procedure tdynarr.put(atIndex: integer; value: T);
var p: ptlistitem;
begin
  p := At(atIndex);
  if p <> nil then p^.info.value := value;
end;
function tdynarr.get(atIndex: integer): T;
var p: ptlistitem;
begin
  get := -1; { <--- Error !!! }
  p := At(atIndex);
  if p <> nil then get := p^.info.value;
end;

procedure tdynarr.setlength(the_len: integer);
begin
  while len < the_len do append;
end;
function tdynarr.At(atIndex: integer): ptlistitem;
var p: ptlistitem;
begin
  if atIndex > -1 then p := head else p := nil;

  while (p <> nil) and (p^.info.index < atIndex) do begin
    p := p^.next;
  end;
  At := p;
end;

var
  arr: tdynarr;
  i: integer;

begin
  arr.init;
  arr.setlength(10);

  for i := 0 to 9 do
  begin
    arr.put(i, 3 * i);
  end;
  for i := 0 to 9 do
  begin
    writeln(arr.get(i));
  end;
  arr.done;
end.

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

Proxin, почему не рассматриваешь второй и третий предложенный варианты?

Автор: Proxin 6.3.2010, 10:57
спасибо большое.
почему не рассматриваю другие варианты? потому что посмотреть охота как это делается на ранних компиляторах. а с tcollection -  не знаю, как реализовать. почитать где про них можно?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)