scanf в C/C++: простыми словами с таблицей

👋 Рад вас видеть! В этой статье мы поговорим о функции scanf. Начнем мы с простого примера для разогрева. Потом мы рассмотрим все спецификаторы формата, которые эта функция поддерживает. Знание printf будет большим плюсом при знакомстве со scanf. В конце статьи вы найдете несколько упражнений для закрепления материала.

Иллюстрация scanf

Как считывать данные используя scanf

Для считывания данных из стандартного ввода в C и C++ можно воспользоваться функцией scanf. Эта функция доступна нам после подключения заголовочного файла <stdio.h> (в C++ я рекомендую использовать <cstdio>).

Функция scanf имеет следующий вид:

int scanf ( const char * format, ... );
  • Первым аргументом передается строка, которая описывает формат строки, которую мы будем считывать.
  • Вторым и последующими аргументами передаются параметры, которые ожидает функция scanf на основе переданного формата строки (первого аргумента).
  • Возвращает функция количество считанных аргументов. scanf может считать меньше указанного количества значений (вплоть до нуля), поскольку возможны ошибки и неожиданные символы при вводе.

Давайте теперь посмотрим на пример использования этой функции:

#include <stdio.h>

int main() {
  int i;
  char name[10];
  char c;

  printf("Загадайте число: ");
  scanf("%d", &i);
  printf("Звезды говорят что вы загадали %d\n", i);

  printf("Теперь введите имя и год рождения через пробел: ");
  int n = scanf("%s %d", name, &i);
  printf("Значений считано: %d\n", n);
  printf("%s, ваш приз без регистрации: $%d", name, i * 2);

  return 0;
}

Пример работы программы:

Загадайте число:       42
Звезды говорят что вы загадали 42
Теперь введите имя и год рождения через пробел: Дима 1999
Значений считано: 2
Дима, ваш приз без регистрации: $3998

scanf игнорирует пробельные символы в начале при считывании.

В этой программе мы продемонстрировали, как можно использовать scanf для простого ввода. Давайте попробуем считать что-то посложнее:

#include <stdio.h>

int main() {
  int day, year;
  char month[20];
  float price;

  printf("Введите дату, название месяца и цену (например, 15 Август 2023 $10.50): ");
  int n = scanf("%d %s %*d $%f", &day, month, &price);
  printf("День: %d\n", day);
  printf("Месяц: %s\n", month);
  printf("Цена: %.2f\n", price);
  printf("Значений считано: %d\n", n);

  return 0;
}

scanf считывает строки %s до первого пробельного символа.

Пример работы программы:

Введите дату, название месяца и цену (например, 15 Август 2023 $10.50): 17 Июль 2010 $12.34
День: 17
Месяц: Июль
Цена: 12.34
Значений считано: 3

В этом примере:

  • Мы используем %*d для игнорирования года. Звездочка говорит scanf‘у считать, но не сохранять значение.
  • Мы считываем день в day, строку в month и цену в price.
  • scanf возвращает количество успешно считанных аргументов, т.е. 3, потому что одно значение было проигнорировано.

Теперь давайте разберем все спецификаторы формата, которые можно использовать для считывания значений.

Certainly, here is the modified question with the changes you requested:

Какой будет вывод программы, если пользователь введет 10 20 30.50?

#include <stdio.h>

int main() {
  int a;
  float c;

  int n = scanf("%d %*d %f", &a, &c);
  printf("a: %d, c: %.2f, n: %d\n", a, c, n);

  return 0;
}
a: 10, c: 30.50, n: 3
a: 10, c: 30.50, n: 2
a: 10, c: 20.00, n: 2
a: 10, c: 30.50, n: 1

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

Структура спецификатора в scanf немного отличается от спецификатора в printf (в квадратных скобках опциональные модификаторы):

%[*][ширина][размер]тип

Как видите, обязательными являются только знак процента и тип; остальные можно не использовать.

Тип

ТипОписаниеПримерВвод
i

