Foreversoft.ru

IT Справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Scanf в си примеры

scanf

Функция scanf() является процедурой ввода общего назначения, считывающей данные из пото­ка stdin. Она может считывать данные всех базовых типов и автоматически конвертировать их в нужный внутренний формат. Если бы printf() выполняла ввод, а не вывод, ее можно было бы назвать аналогом scanf().

Управляющая строка, на которую указывает format, состоит из символов трех типов:

  • Спецификаторы формата
  • Специальные символы
  • Прочие символы (не специальные)

Спецификаторы формата следуют за символом процент и сообщают scanf(), данные какого типа будут считаны следующими. Коды спецификаторов приведены в таблице.

Табпица: Коды форматов для scanf()

КодЗначение
Считать один символ
%dСчитать десятичное число целого типа
%iСчитать десятичное число целого типа
Считать число с плавающей запятой
%fСчитать число с плавающей запятой
%gСчитать число с плавающей запятой
Считать восьмеричное число
%sСчитать строку
Считать шестнадцатиричное число
Считать указатель
%nПринимает целое значение, равное количеству считанных до текущего момента символов
%uСчитывает беззнаковое целое
%[]Просматривает набор символов
%%Считывает символ %

Например, %s считывает строку, a %d считывает переменную целого типа.

Строка формата считывается слева направо, при этом устанавливается соответствие между ко­дами формата и аргументами из списка аргументов.

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

Наличие обычного символа заставляет scanf() считать и отбросить соответствующий символ. Например, «%d,%d» заставляет scanf() считать целое число, считать и отбросить запятую и затем считать еще одно целое число. Если указанный символ не обнаружен во входном потоке, scanf() останавливается.

Все переменные, используемые для приема значений с помощью функции scanf(), должны отыс­киваться по их адресам. Это значит, что все аргументы функции должны быть указателями на переменные. Таким образом, С создает возможность передачи по ссылке, и это позволяет функ­ции изменять содержимое аргумента.

Например, чтобы считать целое число и присвоить его значение переменной count, необходи­мо воспользоваться следующим обращением к scanf():

Строки считываются в массивы символов, и имя массива, без всякого указателя, является адре­сом первого элемента массива. Поэтому, чтобы считать строку в массив символов address, можно использовать команду

В этом случае имя address уже является указателем и не нуждается в префиксе &.

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

последовательность 10 20 будет воспринята, а последовательность 10,20 — нет. Спецификаторы формата scanf() расположены в том же порядке, что и переменные в списке аргументов, которым присваиваются значения принимаемых переменных.

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

при вводе последовательности 10/20 присваивает значение 10 переменной х, отбрасывает символ / и присваивает значение 20 переменной у.

Командами форматирования может задаваться модификатор максимальной ширины поля. Он представляет собой целое число, которое помещается между знаком % и спецификатором фор­мата. Он ограничивает количество считываемых символов для любого поля. Например, если не­обходимо считать не больше, чем 20 символов в массив address, следует написать

scanf («%20s», address);

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

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

поместит символ х в переменную а, пробел — в переменную b и y — в переменную c.

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

поместит 10 в х, а 20 в у. Символ t будет отброшен, поскольку в управляющей строке имеется t.

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

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

Массив, возвращенный scanf(), будет содержать строку с нулевым символом в конце. Перечень считы­ваемых символов можно задать и в инверсной форме. Для этого в качестве первого символа надо поместить ^. Тогда scanf() будет принимать любой символ, не входящий в множество сканирования.

С помощью кавычек можно задать диапазон воспринимаемых символов. Например, следующее выражение дает указание scanf() принимать буквы от «А» до «Z»:

Множество сканирования различает прописные и строчные буквы. Если необходимо, чтобы scanf() принимала те и другие, необходимо перечислить их в множестве сканирования отдельно.

Функция scanf() возвращает число, равное количеству полей, значения которых были действи­тельно присвоены переменным. В это количество не входят поля, которые были считаны, но их значения не были ничему присвоены вследствие использования модификатора * для подавления присваивания. Если до присвоения значения первого поля произошла ошибка, возвращается EOF.

При использовании Borland С++ в 16-разрядной среде можно изменить модель памяти, ис­пользуемую по умолчанию для компилирования программы, путем явного указания размера каж­дого указателя, используемого при вызове scanf(). Ближний указатель задается модификатором N, а дальний — модификатором F. (Нельзя использовать модификатор N, если программа ском­пилирована для модели памяти huge.)

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

Пожалуйста, приостановите работу AdBlock на этом сайте.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Практика

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

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

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

Функция scanf

Функция scanf() представляет собой процедуру ввода общего назначения, которая читает поток stdin и сохраняет информацию в переменных, перечисленных в списке аргументов. Она может читать все встроенные типы данных и автоматически преобразовывать их в соответствующий внутренний формат.

В версии C99 к параметру format применен квалификатор restrict .

