Главная > Уроки > Ввод данных в языке Си. Функция scanf

Записывайся на этот курс на Stepike!

Ввод данных в языке Си. Функция scanf

Вернёмся к последнему листингу прошлого шага:

Листинг 1.

#include <stdio.h> 
int main(void) {
  int a, b, res;

  a = 10;
  b = 7;

  res = a + b;  
  printf("%d + %d = %d\n", a, b, res);
  return 0;
}

Основная задача этого шага научиться получить данные от пользователя.

Для этого можно использовать функцию scanf. Она, так же как и функция printf, описана в заголовочном файле stdio.h. Т.к. он у нас уже подключен в первой строке, то мы можем свободно использовать функцию scanf в своей программе.

Чтобы считать данные, которые ввёл пользователь, и сохранить их в переменную, нужно вызвать функцию scanf со следующими параметрами:

Общий синтаксис функции scanf

Рис.1. Общий синтаксис функции scanf.

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

Основные спецификаторы формата:

%d   - целые числа
%f   - вещественное число типа float
%lf  - вещественное число типа double (обозначение lf от long float)
%c   - символ

Обратите внимание, что в функции scanf для типов float и double используются различные спецификаторы формата.

После формат-строки нужно указать адрес переменной, в которую нужно сохранить данные. Чтобы указать адрес переменной достаточно перед её именем записать знак & (амперсанд), как на рисунке выше.

Напишем, наконец-таки, программу сложения двух чисел.

Листинг 2.

#include <stdio.h> 
int main(void) {
  int a, b, res;

  scanf("%d", &a); // считываем целое значение в переменную a
  scanf("%d", &b); // считываем целое значение в переменную b

  res = a + b;  
  printf("%d + %d = %d\n", a, b, res);
  return 0;
}

Скомпилируйте и запустите эту программу. После того, как программа запущена она будет ждать пока вы введёте данные. Мы с вами знаем какие данные нужно вводить, т.к. мы писали эту программу. Для других пользователей, которые код программы не увидят, хорошо бы вывести на экран подсказку, какие данные нужно ввести. Посмотрите как это реализовано в следующем примере.

Эта программа будет полезна тем, кто следит за своим здоровьем. Данная программа подсчитывает уроверь базового обмена веществ по формуле Миффлина-Сан Жеора исходя из данных, которые вы введёте (возраст, рост и вес).

Листинг 3.

#include <stdio.h> 
int main(void){
	
  int age, height, weight;
  double bov_m, bov_f;
  
  printf("Vash vozrast?(god)\n");
  scanf("%d", &age); // считываем целое значение в переменную age
	
  printf("Vash rost?(cm)\n");
  scanf("%d", &height); // считываем  значение в переменную height
	
  printf("Vash ves?(kg)\n");
  scanf("%d", &weight); // считываем значение в переменную weight
	
  bov_m = 10*weight + 6.25*height - 5*age + 5;
  bov_f = 10*weight + 6.25*height - 5*age - 161;
  printf("|       BMR       |\n");
  printf("|  male  | female |\n");
  printf("|%8.2f|%8.2f|\n",bov_m, bov_f);
	
  return 0;
}

На самом деле, функция scanf – функция форматного ввода. Она устроена чуть ли не сложнее, чем printf. Но рассказывать новичку об особенностях её работы значит понапрасну грузить его лишней информацией. На данном этапе вам будет достаточно и этих знаний, а когда появится необходимость использовать что-то большее, вы с этим сможете сами разобраться. А может и я в каком-нибудь уроке расскажу.

Сохрани в закладки или поддержи проект.

Практика

Решите предложенные задачи. Для удобства работы сразу переходите в полноэкранный режим

Исследовательские задачи для хакеров:

  1. Попробуйте удалить в программе Листинг 2 символ & в какой-нибудь функции scanf. Посмотрите какую ошибку выдаст компилятор.
  2. Попробуйте использовать %f для типа double, а %lf для типа float. Каковы результаты? Напишите об этом в комментариях к этому уроку. Не забудьте указать название вашей IDE или компилятора.

