Вы scanf
спецификатор формата "%[^105]s"
использует класс символов [...]
, который сам по себе является спецификатором и не требует 's'
вконец.Помещая 's'
в конце, вы заставляете scanf
искать литерал 's'
после неограниченного числа символов, НЕ включая 1, 0, 5
.
Похоже, вы намеревались использовать число для защитыграницы ваших массивов - это хорошо, но правильный формат в этом случае - "%104[^\n]"
, который будет читать до 104
символов, которые не включают '\n'
(сохраняя пробел для нуль-символа).
Например:
if (scanf("%104[^\n]",z) == 1)
printf("%s %s\n",s,z);
( примечание: ВСЕГДА проверять ВСЕ пользовательские данные путем минимальной проверки возврата)
Также обратите внимание: , НЕ читая '\n'
выше, он останется в вашем входном буфере (stdin
) непрочитанным, и если ваша следующая попытка ввода будет "%c"
или "%[...]"
, вы будетепримите '\n'
как часть вашего ввода, поскольку nether "%c"
или `"% [...] "потребляют начальные пробелы.
Соберите его вместе в примере, который вы можете сделать:
#include <stdio.h>
int main (void) {
char s[] = "Apple";
char z[105];
printf ("enter z: ");
if (scanf("%104[^\n]",z) == 1)
printf("%s %s\n",s,z);
else
fputs ("error: stream error or user canceled.\n", stderr);
return 0;
}
( примечание: вместо scanf
для чтения строк рекомендуется fgets()
, затем простообрезать '\n'
, включенный в заполненный буфер)
Пример использования / вывода
$ ./bin/oneline
enter z: is a fruit
Apple is a fruit
Использовать fgets()
Вместо
Вместо использования scanf
для ввода строки используйте строчно-ориентированную функцию ввода, такую как fgets()
, которая будет использовать всю строку (включая конец строки).Гарантирует, что ваш входной буфер остается в согласованном состоянии, которое не зависит от предыдущего пользователя спецификатора формата, например,
...
#include <string.h>
...
printf ("enter z: ");
if (fgets (z, sizeof z, stdin) != NULL) {
z[strcspn (z, "\n")] = 0; /* trim '\n' from end of z */
printf("%s %s\n",s,z);
}
Редактировать вопрос в комментарии
Ваша проблема с вашим новым кодом scanf("%lf",&y);
оставляет '\n'
в stdin
непрочитанным , затем вы пытаетесь прочитать scanf("%[^105\n]",z);
, который читает ничего потому что вы исключили чтение '\n'
в классе инвертированных символов , а затем прочитали stdin
как ввод, где первый символ равен '\n'
."%[^105\n]"
означает: читать неограниченное количество символов и останавливать чтение, только если встречается символ 1, 0, 5
или '\n'
(или EOF
).
Принимая смешанный ввод с scanf
полон Подводных камней для новых программистов на C из-за того, что осталось в stdin
, и как ведущие пробелыОбработка зависит от используемого спецификатора формата .Вот почему fgets()
(или POSIX getline()
) рекомендуется для пользовательского ввода, а затем анализирует необходимую информацию из заполненного буфера с помощью sscanf
.При использовании строчно-ориентированной функции ввода строка полностью используется на каждом входе (при условии достаточного размера буфера - не экономьте), устраняя проблемы с scanf
.
Чтобы ваш текущий код работал, вы могли бы сделать:
#include <stdio.h>
/* simple function to empty remainder of line in stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
int i = 4, x;
double d = 4.0, y;
char s[] = "Apple ", z[105];
scanf("%d",&x);
scanf("%lf",&y); /* leaves '\n' as next char in stdin */
empty_stdin(); /* empty extraneous characters */
scanf("%104[^\n]",z); /* read up to 104 chars, \n, or EOF */
printf("%d\n",i+x);
printf("%0.1lf\n",d+y);
printf("%s %s\n",s,z);
return 0;
}
( проверять каждый вызов scanf
- это вам осталось)
Позвольте мнезнать, если у вас есть дополнительные вопросы.