2014-06-25 7 views
3

Я писал программу в c, чтобы прочитать содержимое файла. код выглядит следующим образом:Разница между scanf ("% 79 [^ n]", строка); vs scanf ("% 79 [^ n] n", строка) vs scanf ("% 79 [^ n] s", строка)

#include<stdio.h> 
    void main() 
    { 
    char line[90]; 
    while(scanf("%79[^\n]\n",line)==1) 
    printf("%s",line); 
    } 

Приведенный выше код считывает содержимое файла и отображает его на экране.

Но

while(scanf("%79[^\n]",line)==1) and while(scanf("%79[^\n]s",line)==1) or while(scanf("%79[^\n]s\n",line)==1) 

не работает. (Они показывают только первую строку)

Может кто-нибудь объяснить?

+0

Первый - для ввода ввода типа 'string' –

+0

@shekhar suman ... все они принимают строки – dividedbyzero

+1

'% 79 [^ \ n]' это строка формата, не обязательно должна быть пост- исправлено с 's'. Вторая новая строка '% 79 [^ \ n] \ n' буквально переходит к следующей строке –

ответ

5

В формате "%79[^\n]" указаны все символы до 79 символов, которые не являются '\n'.

При использовании,

scanf("%79[^\n]s",line) 

возвращаемое значение не должно быть 1, так как s в формате спецификатор ожидает буквального s после того, как он закончил читать все символы, которые не '\n'. Другими словами, scanf сообщает об ошибке.

При использовании,

scanf("%79[^\n]\n",line) 

это удается, потому что он находит в буквальном смысле '\n' в конце.

Разница между

scanf("%79[^\n]",line) 

и

scanf("%79[^\n]\n",line) 

является то, что '\n' остается во входном потоке в первом случае в то время как он потребляется во втором случае. Во втором случае потребляется не только '\n', но и любая последовательность пробелов, начинающихся с '\n', также потребляется (благодаря @MattMcNabb для дополнительного пояснения).

Если вы хотите scanf потреблять только '\n', использование:

scanf("%79[^\n]%*c",line) 
+2

Обратите внимание, что '\ n', вне квадратных скобок, соответствует * любой последовательности пробелов *, а не только одной новой строки. Эта версия также будет использовать любые ведущие пробелы в следующей строке. –

+0

«возвращаемое значение не должно быть 1» неверно. С 'scanf («% 79 [^ \ n] s », строка)', если от 1 до 79 'char' сканируются в' line', 'scanf()' вернет 1. Согласование или несоответствие литерала '' s'' не влияет на результат 'scanf()'. – chux

+0

Like-wise 'scanf ("% 79 [^ \ n] \ n ", line)' возвращает 1, если он что-то сканирует в 'line'. Поиск (или не поиск) следующего '' \ n "'не изменяет возвращаемое значение' scanf() '. «\ N» «влияет на потребление белого пространства после сканирования в строке« строка ». – chux

1

Поскольку сам формат такой же, ключ к решению этого, как вы можете, конечно, сказать, завершающий символ после строки формата (или отсутствие этого персонажа)

  • Когда вы '\n' в конце вы скажете scanf, чтобы прочитать и проигнорировать символ конца строки после прочтения строки. Это отлично работает, потому что '\n' - это то, что завершает строку в соответствии с вашим форматом (то есть %79[^\n]).
  • Когда вы положили 's' в конец, вы сообщите scanf, что вы ожидаете буквально s после строки, которая заканчивается на '\n'. Это ошибка, потому что scanf будет читать строку до и, исключая, символ '\n' *.
  • Когда вы не положите '\n' в конец, первое чтение будет успешным, но все последующие будут натыкаться на '\n' и сразу же прекратить чтение.

Обратите внимание, что код, который работает, может привести к неожиданным результатам для строк ввода, которые превышают 79 символов. Эти строки будут разбиты на 79-значную метку, а их остальная часть будет представлена ​​как начало следующей строки.

* Существует маловероятная ситуация, когда это чтение будет успешным - а именно, когда чтение прекращается в связи с достижением предела 79, и затем открывать письмо s на 80-м пространстве.

+0

Я думаю, что проблема длины строки может быть исправлена ​​'while (scanf ("% 79 [^ \ n]% * [^ \ n] ", строка)) {getchar(); printf ("% s \ n", строка); } ' –

+0

@MattMcNabb Ах, я вижу вашу точку зрения - вы правы, это устранит проблему с разделением длинных строк. Спасибо! – dasblinkenlight

+0

@Matt McNabb Примечание: 'scanf ("% 79 [^ \ n]% * [^ \ n] "' застревает, если первый символ '' '\ n''. Он также потребляет несколько' '\ n '', который может/не может быть ОК. – chux

0

Ее возможно, что проблема concested для логических значений shortcircuting. т.е. когда компилятор сдерживает, что у него достаточно информации для оценки всего выражения, ему не нужно проверять другие логические значения (и не оценивает их).

i.e. false и call_foo() всегда оцениваются как false, поэтому call_foo() никогда не вызывается.

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

1

Много тонких различий:

1) "%79[^\n]" рассказывает scanf() для сканирования и сохранения 1 до 79 char кроме '\n'. Если первый попытался выполнить сканирование, то \n, ничего не останется. В примерах OP возвращается 0. Else a '\0' добавляется к пункту назначения line. Возвращается 1, если ничего больше.

2) "%79[^\n]\n" делает 1), и в случае успеха продолжает искать любой подряд бело-пространстве, а не только '\n'. Это, как правило, включает '\n'и, затем все ведущие пробелы next. Он будет возвращать 1 независимо от того, найдет ли оно пробел.

3) "%79[^\n]s" делает 1 и в случае успеха продолжает оставаться единственным s. Он вернется 1 независимо от того, найдет ли он s. Вероятно, это не желание OP - оставьте 's'.

4) "%79[^\n]s\n" делает 3) и в случае успеха, ведет себя как 2) продолжает искать любой подряд бело-пространстве, а не только '\n'. Он будет возвращать 1 независимо от того, найдет ли оно пробел.

5) Заявление 3 while() довольно сложное, взятое в целом. Он застревает, пытаясь прочитать '\n' в начале 1 из 3 scanf().

Лучший подход, если код должен использовать scanf() для чтения строки, является
while (scanf(" %79[^\n]%*c", line) ==1). Это будет подбрасывать ведущее белое пространство, а затем читать строку до '\n', подбрасывая это '\n' через "%*c".

Наилучший подход - использовать fgets(line, sizeof line, stdin).

Смежные вопросы