Разница между «% [^ \ n]» и «% [^ \ n] \ n» «и«% [^ \ n]% *c »` в C как они работают? - PullRequest
4 голосов
/ 28 мая 2020

Больше нигде не нашел ответа.

%[^\n] - Когда я запускаю это, scanf получает ввод и завершается после того, как я нажму клавишу ввода. (Вероятно, оставив \n в системе ввода)

%[^\n]\n - этот получает ввод, но scanf НЕ завершается сразу после того, как я нажимаю клавишу ввода, как показано выше. Я нажимаю еще Enter, и появляется больше новых строк. Когда я ввожу символ, а затем нажимаю ввод, он, наконец, завершается. Пример:

int main(void)
{
    char s[100];

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

    printf("%s", s);

    return 0;
}

Результаты:

enter image description here

Последний:

%[^\n]%*c - Когда я ввожу какие-то данные и нажимаю Enter. scanf немедленно завершается.

Как эти 3 работают и чем они отличаются?

1 Ответ

3 голосов
/ 29 мая 2020

Все 3 формата начинаются с "%[^\n]".

"%[^\n]" - это плохой код 2 , который не имеет ограничения по ширине и подвержен переполнению буфера. Используйте ограничение width , например "%99[^\n]" с char s[100];.

"%[...]" не использует начальные пробелы, как многие другие спецификаторы.

Этот спецификатор направляет ввод для чтения до тех пор, пока не встретится '\n' 1 . '\n' возвращается в stdin. Все остальные символы сохраняются в соответствующем целевом массиве s.

Если символы не были прочитаны (не считая '\n'), спецификатор не работает и scanf() возвращает без изменения s - остальной формат не используется. Нет нулевой символ добавлен.

Если символы были прочитаны, они сохраняются, а нулевой символ добавляется к s, и сканирование продолжается со следующей части формат.

"\n" действует так же, как " ", "\t", "any_white_space_chracter" и считывает и отбрасывает 0 или более пробелов. Это продолжается до тех пор, пока не будет прочитано 1 , отличное от пробелов. Этот непробельный символ возвращается в stdin.

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

С scanf() "\n" в конце формата будет плохим и вызвал проблему OP.

"%*c" читает 1 символ 1 и отбрасывает его - даже если это не '\n'. Этот спецификатор не влияет на счетчик возврата из-за '*'.

Лучшая альтернатива - использовать fgets().

char s[100];
if (fgets(s, sizeof s, stdin)) {
   s[strcspn(s, "\n")] = '\0';  // To lop off potential trailing \n

Меньшая альтернатива -

char s[100] = { 0 };
scanf("%99[^\n]", s);
// With a separate scanf ....
scanf("%*1[\n]");  // read the next character if it is a \n and toss it.

1 ... или конец файла, или редкая ошибка ввода.

2 IMO, хуже, чем gets() .

...