printf ("Введите 'a':");работает 2 раза после 1-го цикла - PullRequest
2 голосов
/ 24 сентября 2019
int main (int argc, char *argv [])
{
     char a = 'v';

     for (int i = 0; a != 'x'; ) 
     {        
         printf("Enter 'a' : "); 
         scanf("%c",&a);
     }

     return 0;
}

Я запустил его и дал ввод k .Когда я нажимаю Enter после этого, почему мой printf работает 2 раза , когда цикл запускается второй раз?

Ответы [ 3 ]

3 голосов
/ 24 сентября 2019

Чтобы понять это поведение, мы можем смоделировать пошаговое выполнение.

printf("Enter 'a' : "); 
scanf("%c",&a); // User type in example 'a' and presses enter.

scanf «буфер» a\n и помещает в a значение 'a'

Условие цикла не выполняется, поскольку 'a' == 'x' равно false

printf("Enter 'a' : ");
scanf("%c",&a); // The buffer still contains `'\n'`

Поскольку в буфере все еще содержатся неиспользованные данные, следующий символ ('\n') помещается в a и цикл продолжается.

Условие цикла не выполняется, поскольку '\n' == 'x' равно false

printf("Enter 'a' : ");
scanf("%c",&a); // The buffer is empty now.

Это дает вам иллюзию, что цикл отображает дважды printf, но на самом деле scanf продолжал читать буфер без необходимости ввода пользователем.

Если вы введете больше символов, например, qwerty, "Enter 'a' : " будет отображаться 7 раз, потому что "qwerty" содержит 6 символов + '\n'


Обратите внимание, что использование while (a != 'x') будет лучше соответствовать вашим потребностям, чем for (int i = 0; a != 'x'; )

2 голосов
/ 24 сентября 2019

Для начала этот цикл

for (int i = 0; a != 'x'; ) 

не имеет смысла хотя бы потому, что переменная i не используется в цикле.

Также это приглашение

printf("Enter 'a' : ");

только сбивает с толку пользователей.Вы просите пользователя ввести символ 'a', когда цикл останавливается при вводе символа 'x'.

Этот вызов scanf

scanf("%c",&a);

читает все символы, включая белые.космические символы.Это причина, почему цикл повторяет еще один.Вы должны написать

scanf( " %c", &c );
        ^^^

В этом случае пробелы будут пропущены.

Из стандарта C (7.21.6.2 функция fscanf)

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

Программа может выглядеть следующим образом

#include <stdio.h>

int main(void) 
{
    char c;

    do
    {
        printf( "Enter a character ('x' - exit): " );
    } while ( scanf( " %c", &c ) == 1 && c != 'x' );

    return 0;
}
2 голосов
/ 24 сентября 2019

Когда вы используете scanf и %c, он читает любой символ - включая символ новой строки, который вы получаете при нажатии клавиши ВВОД.

Так что, если вы запуститезапрограммируйте и наберите

a <Return>

. Вы совершаете две поездки по циклу: одну для чтения 'a' и одну для чтения '\n'.Если вы наберете

<Space> <Space> a <Return>

, он выполнит четыре цикла.И если вы наберете

x <Return>

, он совершит только один обход цикла, потому что он заметит, что вы набрали 'x', и выйдет.

Все станет немного яснее, если выраспечатайте каждый полученный вами символ:

for (int i = 0; a != 'x'; )
{
    printf("Enter 'a' : ");
    scanf("%c",&a);
    printf("you typed %d =  %c\n", a, a);
}

Когда вы увидите его, выведите

 you typed 10 =

- это одна из новых строк.(Значение '\n' равно 10 в ASCII.)

Я сказал, что %c читает любой символ - но это несколько необычно.Большинство других спецификаторов формата scanf - %d, %f, %s и т. Д. - пропускают "пробелы", то есть пробелы, табуляции, новые строки и некоторые другие.Но %c не пропускает их, потому что его задача - прочитать ровно один символ, и кто-то подумал, что вы, возможно, захотите использовать его и для чтения пробельных символов.

...