Перейти к содержимому

Sscanf си что это

  • автор:

sscanf , _sscanf_l , swscanf , _swscanf_l

format
Строка управления форматом. Дополнительные сведения см. в разделе «Синтаксис спецификации формата».

argument
Необязательные аргументы

locale
Используемый языковой стандарт

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

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

Если buffer или format является NULL указателем, вызывается обработчик недопустимых параметров, как описано в разделе проверки параметров. Если разрешается продолжать выполнение, эти функции возвращают -1 и задают errno значение EINVAL .

Дополнительные сведения об этих и других кодах ошибок см. в разделе errno , _doserrno _sys_errlist и _sys_nerr .

Замечания

Функция sscanf считывает данные из buffer в расположение, заданное параметрами argument . Каждый параметр argument должен быть указателем на переменную, которая имеет тип, соответствующий спецификатору типа в параметре format . Аргумент format определяет интерпретацию полей входных данных и имеет такую же форму и функцию, как аргумент format для функции scanf . Если копирование производится между перекрывающимися строками, поведение не определено.

Сведения о символах полей типа scanf см. в разделе scanf «Символы полей типа». Сведения о полях спецификации формата scanf см. в разделе «Поля спецификации форматирования».

При чтении строки с sscanf всегда указывайте ширину формата %s (например, » %32s « вместо » %s « ); в противном случае неправильно отформатированные входные данные могут легко вызвать переполнение буфера.

swscanf — это двухбайтовая версия sscanf ; аргументы для swscanf представляют собой двухбайтовые строки. sscanf не обрабатывает шестнадцатеричные шестнадцатеричные символы. swscanf не обрабатывает шестнадцатеричные или шестнадцатеричные символы зоны совместимости Юникода. В противном случае поведение swscanf и sscanf идентично.

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

Сопоставления подпрограмм универсального текста

TCHAR.H Обычной _UNICODE и _MBCS не определен _MBCS Определенные _UNICODE Определенные
_stscanf sscanf sscanf swscanf
_stscanf_l _sscanf_l _sscanf_l _swscanf_l

Требования

Маршрут Обязательный заголовок
sscanf , _sscanf_l
swscanf , _swscanf_l или

Дополнительные сведения о совместимости см. в разделе Совместимость.

Пример

// crt_sscanf.c // compile with: /W3 // This program uses sscanf to read data items // from a string named tokenstring, then displays them. #include int main( void ) < char tokenstring[] = "15 12 14. "; char s[81]; char c; int i; float fp; // Input various data from tokenstring: // max 80 character string: sscanf( tokenstring, "%80s", s ); // C4996 sscanf( tokenstring, "%c", &c ); // C4996 sscanf( tokenstring, "%d", &i ); // C4996 sscanf( tokenstring, "%f", &fp ); // C4996 // Note: sscanf is deprecated; consider using sscanf_s instead // Output the data read printf( "String = %s\n", s ); printf( "Character = %c\n", c ); printf( "Integer: = %d\n", i ); printf( "Real: = %f\n", fp ); >
String = 15 Character = 1 Integer: = 15 Real: = 15.000000 

Sscanf си что это

Функция sscanf считывает данные из строки (массива символов) в переменные. Функция имеет следующий синтаксис

int sscanf (const char * buffer, const char * format, …);

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

Считаем данные из строки

#include int main(void)

В данном случае строка, из которой считываются данные:

"F 69 123.45"

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

Эту строку передаем в функцию sscanf первым аргументом и считываем ее значения в переменные c , n , d :

А второй аргумент — формат считывания определяет, как данные из строки будут сопоставляться с переменными:

"%c %d %lf"

Поскольку значения в строке buff разделены пробелами, то и в строки форматирования спецификаторы разделены пробелами. Первый спецификатор %c позволяет считать первый символ в переменную типа char c .

Второй спецификатор — %d обеспечивает считывание целого числа в переменную n .

И третий спецификатор %lf считывает данные в переменную типа double — d