Считывает целое число в восьмеричной, десятеричной или шестнадцатеричной системе.

scanf("%i", &x); // x = 987
scanf("%i", &x); // x = -987
scanf("%i", &x); // x = 987

01733
-987
0x3db

d

Считывает целое число в десятеричной системе.

scanf("%d", &x); // x = -987

-987

u

Считывает целое положительное число в десятеричной системе.

scanf("%u", &x); // x = 987

987

o

Считывает целое число в восьмеричной системе.

scanf("%o", &x); // x = -987

-1733

x

Считывает целое число в шестнадцатеричной системе.

scanf("%x", &x); // x = -987
scanf("%x", &x); // x = 987

-3db
0x3db

f, e, g, a

Считывает вещественное число.

scanf("%f", &x); // x = 12.34
scanf("%f", &x); // x = 12.34
scanf("%f", &x); // x = 12.34
scanf("%f", &x); // x = 12.34

1.234e+01
12.34
987
0x1.8ap+3

c

Считывает символ.

scanf("%c", &x); // x = 'C'

C

s

Считывает строку до первого пробельного символа.

scanf("%s", &x); // x = "C++"

C++

p

Считывает адрес в памяти.

scanf("%p", &x); // x = 0x16dc

0x16dc

[<символы>]

Считывает строку до тех пор, пока не встретит символ, который отличается от символов, внутри квадратных скобок.

scanf("%[1a]", &x); // x = "aa1"

aa1398

[^<символы>]

Считывает строку до тех пор, пока не встретит символ, который совпадает с одним из символов, внутри квадратных скобок, после ^.

scanf("%[^a1]", &x); // x = "C++"

C++11

n

Ничего не считывает. Записывает количество считанных символов до этого момента.

scanf("C++%n11", &x); // x = 3

C++11

%%

Считывает знак процента.

scanf("%%%c", &x); // x = 'd'

%d

Игнорирование ввода

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

int x;
scanf("Пропустить: %*d, сохранить: %d", &x);
printf("Число: %d", x);

Пример вывода:

Пропустить: 123, сохранить: 456
Число: 456

Звездочку можно использовать с любым типом из таблицы выше, не только с числами.

Ширина

Мы можем указать максимальное количество символов, которые будут прочитаны функцией scanf при считывании значения:

char s[4]; // 3 символа + '\0'
scanf("%3s", s);
printf("Считали: %s", s);

Вывод:

C++11
Считали: C++

Как и звездочка, ширину можно указывать для любого типа.

Размер

По умолчанию, scanf считывает значения типа int, unsigned int, float и char (зависит от типа спецификатора). Чтобы считать, например, значение в переменную типа long long int, нам нужно явно указать размер:

#include <math.h>
#include <stdio.h>

int main() {
  long long int x;
  printf("Число: ");
  scanf("%lld", &x);
  //      ^ добавили ll для long long int
  printf("Считали: %lld\n", x);
  //                 ^ в printf тоже не забываем

  return 0;
}

Вывод:

Число: 10000000000
Считали: 10000000000

Без указания размера вывод будет выглядеть примерно так:

Число: 10000000000
Считали: 5705032704

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

Вот таблица размеров, которые можно использовать:

РазмерТип
hh

signed char / unsigned char

h

short int / unsigned short int

l

long int / unsigned long int

ll

long long int / unsigned long long int

j

intmax_t / uintmax_t

z

size_t

t

ptrdiff_t

L

long double

Упражнения

  1. Игнорирование значений:
    Напишите программу на C++, которая запрашивает у пользователя дату (день, месяц, год), но сохраняет только день и месяц, игнорируя год. Используйте спецификатор %*d для игнорирования значения года. После ввода пользователем данных, программа должна выводить сохраненные значения дня и месяца.

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

  3. Считывание данных до первого пробела:
    Напишите программу, которая запрашивает у пользователя строку. Используйте scanf для считывания введенной строки до первого пробельного символа и выведите эту строку на экран. Сравните результат с полной строкой, введенной пользователем.

Обсуждение