Разница между scanf(«y[^ n]», строка); против scanf(«y[^ n] n», строка) и scanf(«y [^ n] s», строка)

#c #scanf

#c #сканф

Вопрос:

Я писал программу на языке Си для чтения содержимого файла. Код выглядит следующим образом:

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

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

Но

 while(scanf("y[^n]",line)==1) and while(scanf("y[^n]s",line)==1) or while(scanf("y[^n]sn",line)==1) 
 

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

Кто-нибудь может объяснить?

Комментарии:

1. Первый предназначен для приема ввода типа ‘string’

2. @шекхар суман… все они принимают строки

3. y[^n] является строкой формата, не нуждается в последующей фиксации s . Вторая новая строка y[^n]n буквально переходит на следующую строку

4. Я думаю, что мини-регулярное [^n] выражение заменяет спецификатор s формата. Остальные будут совпадать, если у вас есть литерал s в конце строки.

Ответ №1:

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

Когда вы используете,

 scanf("y[^n]s",line)
 

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

Когда вы используете,

 scanf("y[^n]n",line)
 

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

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

 scanf("y[^n]",line)
 

и

 scanf("y[^n]n",line)
 

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

Если вы хотите scanf потреблять только 'n' то, что нужно, используйте:

 scanf("y[^n]%*c",line)
 

Комментарии:

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

2. «возвращаемое значение не должно быть 1» вводит в заблуждение. При scanf("y[^n]s",line) этом, если отсканировано от 1 до 79 char line , scanf() будет возвращено 1. Совпадение или 's' несоответствие литерала не влияет на scanf() результат.

3. Аналогично scanf("y[^n]n",line) возвращает 1, если он сканирует что-либо line . Нахождение (или не нахождение) следующего "n"' does not change the return value of scanf() . The » n»‘ влияет на использование пробелов после сканирования line .

4. Уверен, что вы хотите scanf("y[^n]*c",line) —> scanf("y[^n]%*c",line)

5. Спасибо, отличные глаза. Исправил ответ. Спасибо, что дали мне знать.

Ответ №2:

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

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

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

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

Комментарии:

1. Я думаю, что проблема с длиной строки может быть исправлена с помощью while ( scanf("y[^n]%*[^n]", line) ) { getchar(); printf("%sn", line); }

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

3. @Matt McNabb Примечание: scanf("y[^n]%*[^n]" застревает, если первое char есть 'n' . Он также потребляет несколько 'n' , которые могут / не могут быть в порядке.

4. Предлагаю отредактировать: » 'n' в конце вы указываете scanf читать и игнорировать все последовательные символы конца строки (и любые другие пробелы) после чтения строки»

5. @chux Он не использует несколько новых строк, и n в конце это было бы плохо, так как тогда он использует другие пробелы в начале следующей строки. Однако вы правы, что scanf возвращает 0 , если [] соответствует пустой строке.

Ответ №3:

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

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

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

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

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

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

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

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

Ответ №4:

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

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

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