Управляющая строка, задаваемая параметром format , состоит из символов трех категорий:

  • спецификаторов формата;
  • пробельных символов;
  • символов, отличных от пробельных.

Спецификации формата начинаются знаком % и сообщают функции scanf() тип данного, которое будет прочитано. Спецификации формата приведены в таблице 13.3. Например, по спецификации %s будет прочитана строка, а по спецификации %d — целое значение. Строка форматирования читается слева направо, и спецификации формата сопоставляются аргументам в порядке их перечисления в списке аргументов.

Таблица 13.3. Спецификации формата функции scanf()
КодНазначение
%aЧитает значение с плавающей точкой (только C99)
%AАналогично коду %a (только C99)
%cЧитает один символ
%dЧитает десятичное целое
%iЧитает целое в любом формате (десятичное, восьмеричное или шестнадцатеричное)
%eЧитает число с плавающей точкой
%EАналогично коду %e
%fЧитает число с плавающей точкой
%FАналогично коду %f (только С99)
%gЧитает число с плавающей точкой
%GАналогично коду %g
%oЧитает восьмеричное число
%sЧитает строку
%xЧитает шестнадцатеричное число
%XАналогично коду %x
%pЧитает указатель
%nПринимает целое значение, равное количеству прочитанных до сих пор символов
%uЧитает десятичное целое без знака
%[]Просматривает набор символов
%%Читает знак процента

По умолчанию спецификации a , f , e и g заставляют функцию scanf() присваивать данные переменным типа float . Если перед одной из этих спецификаций поставить модификатор l , функция scanf() присвоит прочитанные данные переменной типа double . Использование же модификатора L означает, что полученное значение присвоится переменной типа long double .

Современные компиляторы, поддерживающие добавленные в 1995 году средства работы с двухбайтовыми символами, позволяют к спецификации c применить модификатор l ; тогда будет считаться, что соответствующий указатель указывает на двухбайтовый символ (т.е. на данное типа whcar_t ). Модификатор l также можно использовать с кодом формата s ; тогда будет считаться, что соответствующий указатель указывает на строку двухбайтовых символов. Кроме того, модификатор l можно использовать для того, чтобы указать, что набор сканируемых символов состоит из двухбайтовых символов.

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

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

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

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

Символ * , стоящий после знака % и перед кодом формата, прочитает данные заданного типа, но запретит их присваивание. Следовательно, оператор при вводе данных в виде 10/20 поместит значение 10 в переменную x , отбросит знак деления и присвоит значение 20 переменной у .

Команды форматирования могут содержать модификатор максимальной длины поля. Он представляет собой целое число, располагаемое между знаком % и кодом формата, которое ограничивает количество читаемых для всех полей символов. Например, если в переменную address нужно прочитать не более 20 символов, используется следующий оператор.

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

Хотя пробелы, символы табуляции и разделители строк используются в качестве разделителей полей, при чтении одиночного символа они читаются подобно любому другому символу. Например, если входной поток состоит из символов x у , то оператор поместит символ x в переменную а , пробел — в переменную b , а символ у — в переменную с .

Помните, что любые символы управляющей строки (включая пробелы, символы табуляции и новой строки), не являющиеся спецификациями формата, используются для установки соответствия и отбрасывания символов из входного потока. Любой соответствующий им символ отбрасывается. Например, если поток ввода выглядит, как 10t20 , оператор присвоит переменной x значение 10, а переменной у — значение 20. Символ t отбрасывается, так как он присутствует в управляющей строке.

Функция scanf() поддерживает спецификатор формата общего назначения, называемый набором сканируемых символов (scanset) . В этом случае определяется набор символов, которые могут быть прочитаны функцией scanf() и присвоены соответствующему массиву символов. Для определения такого набора символы, подлежащие сканированию, необходимо заключить в квадратные скобки. Открывающая квадратная скобка должна следовать сразу за знаком процента. Например, следующий набор сканируемых символов указывает на то, что необходимо читать только символы A , B и C .

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

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

Во многих реализациях допускается задавать диапазон с помощью дефиса. Например, функция scanf (), встречая набор сканируемых символов в виде %[A-z] , будет читать символы, попадающие в диапазон от А до Z.

Важно помнить, что в наборе сканируемых символов различаются прописные и строчные буквы. Следовательно, чтобы сканировать как прописные, так и строчные буквы, в наборе сканируемых символов придется задать их отдельно.

Функция scanf() возвращает число, равное количеству полей, для которых успешно присвоены значения. К этим полям не относятся поля, которые были прочитаны, но присвоение не состоялось в связи с использованием модификатора * , подавляющего присваивание. При обнаружении ошибки до присвоения значения первого поля функция scanf() возвращает значение EOF .

Модификаторы формата, добавленные к функции scanf() Стандартом C99

