Как сделать ввод с клавиатуры в Паскале: от базовых команд до обработки исключений

Если ваша программа на Pascal не принимает данные с клавиатуры или выдаёт ошибку Runtime error 106 при попытке ввода, проблема кроется в неправильном использовании процедур Read или Readln. Эти функции — основа взаимодействия с пользователем в консольных приложениях, но их синтаксис и нюансы работы часто становятся источником багов. Например, попытка считать строку в переменную типа Integer приведёт к аварийному завершению, а отсутствие обработки нажатия Enter после Read может"сломать" последующий ввод. Разберём, как корректно реализовать ввод для разных типов данных, избежать типичных ошибок и адаптировать код под современные компиляторы (Free Pascal, Lazarus).

В отличие от языков вроде Python или JavaScript, где ввод реализуется через универсальные функции (например, input), в Pascal для каждого типа данных (целые числа, вещественные, символы, строки) требуется свой подход. Более того, поведение Readln отличается в Turbo Pascal 7.0 и Free Pascal 3.2.2 — это важно учитывать при переносе legacy-кода. Ниже вы найдёте актуальные примеры с пояснениями, включая обработку некорректного ввода и работу с динамическими массивами.

Базовый синтаксис: Read vs Readln

Процедуры Read и Readln — два ключевых инструмента для ввода данных в Pascal. Их отличие заключается в обработке символа новой строки (Enter):

  • 🔹 Read(var1, var2,...) — считывает данные из стандартного ввода (клавиатуры) и оставляет курсор в конце текущей строки. Если пользователь ввёл 5 10 и нажал Enter, следующая процедура Read продолжит чтение с той же строки.
  • 🔹 Readln(var1, var2,...) — аналогично Read, но после считывания всех переменных игнорирует оставшиеся символы до конца строки (включая Enter). Это предотвращает"зависание" ввода при последовательных вызовах.
  • 🔹 Readln; (без параметров) — просто ожидает нажатия Enter, полезно для паузы перед закрытием консоли.

Пример корректного использования:

program InputExample;

var

A, B: Integer;

C: Char;

begin

Write('Введите два числа:');

Read(A, B); // Ожидает ввод типа"5 10" (разделённые пробелом)

Readln; // Очищает буфер от оставшегося Enter

Write('Введите символ:');

Readln(C); // Теперь ввод символа не"съест" старый Enter

end.

⚠️ Внимание: Если после Read не вызвать Readln, следующий ввод может прочитать оставшийся символ новой строки как пустую строку или ноль. Это частая причина багов в циклах ввода.

Ввод для разных типов данных

Тип переменной определяет, как Pascal интерпретирует введённые символы. Attempt to read beyond end of file (Runtime error 106) возникает, если пользователь ввёл данные, не соответствующие ожидаемому типу. Например, строка "abc" не может быть преобразована в Integer.

Тип данных Пример ввода Процедура Ошибка при несоответствии
Integer 42 Readln(N: Integer); Runtime error 106 (если ввести "text")
Real 3.14 или 5 Readln(X: Real); Runtime error 106 (если ввести "pi")
Char a или 5 (один символ) Readln(S: Char); Нет (считывает первый символ, игнорирует остальные)
String Hello Readln(Str: String); Нет (но может обрезать строку до максимальной длины)
Boolean TRUE или FALSE (регистр важен!) Readln(Flag: Boolean); Runtime error 106 (если ввести "yes")

Для строк в Free Pascal можно использовать динамический тип AnsiString или String (по умолчанию до 255 символов). В Turbo Pascal длина строки фиксирована и указывается при объявлении:

var

Name: String[30]; // Максимум 30 символов

Обработка ошибок ввода

По умолчанию Pascal не предоставляет встроенных механизмов для обработки некорректного ввода (например, когда пользователь вводит букву вместо числа). Однако можно использовать конструкцию try...exceptFree Pascal) или проверять тип данных вручную.

Пример с обработкой исключения:

program SafeInput;

var

N: Integer;

begin

Write('Введите целое число:');

try

Readln(N);

Writeln('Вы ввели:', N);

except

on EConvertError do

Writeln('Ошибка: введено не число!');

end;

end.

Для Turbo Pascal, где нет исключений, придётся анализировать ввод как строку и проверять её содержимое:

program CheckInput;

var

InputStr: String;

N: Integer;

Code: Integer;

begin

Write('Введите число:');

Readln(InputStr);

Val(InputStr, N, Code);

if Code <> 0 then

Writeln('Ошибка:', InputStr,' не является числом!')

else

Writeln('Число:', N);

end.

⚠️ Внимание: Функция Val возвращает код ошибки в третьем параметре. Если он не равен нулю, преобразование не удалось. Это единственный надёжный способ проверки ввода в старых версиях Pascal.
📊 Какой компилятор Pascal вы используете?
Turbo Pascal 7.0
Free Pascal
Lazarus
Другой
Не знаю

Ввод массивов и структур данных

Для считывания массивов с клавиатуры используйте циклы for или while. Важно заранее определить размер массива или реализовать динамическое выделение памяти (в Free Pascal).