То есть в итоге консольный вывод был бы следующим:

Values: F, 69, 123.450000

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

#include int main(void)

Еще один пример. Пусть в строке содержатся данные пользователя, как имя, возраст, зарплата. Считаем эти данные в переменные:

#include int main(void)

Причем строка форматирования может быть более сложной. Например:

#include int main(void) < char *buff = "Name is Tom and age is 38"; char name[10]; int age; sscanf(buff, "Name is %s and age is %d", name, &age); printf("Name: %s \tAge: %d\n", name, age); // Name: Tom Age: 38 return 0; >

В данном случае исходная строка представляет текст «Name is Tom and age is 38» . И на эту строку накладывается строка форматирования «Name is %s and age is %d» . Соответственно здесь спецификатор %s будет представлять строку «Tom», а спецификатор %d — число 38.

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

Комбинируя это функцию с fgets() , можно считывать данные с консоли:

#include int main(void) < char buff[50]; char name[10]; int age; double salary; printf("Enter the data\n"); if(!fgets(buff, 50, stdin)) < printf("Fatal Error!\n"); return 1; >sscanf(buff, "%s %d %lf", name, &age, &salary); printf("Name: %s \tAge: %d \tSalary: %.2lf\n", name, age, salary); return 0; >

Пример консольного ввода:

Enter the data Tom 38 456.78 Name: Tom Age: 38 Salary: 456.78

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

sprintf

Функция sprintf производит обратное действие — записывает данные в строку:

int sprintf(char *_Buffer, const char *_Format, . )

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

#include void main (void) < int age = 38; char* name = "Tom"; char text[50]; int charNumber = sprintf (text, "Name: %s Age: %d\n", name, age); printf (text); // Name: Tom Age: 38 printf("text length: %d", charNumber); // text length: 19 >

В данном случае в переменную text записывается строка «Name: %s Age: %d\n» , в которую вместо спецификаторов подставляются значения переменных name и age .

Форматированный ввод данных в Си — функция scanf

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

scanf(строка_формата, адреса_переменных);

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

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

Ввод чисел, символов и строк

Пример ввода-вывода целого и вещественного чисел, символа и строки:

int a; float b; char ch, str[30]; scanf("%d%f%c%s", &a, &b, &ch, str); printf("%d %.3f %c %s\n", a, b, ch, str);
45 34.3456y hello 45 34.346 y hello

Здесь при выполнении программы все данные были введены в одну строку. Разделителем между числами и строками является пробел, а также любой другой символ пустого пространства (например, ‘\n’). Однако при считывании символа, пробел учитывается как символ; чтобы этого не произошло, в примере букву записали сразу после числа. Данные можно было бы ввести, разделяя их переходом на новую строку (опять же при этом надо иметь ввиду, как считывается символ).

В строке формата функции scanf() между спецификациями вполне допустимо поставить пробелы: %d %f %c %s . Они никакой роли не сыграют. Понятно, что данные можно было получить и так:

scanf("%d", &a); scanf("%f", &b); scanf("%c", &ch); scanf("%s", str);

Обратите внимание, перед переменной str отсутствует знак амперсанда. В последующих уроках вы узнаете, что имя массива уже само по себе является ссылкой на массив (другими словами, str содержит адрес начала массива).

В функции scanf() в спецификации формата вещественных чисел не указывается точность представления числа. Запись типа %.3f или %.10lf приведет к невозможности получить вещественное число. Чтобы получить число типа double используют формат %lf , для long double ‒ %Lf .

Для целых чисел: длинное целое ‒ %ld , короткое целое ‒ %hd . Существуют спецификации для ввода восьмеричных и шестнадцатеричных чисел.

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

int a; double b; char ch, str[30]; ch = scanf("%d %lf %s", &a, &b, str); if (ch == 3) printf("%d %.3lf %s\n", a, b, str); else printf("Error input\n");

Обычные символы в строке формата