В версии C99 для использования в функции scanf() добавлены модификаторы формата hh , ll , j , z и t . Модификатор hh можно применять к спецификациям d , i , о , u , x и n . Он означает, что соответствующий аргумент является указателем на значение типа signed char или unsigned char . Модификатор ll также можно применять к спецификациям d , i , о , u , x и n . Он означает, что соответствующий аргумент является указателем на значение типа signed long long int или unsigned long long int .

Moдификaтop фopмaтa j , кoтopый пpимeняeтcя к cпeцификaциям d , i , о , u , х и n означает, что соответствующий аргумент является указателем на значение типа intmax_t или uintmax_t . Эти типы объявлены в заголовке и служат для хранения целых максимально возможной разрядности.

Модификатор формата z , который применяется к спецификациям d , i , о , u , х и n означает, что соответствующий аргумент является указателем на объект типа size_t . Этот тип объявлен в заголовке и служит для хранения результата операции sizeof .

Модификатор формата t , который применяется к спецификациям d , i , о , u , х и n означает, что соответствующий аргумент является указателем на объект типа ptrdiff_t . Этот тип объявлен в заголовке и служит для хранения значения разности между двумя указателями.

Пример

Действие данных операторов scanf() объясняется в комментариях.

Функция scanf

Для считывания данных в языке C используется функция scanf. Ее использование похоже на функцию prinf — сначала задается форматная строка, потом передаются переменные, в которые необходимо записать результат. Например, для считывания двух целых чисел функция вызывается так:

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

В функции scanf могут быть явно записаны какие-то символы, кроме форматных строк. Например, вызов

можно использовать для считывания времени, заданного в виде hh:mm — функция считает число, затем символ двоеточия, затем опять число.

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

Особенности считывания чисел

Функция scanf корректно считывает целые числа, если они начинаются с символа 0, или со знака «+». То есть числа «+123» или «0123» будут корректно считаны по форматной строке «%d», никаких дополнительных параметров задавать не нужно.

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

scanf(«%d:%d», &a, &b) сможет корректно считать время, заданное в формате hh:mm при наличии пробела после двоеточия (такая запись успешно считает строки «12:34», «01:02», «01:␣23» или «␣01:␣23», поскольку дается указание считать число, затем сразу же двоеточие, затем — число, перед которым могут быть пробелы). Но такая запись не считает выражение, например, вида «01␣:␣23», поскольку после первого числа сразу должно идти двоеточие.

Чтобы считать записать вида «01␣:␣23» можно использовать форматную строку «%d :%d», причем пробел в форматной строке может означать и отсутствие пробелов.

Возможные форматные символы

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

Форматная
строка
Соответствующий ей тип
%hhdСчитать число (десятичное) и записать его в переменную типа char (для unsigned char нужно использовать %hhu)
%hdshort int (для unsigned short int нужно использовать %hu)
%dint (для unsigned int нужно использовать %u)
%ldlong int (для unsigned long int нужно использовать %lu)
%lldlong long int (для unsigned long long int нужно использовать %llu)
%ffloat
%lfdouble
%Lflong double
char. Считывается один символ, он может быть пробелом или символом конца строки.
%sСчитывается последовательность непробельных символов (строка), записывается в C-строку (типа char * или char[])

Особенность считывание символов

Считывание одного символа «%c» считывает из потока ввода следующий символ, он может быть в том числе и пробельным символом, а также символом конца строки. Но если в форматной строке перед «%c» поставить пробел, то поскольку пробел в форматной строке обозначает последовательность пробельных символов любой длины, то в этом случае будет считан следующий непробельный символ.

Особенность считывания строк

При считывании строки результат записывается в С-строку, которая представляет собой массив символов (или указатель типа char * с выделенной памятью). Поскольку строка в языке C является адресом (указателем) в памяти, где хранится начало строки символов, то передавать в функцию scanf нужно имя переменной без указания амперсанда.

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

Иногда бывает полезно считать всю строку целиком вместе с пробелами до конца строки. Для этого используется функция gets . Например:

Функция gets считается опасной и не рекомендуется для использования, так как она не контролирует количество считанных символов и не учитывает длину передаваемой строки, что может привести к записи данных за пределами строки.

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

fgets(s, 101, stdin);

В данном случае мы использовали stdin для чтения со стандартного ввода.

Не следует забывать, что в языке C в конец строки добавляется нулевой символ для обозначения конца строки. То есть если необходимо считать строку, в которой может быть 4 символа, то для нее нужно создать массив char[5] , и функции fgets нужно передавать число, не меньшее 5.

Возвращаемое значение

Функция scanf возвращает значение, равное числу успешно считанных и записанных в переданные параметры значений, что можно использовать для анализа входных данных.

Например, пусть вызвали scanf(«%d:%d», &a, &b) .

Тогда при вводе строки «12:34» функция scanf считает два числа, запишет их в переменные a и b и вернет значение 2. А при вводе «12 34» будет считано только одно число, поскольку после него должно идти двоеточие, то второе число считано не будет и функция scanf вернет значение 1.

Читать еще:  Экспонента в степени паскаль
Ссылка на основную публикацию
Adblock
detector