LINUX.ORG.RU

Список на Паскале


0

0

Просьба не относиться ко все очень серьезно :)

Всю сознательную жизнь работал с Си, не так давно начал проникаться Си++ и все в том же роде, но возникла идея сбацать что-нибудь на Паскале. Ну и первым делом (что может быть проще?) решил заделать списочек.

На Си я бы поступил просто:
struct __Node{
struct __Node *next, *prev;
void *item;
};
typedef struct __Node Node;
typedef Node* List;
И был бы счастлив.

Теперь Паскаль: работа с указателями там (на мой взгляд) жуткая и не доставляющая эстетического удавольствия. Линки на следующий и предыдущий элементы делаются, но как быть с данными? Уточню, что использую FreePascale, который вроде бы соответствует TurboPascale 7, и под рукой имею описание Турбо Паскаля 5 (книжка Фаронова, написанная на основе лекций). Элегантное решение этой задачи есть?

anonymous

Не понял, чем здесь FreePascal принципиально от Си отличается.

type
  TNode=^Node;
  Node=record
     next,prev:TNode;
     item:Pointer;
  end;

var
  A:TNode;
BEGIN
  //Проверку успешности выделения памяти не делаем.
  New(A);
  GetMem(A^.item,1024);//Зарезервировали 1Кб.
  A^.prev:=nil;
  New(A^.next);
  A^.next^.prev:=A;
  A:=A^.next;

END.

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

anonymous_incognito ★★★★★
()
Ответ на: комментарий от anonymous_incognito

Вобщем-то так я себе и представлял. Я сейчас не готов привести пример (что-то с памятью моей стало), но проблема у меня возникла с тем, чтобы получить адрес переменной. Выход я нашел в использовании PTR(), SEG() и еще какой-то функции, дающей смещение (имени ее не помню). Более элегантного способа нет?

И еще вопрос: а динамический массив там сделать можно? В имеющемся у меня описании все это выглядит очень громоздко. А если точнее, то не понятно, как обращаться к памяти выделенной GETMEM(): я еще не пробовал, но получится это сделать обычным Си-шным образом через индекс массива?

anonymous
()
Ответ на: комментарий от anonymous

> проблема у меня возникла с тем, чтобы получить адрес переменной
var a: integer;
ptra: ^integer;
ptra := @a;

> И еще вопрос: а динамический массив там сделать можно?
На Паскале это очень больно. В Delphi (и, видимо, freepascal) можно юзать setLength() AFAIR.

phoenix ★★★★
()
Ответ на: комментарий от phoenix

Мда, что-то у меня в книжке ни слова про @. Ок, спасиобо.

С setLength() попробую, может, и получится. Только напомните, как там надо объявить такой массив, так, по-моему:

var
arr: array of integer;

?

И формат setLength такой: "setLength(arr, size);"?

anonymous
()

Вроде можно делать так:
type
TArray = array[0..65535] of Byte;
PArray = ^TArray;

var
a: PArray;
begin
GetMem(a, length);
...
FreeMem(a);
end;

В ТурбоПаскале будет ограничение на размер типа TArray, вроде в FreePascal такого быть не должно.
Ну можно и SetLength использовать видимо. Формат такой, только вроде в Дельфи ещё можно многомерные массивы использовать вроде
var a: array of array of Integer;
begin
SetLength(a, 4, 5);
...

Legioner ★★★★★
()
Ответ на: комментарий от anonymous

> Выход я нашел в использовании PTR(), SEG() и еще какой-то функции,
дающей смещение (имени ее не помню). Более элегантного способа нет?

Это связано не со спецификой паскаля в его турбопаскалевом виде, а с 
"оригинальной" системой адресации памяти 8086 процессора по типу 
(сегмент*16+смещение).

А вообще-то адрес переменной можно узнать путём операции @, например:

Var a:integer;
    b:^real;

.....
b:=@a;

Можно использовать этот механизм для ручного создания чего-то ООП-
шного, например:

type
  proc=procedure (var a:integer);
  
procedure t1(var k:integer);
begin writeln(k+1) end;

procedure t2(var m:integer);
begin writeln(m+2) end;

var
  t:proc;
  n:integer;
BEGIN
  Write('n = ');Readln(n);
  if n<0 then t:=@t1 else t:=@t2;
  t(n);
END.

Специально проверил FreePascal'ем -- работает, но в TP(BP) и Delphi,
смутно помнится, что надо писать не t:=@t1, а t:=t1, но поскольку
работаю я в Linux'е и под рукой только FreePascal, то я проверил
именно приведённый код -- он компилируется и работает.


> И еще вопрос: а динамический массив там сделать можно?

Можно, хотя прямых механизмов и нет, но я делаю так:

type
  dyn=array[0..0] of integer;
  tdyn=^dyn;
var
  a:tdyn;
  i,n:integer;
BEGIN
 {$R-} //Отключаем проверку индексов.
 //В учебных целях выделение памяти тоже не проверяем.
  Write('n= ');Readln(n); if n<1 then exit;
  GetMem(a,n*sizeof(dyn));
  for i:=0 to pred(n) do a^[i]:=i mod 3; //Операция i mod 3 сугубо для примера.
  for i:=0 to pred(n) do Writeln('a[',i,'] = ',a^[i]);
  FreeMem(a);
END.

Важно: Если память выделяется через New, то чиститься должна Dispose,
если через GetMem, то потом FreeMem.

Для работы с типами данных также полезно использовать слово absolute,
например:

type
  arr=array[1..10] of byte;
procedure w (var d);
var
  x:arr absolute d;
  i:integer;
begin 
  for i:=low(arr) to high(arr) do writeln(i,':',x[i],' ');
end;

var
  t:Extended;//10 - байтовый вещественный тип для x86
  a:arr;
  i:integer;
BEGIN
  t:=Sqrt(2);
  for i:=1 to 10 do a[i]:=i;
  w(t);//Напечатает 10 байт внутреннего представления корня из 2 для extended типа.
  w(a);//Напечатает значения массива a.
END.

anonymous_incognito ★★★★★
()
Ответ на: комментарий от anonymous

> И формат setLength такой: "setLength(arr, size);"?

Да, только SetLength и такие явные динамические массивы появились впервые в Delphi и только с 4 -ой версии, а в FreePascal'е со второй версии.

anonymous_incognito ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.