Символьные строки и строковые функции 435
В системе используется буферизированный ввод-вывод. Это означает, что введенные данные сохраняются во временной памяти (буфере) до тех пор, пока не будет нажата клавиша . В результате этого к введенным данным добавляется символ новой строки, и вся строка передается функции fgets(). При выводе функция fputs() передает символы в другой буфер, и после отправки символа новой строки содержимое буфера передается дисплею.
Тот факт, что функция fgets() сохраняет символ новой строки, порождает проблему, но и предоставляет дополнительную возможность. Проблема заключается в том, что сохранение символа новой строки в виде части строки может быть нежелательным. Преимущество же в том, что присутствие или отсутствие символа новой строки в сохраненной строке может служить индикатором того, была ли прочитана вся строка. Если этого символа нет, можно принимать решение о том, что делать с оставшейся частью строки.
Во-первых, как избавиться от символа новой строки? Один из способов — его поиск в сохраненной строке и замена нулевым символом:
while (words[i] != '\n') // предполагается, что \n присутствует в words
i++;
words[i] = '\0';
Во-вторых, как быть, если в строке ввода по-прежнему остаются символы? Разумный подход на случай, если вся с трока не помещается в целевом массиве, предусматривает игнорирование не умещающейся части:
while (getchar() != '\n') // чтение без сохранения continue; // ввода, включая \n
В листинге 11.9 к этим базовым идеям добавляется дополнительная проверка, что дает в итоге код, который читает строки ввода, удаляет сохраненные символы новой строки, если таковые имеются, и отбрасывает часть строки, которая не умещается в выделенную область памяти.
Листинг 11.9. Программа fgets3. с

436 глава 11
Цикл
while (words[i] != '\n' && words[i] != '\n') i + +;
выполняет проход по строке до тех пор, пока не встретит символ новой строки или нулевой символ (в зависимости от того, что произойдет раньше). Если найденный символ является символом новой строки, то следующий за циклом оператор if заменяет его нулевым символом. В противном случае часть else отбрасывает остаток строки ввода. Ниже показаны результаты пробного запуска:
Введите строки (или пустую строку для выхода из программы):
Эта
Эта
программа, похоже,
программа
не желает принимать длинные строки.
не желает
Но, тем не менее, она не стопорится на
Но, тем н длинных строках.
длинных с
Готово.
Нулевой символ и нулевой указатель
В листинге 11.9 присутствуют и нулевой символ, и нулевой указатель. Концептуально эти две “нулевых” сущности отличаются друг от друга. Нулевой символ, или \0, является символом, применяемым для пометки конца строки С. Этот символ имеет код, равный нулю. Поскольку данный код не соответствует никакому другому символу, нулевой символ не может случайно появиться в какой-то другой части строки.
Нулевой указатель, или null, имеет значение, которое не соответствует какому-то допустимому адресу данных. Он часто используется в функциях, в противном случае возвращающих допустимые адреса, для указания на некоторую специальную ситуацию, такую как обнаружение признака конца файла или невозможность выполнения действия ожидаемым образом.
Итак, нулевой символ имеет целочисленный тип, а нулевой указатель — тип указателя. Иногда путаница возникает из-за того, что числовым представлением их обоих может оказаться значение 0. Но концептуально — это различные типы 0. Кроме того, нулевой символ, будучи символом, занимает один байт, тогда как нулевой указатель, как адрес, обычно занимает четыре байта.
Функция gets_s()
Необязательная функция gets_s() в С11, подобно fgets(), применяет аргумент для ограничения количества читаемых символов. С учетом определений из листин- та 11.9 следующий код будет считывать строку ввода в массив words, обеспечивая появление символа новой строки в числе первых 9 символов ввода:
gets_s(words, STLEN);
Ниже описаны три основных отличия этой функции от fgets().
• Функция gets s() просто выполняет чтение из стандартного ввода, поэтому она не нуждается в третьем аргументе.
• Если функция gets s() считывает символ новой строки, то отбрасывает его, а не сохраняет.
Символьные строки и строковые функции 437
• Если gets_s() прочитает максимальное количество символов, и среди них символ новой строки отсутствует, она предпринимает несколько действий. Функция устанавливает первый символ целевого массива в нулевой символ. Затем она читает и отбрасывает последующие введенные данные, пока не встретится символ новой строки или признак конца файла. Наконец, функция возвращает нулевой указатель. Она вызывает зависящую от реализации функцию “обработчика” (или же выбранную вами функцию), которая может привести к выходу из программы или прекращению ее работы.
Читать дальше