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);
- На прошлом занятии вы написали программу, содержащую функции, вычисляющие факториал числа и заданный элемент ряда Фибоначчи. Измените эту программу таким образом, чтобы она запрашивала у пользователя, что он хочет вычислить: факториал или число Фибоначчи. Затем программа запрашивала бы у пользователя либо число для вычисления факториала, либо номер элемента ряда Фибоначчи.
- Напишите программу, которая запрашивает у пользователя две даты в формате дд.мм.гггг. Дни, месяцы и года следует присвоить целочисленным переменным. Программа должна выводить на экран информацию о том, какая дата более ранняя, а какая более поздняя.
- Используя цикл, напишите код, в котором пользователю предлагается вводить данные до тех пор, пока он не сделает это корректно, т.е. пока все указанные в 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);
Компилятор о подобной ошибке ничего не сообщает.
Напишите свою версию scanf по аналогии с minprintf из предыдущего параграфа.
Перепишите основанную на постфиксной записи программу калькулятора из главы 4 таким образом, чтобы для ввода и преобразования чисел она использовала scanf и/или sscanf .