2010-10-25 17 views
2


, когда я написал это, компиляция и запуск:scanf не работает почему?

int x; 
scanf ("%d", &x); 
while (x!=4) { 
    scanf ("%d", &x); 
} 

и при вставке полукокса или двойного числа меньше, чем 4 он войти в бесконечный цикл.
при вставке двойного числа больше 4 он заканчивается.
Любые объяснения?

ответ

9

от C language standard (n1256):

7.19.6.2 Функция fscanf
...
4 Функция fscanf выполняет по очереди каждую директиву формата. Если директива не работает, как описано ниже, функция возвращает. Ошибки описываются как сбои ввода (из-за возникновения ошибки кодирования или недоступности входных символов) или соответствия сбоям (из-за несоответствующего ввода).
...
7 Директива, являющаяся спецификацией преобразования, определяет набор совпадающих входных последовательностей, как описано ниже для каждого спецификатора. Спецификация преобразования выполняются в следующих шагах:

8 входных белых символы пробела (как определенно с помощью функции isspace) пропускаются, если спецификация не включает в себя [, гр или п спецификатора , 250)

9 Элемент ввода читается из потока, если спецификация не включает в себя п спецификатор. Элемент ввода определяется как самая длинная последовательность входных символов, которая не превышает заданную ширину поля и которая является или является префиксом соответствующей последовательности ввода. 251) Первый символ, если он есть, после ввода элемента остается непрочитанным. Если длина входного элемента равна нулю, выполнение директивы выходит из строя; это условие является совпадающим сбоем, если только конец файла, ошибка кодирования или ошибка чтения не позволяют вводить данные из потока, и в этом случае это ошибка ввода.

в 10 За исключением случая % спецификатора, входной позиции (или, в случае % п директивы в, количество вводимых символов) преобразуется к типу, соответствующего спецификатора преобразования , Если входной элемент не соответствует последовательности, выполнение директивы не выполняется: это условие является несоответствующим. Если исключение присваивания не было указано *, результат преобразования помещается в объект, на который указывает первый аргумент, следующий за аргументом формата, который еще не получил результат преобразования. Если этот объект не имеет соответствующего типа или если результат преобразования не может быть представлен в объекте, поведение не определено.

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

scanf() возвращает количество успешных заданий; Вы должны проверить этот результат, чтобы увидеть, если преобразование удалось, например, так:

int x = 0; 
while (x != 4) 
{ 
    int result = scanf("%d", &x); 
    if (result != 1) 
    { 
    printf("Last call to scanf() failed; exiting\n"); 
    break; 
    } 
} 

К сожалению, у вас еще есть плохой вход застрял во входном потоке. Существует ряд стратегий для решения этой проблемы. Вы можете удалить нарушитель персонаж с getchar и попробуйте еще раз:

while (x != 4) 
{ 
    int tmp; 
    if (scanf("%d", &tmp) == 0) 
    getchar(); 
    else 
    x = tmp; 
} 

Или вы могли бы попытаться прочитать до следующей строки, при условии, что все остальные входы b0rked:

while (x != 4) 
{ 
    int tmp; 
    if (scanf("%d", &tmp) == 0) 
    while (getchar() != '\n') 
     ; 
    else 
    x = tmp; 
} 

Или вы могли бы попробовать читать ввод как текста и преобразовать в целое число с помощью strtol() (мой предпочтительный метод):

char input[SOME_SIZE]; 
int x = 0; 
... 
while (x != 4) 
{ 
    if (fgets(input, sizeof input, stdin)) 
    { 
    char *check; 
    int tmp = (int) strtol(input, &check, 10); 
    if (!isspace(*check) && *check != 0) 
    { 
     printf("%s is not a valid integer: try again\n", input); 
    } 
    else 
    { 
     x = tmp; 
    } 
    } 
    else 
    { 
    printf("Read error on standard input\n"); 
    break; 
    } 
} 

Это больше работы, но это позволяет вам ломать неудачный ввод до получает назначение на x.

+0

проголосуйте за ссылку и за решение getchar() – Aboelnour

+0

Просто небольшое замечание. Игнорирование части ввода на самом деле является очень плохой практикой. Вы должны сообщить об ошибке при первом признаке проблемы, а не продолжить чтение. –

-2

% d, которое вы передали scanf, сообщает ему разбор int. Когда вы вводите double, он не может проанализировать ни хранение анализируемых данных в переменной x, потому что double использует 64 бита на 32-битных машинах и int всего 32 бита, поднимая Seg. Неисправность или случайные побочные эффекты.

+2

-1 scanf считывает ** текст **. если вы вводите десятичную точку (или экспонента или любую вещь * ошибки), scanf останавливается из-за несоответствующего символа. – pmg

6

Вы не проверяете, действительно ли наступил scanf, поэтому вы попадете на ошибку. В каждом цикле scanf будет пытаться читать и терпеть неудачу.

scanf возвращает количество успешно считанных элементов таким образом изменить цикл, чтобы что-то вроде этого while (x!=4) { if (scanf("%d",&x) != 1) break; }

+0

+1 для правильного использования 'scanf' – pmg

+0

проголосуйте за правильное использование scanf() – Aboelnour

5

Когда зсапЕ прекращает сканирование в определенном положении во входном потоке, он никогда не будет продвигать поток, так что следующий зсапЕ будет попробуйте еще раз ту же ошибку ... и снова ... и снова

 
input: 42 23 foo ... 
scanf:^
x  42 
scanf: ^
x  23 
scanf: ^
x  unusable 
scanf:  ^
x  unusable 
scanf:  ^
x  unusable 
scanf:  ^
x  unusable 
scanf:  ^
x  unusable 
+0

, и как насчет того, если я ввел двойное число меньше 4, он вводит бесконечный цикл.и при вставке double больше 4 завершается. – Aboelnour

+0

Я не могу объяснить это поведение. Цикл прекращается, когда x не равно 4. Но использование x после неудачного сканированияf является неопределенным поведением: все может случиться. – pmg

+2

@Aboelnour Если вы введете '4.29419541951', он будет читать' 4' как целое число и выйти. Если вы введете '3.29419541951', он будет читать' 3', а затем пропустить следующий цикл, потому что первым символом является '.'. Вам нужно проверить возвращаемое значение. Проверьте код в моем ответе. –

Смежные вопросы