Дополнительные материалы

  1. пока нет

Оставить комментарий

Чтобы код красиво отображался на странице заключайте его в теги [code] здесь писать код [/code]

Комментарии

Сергей
Здраствуйте мне нужна помощь :когда я задаю значение float он в ответе пишет так : 3.50 + 3.40 = 6.9000000
Как убрать нолики?

KaDeaT
Об этом рассказывается в уроке Форматированный вывод.

Посмотрите на листинг 8 и на результат вывода.
Дмитрий
Нет возможности в некоторых темах сохранить урок ввиде PDF файла для изучения в offline когда летишь в самолёте! Создайте пожалуйста одну общую кнопку для сохранения уроков в режиме ,offline пожалуйста
KaDeaT
Дмитрий, добрый день. Да, знаю об этой проблеме.

К сожалению не хватает времени сделать pdf-версии для всех уроков. Но оно обязательно будет, обещаю. Не могу быть уверенным, что к концу этого года успею, но уж в январе 2018 pdf-версия будет у каждого урока.
Кирилл
Здравствуйте, появился вопрос: почему при выводе переменных в printf мы не используем знак "&", хотя в вводе scanf он необходим?
Заранее большое спасибо
KaDeaT
Добрый день.
Это одна из особенностей того, как устроены функции в языке Си.

Функции не могут изменять те переменные, которые им передаются. Чтобы они могли изменять эти переменные, надо им передавать не переменную, а адрес в памяти где хранится переменная. Поэтому для printf, которая просто выводит переменную на экран не изменяя её, нужно передавать только имя переменной, а для scanf, которая записывает в переменную данные, тем самым изменяя её, нужно передавать адрес в памяти.
Чтобы получить адрес переменной, нужно использовать операцию &.
DimaKotoriyRAshid
У меня никак не получается сделать предпоследнее задание , постоянно выдает ошибку номер 2. При правильном ответе он пишет какую то откровенную дич. Уже битый час пытаюсь найти ошибку ((9(
KaDeaT
Пожалуйста, напишите в комментариях на Stepik номер своего решения. Попробую вам помочь.)
Андрей
"но уж в январе 2018 pdf-версия будет у каждого урока" это цитата из комментария))
Я не могу найти эту кнопку!!!
KaDeaT
Дела и заботы, к сожалению, помешали сбыться этому плану. Никак не могу взяться за эту работу. Но возьмусь летом, а может даже раньше.
Farid
ya reshil vse zadaci,pishu kuski sekretnogo klyuca,no mne pishut neverniy klyuc.mojete proveryat?
KaDeaT
Проверил, всё работает правильно. Может быть вы не удалили пробелы? Пробелов быть не должно.
Виталий
* а когда появится необходимость использовать что-то большее, вы с этими сможете сами разобраться - очепятка ~вы с ЭТИМ сможете~
KaDeaT
Спасибо. Поправил!
Samvel
1 + -365906032 = 803628530
Eclipse
KaDeaT
спасибо.
Николай Евсюков
1. CRT: unhandled exception (main) -- terminating
*** Process returned 255 ***

2. float f;
double d;
scanf("%lf", &f);
scanf("%f", &d);
printf("%f %f", f, d);

Ввод:
1.1
2.2
Вывод:
-0.000000 0.000000

P.S. IDE Pelles C.
KaDeaT
Спасибо.
Krowka_v_Kartowke
Здравствуйте, нашел опечатку. "Скомпилируйте и запустить(*те) эту программу.". Урок отличный, спасибо Вам.
KaDeaT
Спасибо за внимательность! Поправил.
не_робот_я
хакерские задачи:
1. сегфолт (ошибка сегментации)
2. Xcode ругается так "Format specifies type 'float *' but the argument has type 'double *'", а онлайн компилятор onlinegdb.com не ругается, но результат выдаёт нулевой.
KaDeaT
Спасибо!
Estel
Отличные уроки, большое спасибо!

