Указатели и односвязные списки в Free Pascal

Всем привет!

В настоящее время я решаю задачу создания односвзяного списка c использованием указателей применительно к потоку стандартного ввода в языке Free Pascal.

Условие задачи:

Написать программу, которая читает целые числа из потока стандартного ввода до возникновения ситуации "конец файла", после чего дважды печатает все введенные числа в том порядке, в котором они были введены.Количество чисел заранее неизвестно, вводить явные ограничения на это количество запрещается.

Мой код:

   program InputStreamNumbers;
   type
       itemptr = ^item;
       item = record
               data: Integer;
               next: itemptr;
       end;
   var
       first, last, tmp: itemptr;
       n: Integer;
   begin


       while not SeekEof do    {        цикл чтения чисел }
       if first = nil then     { делаем список корректно пустым! }
       begin
               new(first);
               last := first           { создали }
       end
       else
       begin
               new(last^.next);
               last := last^.next
       end;
       last^.data := n;
       last^.next :=nil;

       while tmp <> nil do             {до конца}
       begin
               writeln(tmp^.data);
               tmp := tmp^.next        { переход к следующему элементу}
       end
   end.

В данной задаче я использую два указателя first и last, а также промежуточный tmp

Ниже приведена моя схема решения задачи:

   first                                  last
     |                                      |
     v                                      v
   item.next -> item.next -> item.next -> item.next = nil
       .data        .data        .data        .data

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

 Runtime error 216 at $0000000000401124
  $0000000000401124
  $000000000040104C

В документации по FreePascal

    https://www.freepascal.org/docs-html/user/userap4.html#x189-196000D

написано следующее:

    >216 **General Protection fault**
    >The application tried to access invalid memory space. This can be caused by 
    >several problems:
    >1.
    >Dereferencing a nil pointer.
    >2.
    >Trying to access memory which is out of bounds (for example, calling move 
     with 
     an invalid length).

Не могу понять, почему компилятор ругается на разыменовывание указателей.


Ответы (1 шт):

Автор решения: AOIPKN

В вашем решении не нужно использовать дополнительный временный указатель tmp, поскольку он излишен и не используется в односвязном списке. Если бы вы добавляли элементы в начало списка, а не в его конец (как в вашем случае), то он действительно имел бы место. Причём когда вы его используете, вы его не инициализируете. Тоже самое и с указателем first. Перед циклом необходимо его инициализировать, иначе в указателе находится неопределённое значение. Правильное решение задачи:

program SINGLY_LINKED_LIST2;
type
    itemptr = ^item;
    item = record
        data: integer;
        next: itemptr
    end;
var
    first: itemptr;
    last: itemptr;
    n: integer;
begin
    first := nil;
    while not SeekEof do
    begin
        read(n);
        if first = nil then
        begin
            new(first);
            last := first
        end
        else
        begin
            new(last^.next);
            last := last^.next;
        end;
        last^.data := n;
        last^.next := nil
    end;
    while first <> nil do
    begin
        writeln(first^.data);
        writeln(first^.data);
        first := first^.next
    end
end.
→ Ссылка