Стив Саммит. Язык си в вопросах и ответах.Cтандартный ввод/вывод.

Стив Саммит. Язык си в вопросах и ответах.Cтандартный ввод/вывод.

Ответы на вопросы разбиты по темам:

1. Нулевые указатели

2. Указатели и массивы.

3. Выделение памяти

4. Выражения

5. ANSI C

6. Препроцессор С.

7. Списки аргументов переменной длины.

8. Булевы выражения и переменные.

9. Структуры, перечисления и объединения.

10. Декларации.

11. Cтандартный ввод/вывод.

12. Библиотечные функции.

13. Lint.

14. Стиль.

15. Операции с плавающей точкой.

16. Интерфейс с операционной системой.

17. Разное (Пребразование Fortran -> C , грамматики для YACC и т.п.)

Cтандартный    ввод/вывод.

11.1    Что плохого в таких строках:
char c; while((c = getchar())    != EOF)…

О:    Во-первых, переменная, которой присваивается возвращенное getchar значение, должна иметь тип int. getchar может вернуть все возможные значения для символов, в том числе EOF. Если значение, возвращенное getchar присваивается переменной типа char, возможно либо обычную литеру принять за EOF, либо EOF исказится (особенно если использовать тип unsigned char) так, что распознать его будет невозможно.
Смотри: CT&P Разд.5.1 c. 70.

11.2    Как напечатать символ ‘%’ в строке формата printf? Я попробовал \%, но из этого    ничего не вышло.

О:    Просто удвойте знак процента %%    .
Смотри: K&R I Разд. 7.3 c. 147; K&R II Разд. 7.2 c. 154; ANSI Разд. 4.9.6.1 .

11.3    Почему не работает scanf(«%d»,i)?

О:      Для функции scanf необходимы адреса переменных, по которым будут записаны данные, нужно написать scanf(«%d», &i);

11.4    Почему не работает double d; scanf(«%f», &d);

О:    scanf использует спецификацию формата %lf для значений типа double и %f для значений типа float. (Обратите    внимание на несходство с printf,    где в соответствии с правилом расширения типов аргументов спецификация %f    используется как для float, так    и для double).

11.5    Почему фрагмент программы
while(!feof(infp)) { fgets(buf, MAXLINE, infp); fputs(buf, outfp); }
дважды копирует последнюю строку?

О:      Это Вам не Паскаль. Символ EOF появляется только _после_ попытки прочесть, когда функция ввода натыкается на конец файла. Чаще всего необходимо просто проверять значение, возвращаемое функцией ввода, (в нашем случае fgets); в использовании feof() обычно вообще нет необходимости.

11.6    Почему все против использования    gets()?

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

11.7    Почему переменной errno присваивается значение ENOTTY после вызова printf()?

О:      Многие реализации стандартной библиотеки ввода/вывода несколько изменяют свое поведение, если стандартное устройство вывода — терминал. Чтобы определить тип устройства, выполняется операция, которая оканчивается неудачно (c сообщением ENOTTY), если устройство вывода — не терминал. Хотя вывод завершается успешно, errno все же содержит ENOTTY.
Смотри: CT&P Разд. 5.4 c. 73.

11.8    Запросы    моей программы,    а также    промежуточные результаты не всегда отображаются на    экране,    особенно когда моя программа передает данные по каналу (pipe) другой    программе.

О:    Лучше всего явно использовать fflush(stdout), когда непременно нужно видеть то, что выдает программа. Несколько механизмов пытаются «в нужное время» осуществить fflush, но, похоже, все это правильно работает в том случае, когда stdout — это терминал. (см. вопрос 11.7).

11.9    При чтении с клавиатуры функцией scanf возникает чувство, что программа зависает, пока я перевожу строку.

О:      Функция scanf была задумана для ввода в свободном формате, необходимость в котором возникает редко при чтении с клавиатуры. Что же касается ответа на вопрос, то символ «\n» в форматной строке вовсе не означает, что scanf будет ждать перевода строки. Это значит, что scanf будет читать и отбрасывать все встретившиеся подряд пробельные литеры (т.е. символы пробела, табуляции, новой строки, возврата каретки, вертикальной табуляции и новой страницы). Похожее затруднение случается, когда scanf «застревает», получив неожиданно для себя нечисловые данные. Из-за подобных проблем часто лучше читать всю строку с помощью fgets, а затем использовать sscanf или другие функции, работающие со строками, чтобы интерпретировать введенную строку по частям. Если используется sscanf, не забудьте проверить возвращаемое значение для уверенности в том, что число прочитанных переменных равно ожидаемому.

11.10   Я пытаюсь обновить содержимое файла, для чего использую fopen в режиме «r+», далее читаю строку, затем пишу модифицированную строку в файл, но у меня ничего не получается.

О:      Непременно вызовите fseek перед записью в файл. Это делается для возврата к началу строки, которую Вы хотите    переписать; кроме того, всегда необходимо    вызвать    fseek или fflush между чтением и записью    при чтении/записи в режимах «+». Помните также,    что литеры можно заменить лишь точно таким    же числом литер. См. также вопрос 17.4.
Смотри: ANSI Разд. 4.9.5.3 c. 131.

11.11    Как мне    прочитать одну литеру, не дожидаясь нажатия RETURN?

О:    Смотри вопрос 16.1

11.12   Как мне отменить ожидаемый ввод, так, чтобы данные, введенные пользователем, не читались при следующем запросе? Поможет ли здесь fflush(stdin)?

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

11.13   Как перенаправить stdin или stdout в файл?

О:    Используйте freopen.

11.14    Если я использовал freopen, то как вернуться назад к stdout (stdin)?

О:      Если необходимо переключаться между stdin (stdout) и файлом, наилучшее универсальное решение — не спешить использовать freopen. Попробуйте использовать указатель на файл, которому можно по желанию присвоить то или иное значение, оставляя значение stdout (stdin) нетронутым.

11.15    Как восстановить имя файла по указателю    на открытый файл?

О:    Это проблема, вообще говоря, неразрешима. В случае операционной системы    UNIX, например,    потребуется поиск по всему диску (который, возможно, потребует специального разрешения), и    этот поиск окончится неудачно, если указатель на файл был каналом (pipe) или    был связан с удаленным файлом. Кроме того, обманчивый ответ будет получен для файла со множественными связями.  Лучше всего самому запоминать имена при открытии файлов (возможно, используя специальные функции, вызываемые до и после fopen);

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

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