Как ввести массив с клавиатуры на ассемблере: пошаговое руководство

Работа с массивами данных в языке ассемблер требует понимания того, как компьютер воспринимает ввод пользователя. Клавиатура передает не готовые числа, а символы в кодировке ASCII, которые необходимо преобразовать в байты или слова перед сохранением в оперативную память. Этот процесс часто вызывает сложности у новичков, так как требует ручного управления регистрами и стеком.

Вам нужно четко различать ввод одного символа и ввод последовательности цифр, составляющих число. Если вы пытаетесь заполнить массив из десяти элементов, каждый ввод должен обрабатываться индивидуально: считывать символ, проверять его на принадлежность к цифрам, преобразовывать и записывать в память по указанному смещению. Игнорирование этого механизма приведет к тому, что вместо чисел вы получите строку непонятных символов.

Ниже мы разберем алгоритм работы с прерываниями для получения данных, парсинг строки в число и структуру данных для хранения массива. При работе с реальным режимом процессора

Организация памяти и подготовка буфера

Первым этапом является выделение места в сегменте данных под будущий массив. В отличие от языков высокого уровня, ассемблер не создает массивы автоматически; вы должны явно зарезервировать память директивами DB (Define Byte) или DW (Define Word). Для ввода с клавиатуры часто удобно сначала создать буфер, который будет принимать строку символов, а затем уже конвертировать её.

Если вы планируете вводить числа, разделенные пробелами или запятыми, структура буфера должна учитывать эти разделители. Необходимо предусмотреть место не только для самих цифр, но и для символа возврата (Enter, код 13), который завершает ввод одной ячейки массива. Ошибка в размере буфера может привести к переполнению памяти и перезаписи соседних переменных.

Важно правильно инициализировать указатели. Счетчик элементов массива должен быть установлен в ноль, а регистр-указатель (например, SI или DI) должен указывать на начало зарезервированной области. Без корректной инициализации указателей программа будет записывать данные в случайные места памяти, вызывая непредсказуемое поведение.

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

Для получения данных от пользователя в среде DOS используется прерывание INT 21h. Функция AH=01h позволяет считать один символ с задержкой (эхо в консоли включено), что удобно для визуального контроля ввода. Считанный символ помещается в регистр AL, откуда его можно сразу переместить в буфер или сразу обработать.

Вам нужно реализовать цикл, который будет продолжать чтение, пока пользователь не нажмет клавишу ввода (Enter) или не заполнит массив полностью. Внутри цикла необходимо проверять код символа: если это цифра (коды 30h–39h), продолжаем формирование числа, если это разделитель — сохраняем текущее число в массив.

Использование функции INT 16h также возможно, если вы хотите считывать символы без отображения на экране, но для большинства учебных задач INT 21h является стандартом де-факто. Обратите внимание, что регистр AL должен быть сохранен, если вы вызываете другие подпрограммы, так как они могут изменить его содержимое.

⚠️ Внимание: Символы клавиатуры приходят в кодировке ASCII. Символ '0' имеет код 48 (30h), а не 0. Для получения числового значения необходимо вычитать из кода символа значение 30h.

Преобразование строки в число (Парсинг)

Самая сложная часть задачи — превратить последовательность символов в целочисленное значение. Алгоритм прост: инициализируйте аккумулятор нулем, затем для каждого нового символа умножьте текущее значение на 10 и прибавьте цифру. Этот метод горизонтального накопления позволяет обрабатывать числа любой длины, пока они помещаются в регистр.

Реализация этого алгоритма на ассемблере требует использования инструкций умножения MUL или сдвигов SHL. Например, умножение на 10 можно заменить на сдвиг вправо на 1 бит (умножение на 2) и на 3 бита (умножение на 8), а затем сложить результаты. Это значительно ускоряет выполнение программы на старых процессорах.

Не забудьте обработать знак числа. Если первым символом является минус (код 2Dh), вам нужно установить флажок знака и пропустить его при парсинге цифр. После завершения ввода числа, если знак был отрицательным, примените инструкцию NEG для получения дополнительного кода числа.

📊 Какой набор инструкций вы используете для парсинга
Множители MUL
Сдвиги SHL/SAL
Встроенные функции
Пока не знаю

Запись данных в массив

После того как число преобразовано и находится в регистре (обычно AX или AL), его нужно сохранить в массив. Используйте регистр индекса SI для смещения. Команда MOV [SI], AL запишет младший байт, а MOV [SI], AX — целое слово. После записи обязательно увеличьте SI на размер элемента массива (1 или 2 байта).

Критически важно проверять границы массива перед записью, чтобы не выйти за пределы выделенной памяти. Если количество введённых элементов превысило заданное, необходимо прервать цикл ввода и вывести сообщение об ошибке или завершить программу. Переполнение буфера — одна из самых частых уязвимостей в низкоуровневом коде.

Для наглядности рассмотрим таблицу, описывающую распределение памяти при вводе массива из 3-х чисел по 2 байта каждое:

Адрес смещения Содержимое (Hex) Значение (Dec) Комментарий
0000h 00 05 5 Первый элемент
0002h 0A 00 10 Второй элемент
0004h FF FF -1 Третий элемент (отрицательный)
0006h ?? ?? ?? Следующая свободная ячейка

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

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

Для этого используется проверка диапазона символов. Если код символа меньше 30h или больше 39h (и это не знак), можно считать ввод ошибочным. После ошибки пользователь должен иметь возможность перезаписать текущий элемент или пропустить его. Игнорирование некорректного ввода приведет к тому, что в массив попадут значения, равные кодам букв ASCII.

Также стоит учесть случай, когда пользователь нажимает Enter сразу, не введя ни одной цифры. В этом случае значение должно быть равно 0, а программа должна продолжить ожидание следующего числа, не увеличивая счетчик ошибок. Логика обработки таких пограничных случаев часто отделяется в отдельные подпрограммы для чистоты кода.

⚠️ Внимание: Если вы ввели неверный символ, регистры могут содержать мусор. Обязательно сбрасывайте регистры аккумулятора (AX) в ноль перед началом обработки нового числа, чтобы избежать накопления ошибок.

Дополнительные возможности и отладка

Для отладки программы ввода массива полезно выводить промежуточные значения на экран. Используйте функцию INT 21h с кодом 02h для печати символов. Это поможет вам понять, на каком этапе парсинг ломается или почему в массив записываются неверные значения.

Можно реализовать возможность просмотра массива после его заполнения. Пройдитесь циклом по всем элементам, преобразуйте их обратно в строку (из числа в символы) и выведите на экран. Это завершает цикл работы с данными: ввод, обработка, хранение, вывод. Консолидация данных позволяет убедиться в целостности структуры.

Как заменить ввод с клавиатуры на чтение из файла?

Чтобы читать массив из файла, нужно открыть файл через INT 21h, функцию 3Dh, затем читать байты функцией 3Fh в буфер и обрабатывать их точно так же, как символы клавиатуры, но без ожидания нажатия клавиш.-->

Типичные ошибки начинающих

Одной из самых распространенных ошибок является неправильное управление стеком. Если вы вызываете подпрограмму для парсинга, не забудьте сохранить регистры BP, SI, DI на входе и восстановить их на выходе. Нарушение соглашения о вызовах приводит к тому, что адрес возврата или смещение в массиве теряются.

Другая ошибка — использование символьных регистров вместо числовых при арифметике. Регистр AL хранит байт, но если вы складываете числа без приведения типов, результат может быть неверным. Внимательно следите за размером операндов

складывать byte с word нельзя без явного преобразования.

Иногда забывают увеличить счетчик цикла или смещение указателя, из-за чего программа зацикливается на одном элементе массива. Использование дебаггера (например, в среде Turbo Debugger или отладчиках Linux) позволяет пошагово выполнить код и увидеть изменение значений регистров в реальном времени.

☑️ Контрольный список перед запуском

Выполнено: 0 / 5

⚠️ Внимание: При работе в 64-битной ОС Windows (x64) стандартные DOS-прерывания (INT 21h) недоступны без использования эмуляторов. Для нативных программ используйте WinAPI или переходите в 16-битный режим.

Заключение

Ввод массива с клавиатуры на ассемблере — это фундаментальная задача, объединяющая работу с периферией, памятью и арифметикой. Успех зависит от тщательной проработки алгоритма преобразования строк в числа и строгой дисциплины в управлении регистрами. Освоив этот навык, вы сможете писать более сложные программы работы с файлами и сетевыми протоколами.

Помните, что код должен быть модульным: разделение задач на чтение, парсинг и запись делает программу читаемой и легкой в поддержке. Модульность кода особенно важна в ассемблере, где отслеживание состояния регистров вручную становится сложной задачей при увеличении объема программы.

Часто задаваемые вопросы

Можно ли вводить массив чисел сразу, без преобразования строк?

Нет, клавиатура всегда передает символы. Даже если вы вводите число 5, система получает код символа '5' (0x35). Преобразование в двоичный формат (0x05) обязательно для корректной арифметики.

Как обрабатывать отрицательные числа при вводе?

Нужно проверять первый символ. Если это минус (код 0x2D), запоминаем флаг отрицательного знака, пропускаем этот символ и при завершении ввода применяем инструкцию NEG к полученному числу.

Что делать, если пользователь ввел число слишком большое для регистра?

Вам нужно реализовать проверку переполнения перед каждым умножением или добавлением. Если результат превышает максимальное значение регистра, следует вывести ошибку "Overflow" и запросить ввод заново.

Как сохранить массив в файл после ввода?

Используйте функции DOS INT 21h: 3Dh (открыть файл), 3Ch (создать файл), 3Fh (читать) и 40h (записать). Запишите содержимое блока памяти, выделенного под массив, в открытый дескриптор файла.