Как читать ввод пользователя в C с помощью scanf

10

Константы удобны. Они статичны. Но они также скучны.

Программа, которая всегда складывает 5 и 7, делает ровно одну вещь. Она не адаптируется. Она не взаимодействует. Чтобы сделать код на C действительно полезным для конечных пользователей, нужно перестать жестко задавать значения и начать прислушиваться.

Инструмент для этой задачи — scanf.

От жестко заданных значений к динамическим

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

Это неудобно для пользователя.

Чтобы исправить это, нам нужно захватывать ввод из консоли. Стандартная библиотека обрабатывает как вывод (printf ), так и ввод (scanf ). Переход от констант к значениям, определяемым пользователем, превращает программу из демонстрации калькулятора в простой утилиту.

Синтаксис scanf

Вот код, который это реализует:

Логика проста. Она линейна.

  1. Программа запрашивает первое целое число.
  2. scanf ожидает ввод.
  3. Пользователь вводит число и нажимает Enter.
  4. Значение сохраняется в a.
  5. Повторяется для b.
  6. Складывает их.
  7. Выводит результат.

Путаница с амперсандом (&)

Самая распространенная точка отказа для начинающих здесь — символ &.

Посмотрите на эту строку:
scanf("%d", &a);

Почему здесь есть амперсанд? Почему не просто scanf("%d", a);?

Переменные в C — это не просто имена. Это адреса памяти. Когда вы объявляете int a, вы резервиете фрагмент оперативной памяти. scanf не хочет значение a, потому что a в данный момент пуста (или содержит мусор). scanf нужен адрес, по которому он может записать новое значение.

& — это оператор «адрес переменной». Он передает scanf место в памяти, чтобы он мог напрямую изменять a. Без него вы указываете scanf на случайный фрагмент памяти. Программа, скорее всего, аварийно завершится или, что хуже, испортит ваши данные.

Ключевая мысль: printf использует значение. scanf нуждается в адресе.

Спецификаторы формата

Вы использовали %d в printf для отображения целого числа. Вы должны использовать %d в scanf для его чтения.

Несоответствие этих спецификаторов приводит к неопределенному поведению. Если вы попытаетесь прочитать целое число, используя %f (число с плавающей запятой), данные будут интерпретированы неправильно. Структура памяти числа с плавающей запятой отличается от структуры целого числа. scanf запишет сырые биты числа с плавающей запятой

Как scanf и printf обрабатывают переменные в C

Компиляция и запуск кода — это момент, когда теория встречается с реальностью. Если пропустить этот шаг, вы просто гадаете. Функция scanf работает аналогично printf в отношении форматных строк, но предъявляет более строгие требования к вводу. Перед переменными типов char, int, float и структурами необходимо ставить оператор адреса (& ). Без него программа аварийно завершает работу.

Почему scanf требует оператора адреса

Знак амперсанда не является необязательным. Он указывает компилятору сохранять введённые данные непосредственно по адресу памяти переменной. Если его опустить, возникает ошибка времени выполнения. Попробуйте намеренно убрать его. Наблюдение за аварийным завершением работы программы более поучительно, чем чтение об этом. Это наглядно демонстрирует, насколько хрупким может быть C при неправильной работе с адресами памяти.

Как printf форматирует вывод для пользователя

printf отправляет текст в стандартный вывод. Самая простая версия выглядит так:

Она выводит слово «Hello» без перевода строки. Сравните это с:

\n добавляет символ перевода строки. Он завершает текущую строку. Без него следующий вывод появится на той же строке. Это небольшая деталь, которая ухудшает читаемость, если её игнорировать.

Как встраивать переменные в строки printf

Чтобы вывести значение переменной, используется заполнитель (плейсхолдер). Спецификатор %d заменяет себя значением целочисленной переменной. Рассмотрим пример:

Можно использовать последовательные вызовы printf для смешивания текста и переменных, но это неэффективно:

Более чистый подход заключается во встраивании заполнителя непосредственно в строку:

Также можно использовать несколько заполнителей:

Количество заполнителей должно точно соответствовать количеству переменных. Типы также должны совпадать. Три спецификатора %d требуют трёх параметров типа int, перечисленных в том же порядке. Несоответствие типов или количества параметров приводит к неопределённому поведению.

Какие заполнители обрабатывают различные типы C

printf поддерживает стандартные типы C с помощью определённых спецификаторов формата:

  • int использует %d
  • float использует %f
  • char использует %c
  • строки символов используют %s

Подробную документацию можно найти, введя команду man 3 printf на машине с UNIX. Другие компиляторы предоставляют аналогичные справочные страницы или файлы помощи.

Распространённые ошибки в C, которых следует избегать

Регистр символов имеет строгое значение. Printf или PRINTF приведут к ошибке. Функция должна быть записана строчными буквами: printf.

  • Забытый & в scanf вызывает аварийное завершение работы во время выполнения.
  • Несоответствие количества параметров в printf или scanf приводит к искажению вывода.
  • Использование необъявленных переменных вызывает ошибки компиляции.

Отладка этих проблем часто сводится к проверке синтаксиса в первую очередь. Компилятор обычно точно указывает, где находится несоответствие. Вам остаётся только прочитать сообщение об ошибке.