по заданию 1:
Variable 'dollars' is uninitialized when used here
Initialize the variable 'dollars' to silence this warning
по заданию 2:
Format specifies type 'float *' but the argument has type 'double *'
Format specifies type 'double *' but the argument has type 'float *'
(Xcode)
KaDeaT
Спасибо!
Максим
Использую Dev C++.
1. Если удалить адрес из какой-либо переменной, она на выводится на экран, при нажатии на клавишу.
2. Если использовать спецификатор %f для типа double, выводимый результат будет 0.00000+0.00000=0.00000.
3. Если использовать спецификатор %lf для типа floai, второе слагаемое будет всегда 0.00000, а первое будет выдавать неверно введенные данные.
pchristi
Поэкспериментировал со второй хакерской задачкой. Вводил число 3.14 потом 1.12;
В первом случае при %f и double в printf был такой результат:
1) 512181179925964090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000.000000
2) 512181179185108140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000.000000
Во втором случае, при %lf и типе float вышло так:
1) 126443839488.000000
2) 0.000000

IDE = CLion;
Александр
Не одобряю примеры на данной странице, так как в них начальные значения переменным не задаются. Это очень плохой стиль программирования: если в реальной жизни забудешь дальше выполнить присваивание значения, новичок может долго отлаживаться, чтобы понять, в чём проблема.
Кирилл
Я сломал зал славы! Мое достижение в нем датировано 31.12.2020!!!
KaDeaT
Это награда за то, что решали задачи в канун нового года.)
LRusseBesuhof
При задании переменной типа double, что "%f", что "%lf" выводит стандартные 6 знаков после запятой. При задании переменной типа float, что "%f", что "%lf" пишет:"warning C4305: инициализация: усечение из "double" в "float"" и выводит также 6 знаков. Visual Studio 2019.
jslovak
я не робот )
gcc
%f для типа double:
4.4
3.3
0.000000 + 0.000000 = 0.000000
%lf для типа float:
3.3
4.4
2.275000 + -0.000000 = 2.275000
Никита
Как исправить эту ошибку? Попробовал загуглить тоже не помогло.
Ошибка C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.
Mario
1. при попытке записать значение без амперсанда выдаёт "process returned 255";

2. если "перепутать" входные типы, то:

float x;
double y;
scanf("%lf%f", &x, &y);
printf("x = %fny = %fn", x, y);
//при любых входных данных на выходе всегда:
//x = 0.000000
//y = 0.000000


Pelles C for Windows 11.00.2
Иван Хрипков
Пользуюсь onlinegdb:
1)
 main.c:6:11: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
6 | scanf("%d", a); // считываем целое значение в переменную a
| ~^ ~
| | |
| | int
| int *
^C


2)
 main.c:7:11: warning: format ‘%f’ expects argument of type ‘float *’, but argument 2 has type ‘double *’ [-Wformat=]
7 | scanf("%f", &a, &b);
| ~^ ~~
| | |
| | double *
| float *
| %lf
main.c:7:9: warning: too many arguments for format [-Wformat-extra-args]
7 | scanf("%f", &a, &b);
| ^~~~
main.c:8:12: warning: format ‘%lf’ expects argument of type ‘double *’, but argument 2 has type ‘float *’ [-Wformat=]
8 | scanf("%lf", &res);
| ~~^ ~~~~
| | |
| | float *
| double *
| %f
^C
Владимир
Добрый день. Запускаю код с Листинга 2 в Visual Studio 2022 и пробовал в Pelles C IDE выдаёт ошибку. Ошибка C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Rada
Не совсем понятно про вторую исследовательскую задачу. Что должно получиться?
Андрей
Предупреждение компилятора (уровень 3) C4996

Для его отключения в VS2022 или других можете добавить в начало файла с исходным кодом:
#define _CRT_SECURE_NO_WARNINGS
Vitaliy
 
char a[]="S.Holmes:";
char b[]="51grad 31'25.48";
char c[]="0 grad 9'29.93";
char d[]={'N',' W','"',' '};
printf("%sn" "%s" "%c" "%c" "%cn",a ,b , d[2],d[3],d[0]);
printf("%s" "%c" "%c" "%cn",c ,d[2],d[3],d[1] );