Указатели и односвязные списки в 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 шт):
В вашем решении не нужно использовать дополнительный временный указатель 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.