Пример ввода одномерного массива:

program ArrayInput;

const

MAX_SIZE = 10;

var

A: array[1..MAX_SIZE] of Integer;

I, N: Integer;

begin

Write('Введите размер массива (до', MAX_SIZE,'):');

Readln(N);

for I:= 1 to N do

begin

Write('A[', I,'] =');

Readln(A[I]);

end;

end.

Для динамических массивов в Free Pascal:

program DynamicArrayInput;

var

A: array of Integer;

I, N: Integer;

begin

Write('Введите размер массива:');

Readln(N);

SetLength(A, N); // Выделяем память

for I:= 0 to N-1 do

begin

Write('A[', I,'] =');

Readln(A[I]);

end;

end.

- Указан ли размер массива заранее или он вводится пользователем?|- Соответствует ли тип элементов массива ожидаемому вводу?|- Есть ли защита от переполнения (если размер фиксирован)?|- Очищается ли буфер ввода после Read?-->

Проблемы с буфером ввода и их решения

Одна из самых распространённых ошибок —"зависание" программы после смешивания Read и Readln. Это происходит из-за того, что Read не очищает буфер ввода от символа новой строки (Enter), и следующий Readln считывает пустую строку.

Сценарий ошибки:

Read(X); // Пользователь вводит"5" и нажимает Enter

Readln(Y); // Считывает оставшийся Enter, Y становится пустым

Решения:

  • 🔧 Всегда используйте Readln после Read, если дальше идёт другой ввод.
  • 🔧 Очищайте буфер вручную с помощью дополнительного Readln:
Read(X);

Readln; // Очистка буфера

Readln(Y);

Для сложных случаев (например, чтение до конца файла) используйте функцию Eof:

while not Eof do

begin

Readln(Str);

// Обработка строки

end;

Почему в Turbo Pascal нет функции Flush для очистки буфера?

В оригинальной реализации Pascal (и Turbo Pascal) концепция"очистки буфера" не предусмотрена на уровне языка. Вместо этого ожидается, что программист явно управляет потоком ввода, используя Readln для перехода на новую строку. В современных компиляторах (Free Pascal) можно использовать модуль SysUtils для более гибкой работы с буфером, но в классическом Pascal это считалось излишним.

Расширенные техники: ввод из файла и перенаправление

В реальных проектах данные часто считываются не с клавиатуры, а из файлов или перенаправленного стандартного ввода. Для этого используются процедуры Assign, Reset и Read/Readln с явным указанием файловой переменной.

Пример чтения из файла:

program FileInput;

var

F: Text;

S: String;

begin

Assign(F,'input.txt');

Reset(F);

while not Eof(F) do

begin

Readln(F, S);

Writeln('Прочитано:', S);

end;

Close(F);

end.

Перенаправление ввода (например, из командной строки):

{ Для Windows: }

{ program.exe < input.txt }

В Free Pascal можно использовать модуль Classes для работы с потоками, но для консольных приложений обычно хватает стандартных процедур.

Совместимость с разными компиляторами

Код, написанный для Turbo Pascal, может не работать в Free Pascal без. Основные различия:

Функциональность Turbo Pascal 7.0 Free Pascal 3.2.2
Макс. длина строки 255 символов Ограничена памятью (AnsiString)
Обработка исключений Нет (используется Val) Есть (try...except)
Динамические массивы Нет Да (SetLength)
Юникод Нет Да (тип UnicodeString)

Для кросс-компиляции рекомендуется:

  • 🛠 Использовать {$MODE TP} или {$MODE Delphi} для управления совместимостью.
  • 🛠 Заменять Val на TryStrToInt в Free Pascal.
  • 🛠 Избегать фиксированных строк (String[N]) в пользу AnsiString.

FAQ: Частые вопросы по вводу в Pascal

Почему после ввода числа программа пропускает следующий Readln?

Это происходит из-за того, что Read не очищает буфер от символа новой строки (Enter). Решение: добавьте Readln после Read или используйте только Readln для всех вводов.

Как ввести строку с пробелами?

Используйте Readln(Str: String). Эта процедура считывает всю строку до нажатия Enter, включая пробелы. Если нужно ограничить длину, укажите её при объявлении: Str: String[50].

Можно ли в Pascal вводить данные без нажатия Enter?

В стандартном Pascal нет функции для побайтового чтения без буферизации. Однако в Free Pascal можно использовать модуль Crt и функцию KeyPressed для проверки нажатий в реальном времени.

Как проверить, что пользователь ввёл корректное число?

В Turbo Pascal используйте Val с проверкой кода ошибки. В Free Pascal лучше обернуть Readln в блок try...except и отлавливать EConvertError.

Почему при вводе русского текста отображаются кракозябры?

В Turbo Pascal по умолчанию используется кодировка CP866 (DOS). Для работы с русским текстом в Free Pascal под Windows установите кодировку консоли с помощью SetConsoleCP/SetConsoleOutputCP (модуль Windows).