В строке формата scanf() допустимо использование обычных символов. В этом случае при вводе данных также должны вводиться и эти символы:

int a, b, c; scanf("%d + %d = %d", &a, &b, &c); printf("Your answer is %d\n", c); printf("The correct is %d\n", a+b);

В данном случае, когда программа выполняется, ввод должен выглядеть примерно так: 342+1024 = 1366. Знаки «+» и » lang»>% , но перед буквой формата звездочку * . В таком случае данные считываются, но никакой переменной не присваиваются. Это можно использовать, например, когда нет определенной уверенности в том, что поступит на ввод, с одной стороны, и нужды сохранять эти данные, с другой:

float arr[3]; int i; for(i = 0; i  3; i++) scanf("%*s %f", &arr[i]); printf("Sum: %.2f\n", arr[0]+arr[1]+arr[2]);

Здесь предполагается, что перед каждым числом будет вводиться строка, которую следует проигнорировать, например:

First: 23.356 Second: 17.285 Third: 32.457 Sum: 73.098

Использование «шаблонов»

Для функции scanf() есть пара спецификаций формата, отдаленно напоминающих шаблоны командной оболочки и др. Формат […] позволяет получить строку, содержащую любые символы, указанные в квадратных скобках. Как только на ввод поступает символ, не входящий в указанный набор, считывание данных прекращается. Формат [^…] , наоборот, помещает в строку символы, не входящие в указанный набор, до тех пор пока не встретит любой из указанных.

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

char str[30]=""; scanf("%[0-9]", str); printf("%s\n", str);

А в этом случае строке будет присвоена последовательность символов до любого из указанных знаков препинания:

scanf("%[^;. ]", str); printf("%s\n", str);
one two three four five! one two three four five

Обратите внимание, что в примере выше в строку были записаны как символы пробелов, так и символ перехода на новую строку. Таким образом, если надо прочитать одну строку вместе с пробелами, можно использовать такой подход:

scanf("%[^'\n']", str);

Здесь в строку считываются все символы, кроме перехода на новую строку. Как только встречается этот символ ‒ ‘\n’ , запись данных в переменную прекращается.

Некоторые особенности и ограничения функции scanf

Как только поступают некорректные данные, функция scanf() завершает свою работу. В примере:

scanf("%d%f", &a, &b);

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

scanf("%d", &a); scanf("%f", &b);

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

// если данные не удалось присвоить, if (scanf("%d", &a) != 1) // то выбросить их в виде строки scanf("%*s"); scanf("%f", &b);
  1. На прошлом занятии вы написали программу, содержащую функции, вычисляющие факториал числа и заданный элемент ряда Фибоначчи. Измените эту программу таким образом, чтобы она запрашивала у пользователя, что он хочет вычислить: факториал или число Фибоначчи. Затем программа запрашивала бы у пользователя либо число для вычисления факториала, либо номер элемента ряда Фибоначчи.
  2. Напишите программу, которая запрашивает у пользователя две даты в формате дд.мм.гггг. Дни, месяцы и года следует присвоить целочисленным переменным. Программа должна выводить на экран информацию о том, какая дата более ранняя, а какая более поздняя.
  3. Используя цикл, напишите код, в котором пользователю предлагается вводить данные до тех пор, пока он не сделает это корректно, т.е. пока все указанные в scanf() переменные не получат свои значения. Протестируйте программу.

Курс с решением задач:
pdf-версия

Sscanf си что это

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

int scanf(char *format, . )

Функция scanf читает символы из стандартного входного потока, интерпретирует их согласно спецификациям строки format и рассылает результаты в свои остальные аргументы. Аргумент-формат мы опишем позже; другие аргуметы, каждый из которых должен быть указателем , определяют, где будут запоминаться должным образом преобразованные данные. Как и для printf , в этом параграфе дается сводка наиболее полезных, но отнюдь не всех возможностей данной функции.

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

Существует также функция sscanf , которая читает из строки, (а не из стандартного ввода).

