Разница между %d и %d при сканировании на языке C

Если я кодирую, как показано ниже

int main()
{
    int num;

    for(int i = 0; i < 3; i++)
    {
        printf("enter an integer\n");
        scanf("%d", &num);
        printf("%d\n", num);
    }
    return 0;
}

а затем введите «1 2 3», вывод

enter an integer
1 2 3
1
enter an integer
2
enter an integer
3

Я знаю, что это потому, что буфер содержит 1, 2, 3 в то время, когда ввод

однако, когда я добавляю пробел от "%d" до "%d" в scanf и ввожу то же самое "1 2 3", как и раньше,

вывод

enter an integer
1 2 3
1
enter an integer
2
enter an integer

Это не продолжалось, как раньше, с небольшими изменениями с "%d"

почему это происходит?


person Seil Lee    schedule 22.01.2020    source источник


Ответы (1)


Разница между «%d» и «%d» в scanf на языке C

Разница в том, что когда вы используете %d в качестве строки формата, scanf()продолжает использовать пробельные символы, пока не встретит другой непробельный символ, например, 2,3,4. Простой символ новой строки \n или другой символ пробела после введенного числа не нарушит потребление.

Принимая во внимание, что когда вы используете %d только без пробела после спецификатора формата, символ пробела, такой как новая строка \n, прерывает использование.


Это не продолжалось, как раньше, с небольшими изменениями с %d

Почему это происходит?

Причина в том, что scanf("%d ", &num); после того, как он израсходовал 3 при третьем проходе цикла for, по-прежнему использует завершающий пробел до тех пор, пока не найдет другой символ.

3 не печатается, потому что scanf() все еще потребляет. Вся программа будет завершена только в том случае, если вы введете другой символ, например 4, в этом конкретном случае. Это будет работать, потому что цикл for имеет только 3 прохода тела. Если бы у него было больше, чем это, это даже не сработало бы. Вам нужно иметь еще один символ в stdin, так как у вас есть пошаговые инструкции по циклу for с такого рода программами.

person RobertS supports Monica Cellio    schedule 22.01.2020
comment
Вся программа завершится, только если вы введете другой символ.... -- Сигнализация конца файла с клавиатуры с помощью Ctrl-D (Linux) или Ctrl-C (Windows) также будет работать. - person ad absurdum; 22.01.2020
comment
@exnihilo Действительно точно; но это требует действий от пользователя. Если бы пользователь ничего не делал или другая программа записывала символы в stdin, программа не остановится сама с этим буфером. - person RobertS supports Monica Cellio; 22.01.2020
comment
Дело в том, что scanf() не вернется, пока не будет найдено совпадение или до конца файла. Вам нужен еще один символ — это не совсем правильно. Если ввод перенаправляется из файла, scanf() вернется, когда будет достигнут конец файла. Мой ответ на повторяющийся вопрос обсуждает это. - person ad absurdum; 22.01.2020
comment
@exnihilo При третьем вызове scanf(), когда 3 потребляется, он ищет другой небелый символ. Если он встретит один, например 4, он должен завершить соответствующее потребление, scanf() вернется, 3 будет напечатано со следующим printf(), и, поскольку цикл не имеет дальнейших итераций, программа будет завершена. Во всяком случае, я еще не видел вашего ответа и обсуждения в дубликате. Я посмотрю на это сейчас. - person RobertS supports Monica Cellio; 22.01.2020
comment
@exnihilo Хорошо, я прочитал это сейчас. +1 за ваш ответ. - Теперь я понимаю, что вы имеете в виду - Когда он встречает конец файла, потребление также завершается ошибкой, и scanf() возвращает EOF. Да, я забыл упомянуть об этом. Я учту это в своем ответе. - person RobertS supports Monica Cellio; 22.01.2020
comment
@exnihilo Итак, мое предположение, что программа не завершится, неверно, верно? Он заканчивается; scanf() в этом случае возвращает EOF, но следующее printf() просто не может распечатать его на терминале. - person RobertS supports Monica Cellio; 22.01.2020
comment
scanf() возвращает EOF. Обратите внимание, что scanf() возвращает EOF только в случае сбоя ввода (редко) перед первым преобразованием; в противном случае возвращается количество успешных преобразований. Вы правы в том, что scanf() не завершается в приведенном выше коде, если только ввод не был перенаправлен из файла, и в этом случае конец файла приведет к возврату scanf(). Если пользователь вводит другой символ (как вы предложили) или, если он сигнализирует EOF с клавиатуры, scanf() также вернется. Во всех этих случаях будет выполнен последний printf(). - person ad absurdum; 22.01.2020
comment
@exnihilo Что вы имеете в виду под перенаправлением из файла? Я думал, мы говорим только о файле stdin? И почему во всех случаях он приходит к финальному printf() - Во всех этих случаях будет выполнен финальный printf(). - если scanf() не завершится? - person RobertS supports Monica Cellio; 22.01.2020
comment
Если пользователь вводит ввод, нажимая ввод после 3, как это делал OP, scanf() будет бесконечно ждать ввода. Если этот ввод является пробелом, он будет соответствовать и продолжит ожидание. Если этот ввод не является пробельным символом, совпадение не выполняется, возвращается scanf() и выполняется последнее printf(). Если вместо этого после нажатия [ENTER] пользователь подаст сигнал eof с помощью Ctrl-D, scanf() вернется и будет выполнено последнее printf(). Или, если файл содержит 1 2 3 [любое количество пробелов], будет достигнут eof и будет возвращено scanf(), а последнее printf() будет выполнено. Вот, напр. a.out < file.txt. - person ad absurdum; 22.01.2020