int x;
char s[buf_size];
int i = scanf("Значение x равно '%d', а значение s равно '%s'\n",&x,s);
Здесь функция
scanf()
пытается считать целое число в переменную
x
и последовательность символов, не являющихся разделителями, в массив
s
. Неформатные символы указывают, что они должны содержаться в строке ввода. Рассмотрим пример.
"Значение x равно '123', а значение s равно 'string '\n"
Программа введет число
123
в переменную
x
и строку "
string
", за которой следует
0
, в массив
s
. Если вызов функции
scanf()
завершает работу успешно, результирующее значение (
i
в предыдущем вызове) будет равно количеству присвоенных аргументов-указателей (в данном примере это число равно
2
); в противном случае оно равно
EOF
. Этот способ индикации ввода уязвим для ошибок (например, что произойдет, если вы забудете вставить пробел после строки "
string
" в строке ввода?). Все аргументы функции
scanf()
должны быть указателями. Мы настоятельно рекомендуем не использовать эту функцию.
Как же ввести данные, если мы вынуждены использовать библиотеку
stdio
? Один и из распространенных ответов гласит: “Используйте стандартную библиотечную функцию
gets()
”.
// очень опасный код:
char s[buf_size];
char* p = gets(s); // считывает строку в массив s
Вызов
p=gets(s)
будет вводить символы в массив
s
, пока не обнаружится символ перехода на новую строку или не будет достигнут конец файла. В этом случае в конец строки
s
после последнего символа будет вставлен
0
. Если обнаружен конец файла или возникла ошибка, то указатель p устанавливается равным
NULL
(т.е.
0
); в противном случае он устанавливается равным
s
. Никогда не используйте функцию
gets(s)
или ее эквивалент
scanf("%s",s))!
За прошедшие годы создатели вирусов облюбовали их слабые места: генерируя вводную строку, переполняющую буфер ввода (в данном примере строку
s
), они научились взламывать программы и атаковать компьютеры. Функция
sprintf()
страдает от таких же проблем, связанных с переполнением буфера.
Библиотека
stdio
содержит также простые и полезные функции чтения и записи символов.
Обратите внимание на то, что результатом этих функций является число типа
int
(а не переменная типа
char
или макрос
EOF
). Рассмотрим типичный цикл ввода в программе на языке С.
int ch; /* но не char ch; */
while ((ch=getchar())!=EOF) { /* какие-то действия */ }
Не применяйте к потоку два последовательных вызова
ungetc()
. Результат такого действия может оказаться непредсказуемым, а значит, программа не будет переносимой.
Мы описали не все функции из библиотеки
stdio
, более полную информацию можно найти в хороших учебниках по языку С, например в книге
K&R.
Б.10.3. Строки в стиле языка С
Строки в стиле языка C представляют собой массивы элементов типа
char
, завершающиеся нулем. Эти строки обрабатываются функциями, описанными в заголовках
<cstring>
(или
<string.h>
; примечание:
но не <string>
) и
<cstdlib>
.
Эти функции оперируют строками в стиле языка С с помощью указателей
char*
(указатели
const char*
ссылаются на ячейки памяти, предназначенные исключительно для чтения).
Обратите внимание на то, что в языке C++ функции
strchr()
и
strstr()
дублируются, чтобы обеспечить безопасность типов (они не могут преобразовать тип
const char*
в тип
char*
, как их аналоги в языке C); см. также раздел 27.5.
Функции извлечения символов просматривают строку в стиле языка С в поисках соответственно форматированного представления числа, например "
124
" и "
1.4
". Если такое представление не найдено, функция извлечения возвращает
0
. Рассмотрим пример.
int x = atoi("fortytwo"); /* x становится равным 0 */
Б.10.4. Память
Функции управления памятью действуют в “голой памяти” (без известного типа) с помощью указателей типа
void*
(указатели
const void*
ссылаются на ячейки памяти, предназначенные только для чтения).
Функции
malloc()
и ей подобные не вызывают конструкторы, а функция
free()
не вызывает деструкторы. Не применяйте эти функции к типам, имеющим конструкторы или деструкторы. Кроме того, функция
memset()
также никогда не должна применяться к типам, имеющим конструктор.
Функции, начинающиеся с приставки mem, описаны в заголовке
<cstring>
, а функции выделения памяти — в заголовке
<cstdlib>
.
См. также раздел 27.5.2.
Б.10.5. Дата и время
В заголовке
<ctime>
можно найти несколько типов и функций, связанных с датами и временем.