int sscanf(char *string, char *format, arg1, arg2, . )

Функция sscanf просматривает строку string согласно формату format и рассылает полученные значения в arg 1 , arg 2 , и т.д. Последние должны быть указателями.

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

  • Пробелы или табуляции, которые игнорируются.
  • Обычные символы (исключая % ), которые, как ожидается, совпадут с очередными символами, отличными от символов-разделителей входного потока.
  • Спецификации преобразования, каждая из которых начинается со знака % и завершается символом-спецификатором типа преобразования. В промежутке между этими двумя символами в любой спецификации могут располагаться, причем в том порядке, как они здесь указаны: знак * (признак подавления присваивания); число, определяющее ширину поля; буква h , l или L , указывающая на размер получаемого значения; символ преобразования ( o , d или x ).

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

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

Таблица 7.2. Основные преобразования scanf

Символ Вводимые данные; тип аргумента
d десятичное целое; int *
i целое; int * . Число может быть восьмеричным (с 0 слева) или шестнадцатеричным (с 0x или 0X слева)
o восьмеричное целое (с нулем слева или без него); int *
u беззнаковое десятичное целое; unsigned int *
x шестнадцатеричное целое (с 0x или 0X слева или без них); int *
c символы; char * . Следующие символы из входного потока (по умолчанию один) размещаются в указанном месте. Обычный пропуск символов-разделителей подавляется; чтобы прочесть очередной символ, отличный от символа-разделителя, используйте спецификацию %1s
s строка символов (без обрамляющих кавычек); char * , указывающий на массив символов, достаточный для хранения строки и завершающего символа ‘\0’ , который будет добавлен автоматически
e , f , g число с плавающей точкой, возможно со знаком; обязательно присутствие либо десятичной точки, либо экспоненциальной части, а возможно, и обеих вместе; float *
% сам знак % , никакое присваивание не выполняется

Перед символами-спецификаторами d , l , o , u и x может стоять буква h , указывающая на то, что соответствующий аргумент должен иметь тип short * (а не int * ), или l , указывающая на тип long * . Аналогично, перед символами-спецификаторами e , f и g может стоять буква l , указывающая, что тип аргумента — double * (а не float * ).

Чтобы построить первый пример, обратимся к программе калькулятора из главы 4, в которой организуем ввод с помощью функции scanf :

#include main() /* программа-калькулятор */

Предположим, что нам нужно прочитать вводимые строки, содержащие данные вида

25 дек 1988

Обращение к scanf выглядит следующим образом:

int day, year; /* день, год */ char monthname[20]; /* название месяца */ scanf("%d %s %d", &day, monthname, &year);

Знак & перед monthname не нужен, так как имя массива является указателем.

В строке формата могут присутствовать символы, не участвующие ни в одной из спецификаций; это значит, что эти символы должны появиться на вводе. Так, мы могли бы читать даты вида mm/dd/yy с помощью следующего обращения к scanf :

int day, month, year; /* день, месяц, год */ scanf("%d/%d/%d", &day, &month, &year);

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

while (getline(line, sizeof(line)) > 0) < if (sscanf(line, "%d %s %d", &day, monthname, &year) == 3) printf("Верно: %s\n", line); /* в виде 25 дек 1988 */ else if (sscanf(line, "%d/%d/%d", &month, &day, &year) == 3) printf("Верно: %s\n", line); /* в виде mm/dd/yy */ else printf("Неверно: %s\n", line); /*неверная форма даты */ >

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

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

Одна из самых распространенных ошибок состоит в том, что вместо того, чтобы написать

scanf("%d", &n);
scanf("%d", n);

Компилятор о подобной ошибке ничего не сообщает.

Упражнение 7-4

Напишите свою версию scanf по аналогии с minprintf из предыдущего параграфа.

Упражнение 7-5

Перепишите основанную на постфиксной записи программу калькулятора из главы 4 таким образом, чтобы для ввода и преобразования чисел она использовала scanf и/или sscanf .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *