2013-06-13 5 views
5

Следующий код дает причудливый o/p, как только я его скомпилирую.Почему нам нужно поставить пробел до% c?

main() { 
    char name[3]; 
    float price[3]; 
    int pages[3], i; 

    printf ("\nEnter names, prices and no. of pages of 3 books\n") ; 

    for (i = 0 ; i <= 2 ; i++) 
     scanf ("%c %f %d", &name[i], &price[i], &pages[i]); 

    printf ("\nAnd this is what you entered\n") ; 

    for (i = 0 ; i <= 2 ; i++) 
     printf ("%c %f %d\n", name[i], price[i], pages[i]); 
} 

Но если мы дадим пространство в инструкции scanf до% c, оно дает правильный o/p.

Может кто-нибудь объяснить мне, почему это так?

Обновление: -

Если я обеспечиваю вход как this-

F 
123.45 
56 
J 
134 
67 
K 
145 
98 

тогда мой вопрос, почему не мы даем пространство перед% F и пространства до% d? Почему нам нужно предоставить пространство до% c?

+1

Какой тип ''% c'' вы имеете в виду? –

+0

И каков правильный выход? Каков результат, который предоставляет программа? –

+0

@JeffMercado, обновил мой вопрос. Я говорю об утверждении scanf. –

ответ

11

Добавление пробела в строку формата позволяет scanf потреблять символ новой строки из ввода, который происходит каждый раз, когда вы нажимаете return. Без пробега name[i] получит знак '\n', а real char оставлен неверным толкованием %f.

Так, скажем, ваш вход

a 1.0 2 
b 3.0 4 
c 5.0 6 

Программа видит больше, как это:

a 1.0 2\nb 3.0 4\nc 5.0 6\n\377 

То есть, линия-брейки фактические символы в файле (и \ 377 здесь указывает «конец файла»).

Первый scanf будет работать нормально, потребляя символ, поплавок и целое число. Но он оставляет вход так:

\nb 3.0 4\nc 5.0 6\n\377 

Так второй scanf будет читать '\n' как его% с, если не избавиться от него в первую очередь.

Добавление пространства в строке формата инструктирует зсапЕ отбросить любые символы пробела (любой из пространства ' ', вкладки '\t' или новой строки '\n').

директива является одно из следующих действий:

  • Последовательность пробельных символов (пробел, табуляция, перевод строки и т.д .; см isspace (3)). Эта директива соответствует любому количеству пробелов, в том числе ни одного, на входе.

  • ...

из http://linux.die.net/man/3/scanf


Такого рода проблемы возникают всякий раз, когда вы используете scanf с %c в цикле.Потому что, принимая в свободной форме ввода, новые строки могут случиться в любом месте. Таким образом, принято стараться избегать всей проблемы, используя двухуровневый подход. Вы читаете строки ввода в буфер (с использованием fgets); отрубать глупых символов новой строки; затем используйте sscanf вместо scanf, чтобы читать из буфера (строки), а не прямо из файла.

+0

Спасибо за предложение. Я все еще не могу понять эту концепцию. Простите мое невежество, я новичок в C. –

+0

Добавил еще несколько объяснений. –

+2

Просто добавьте luser droog. Новый символ строки будет сохранен в буфере, а scanf сначала увидит буфер, и если буфер не пуст, он принимает входные данные из буфера. В противном случае он принимает от stdin. Поэтому, чтобы сбросить буфер, мы помещаем пространство infront% c в scanf. –

3

Неправильное подключение с помощью% с

Рассмотрим следующий фрагмент кода:

int main(){ 
int x; 
char y; 
scanf("%d", &x); 
scanf("%c", &y); 
printf("%d %c", x, y); 
} 

Поведение:
При выполнении указанной выше программы, то первый зсапЕ называется , который будет ждать ввода десятичного числа. Скажем, вы вводите 12 (Это ASCII '1' и ASCII '2'). Затем вы нажимаете клавишу «enter» на , сигнализируя о конце ввода. Затем программа выполнит второй scanf, за исключением того, что вы не заметите, что программа не ждет вас до , введите символ и вместо этого перейдите прямо к выходу 12, затем следуйте с помощью '\ n'.



Объяснение:
Почему это происходит? Давайте посмотрим на поведение программы шаг за шагом. Изначально в буфере ничего нет. Когда вызывается первый scanf(), он не имеет ничего , чтобы читать, и поэтому он ждет. Он продолжает ждать, пока вы не наберете 1,2, затем введите «enter». Теперь, что находится в , буфером являются символ 1, символ 2 и символ '\ n'. Помните, что «\ n» обозначает конец ввода, как только все поля были введены, но также сохраняется в буфере в виде символа ASCII. На этом этапе scanf будет считывать самый большой десятичный ввод из буфера и преобразовывать его в целое число. В этом примере он находит строку «12», а преобразует ее в десятичное значение двенадцать и помещает ее в x. Затем scanf возвращает управление обратно на на главную функцию и возвращает значение 1, чтобы иметь возможность успешно конвертировать одну запись . В нашем примере мы не поймаем возвращаемое значение scanf в переменной. Для надежного кода важно проверить возвращаемое значение scanf(), чтобы убедиться, что пользователь вводит правильные данные.



Что сейчас осталось в буфере «\ п». Затем второй scanf вызывает , и он ожидает персонажа. Поскольку в буфере уже есть символ '\ n', scanf видит это, берет его из буфера и помещает его в y. Поэтому при выполнении printf после этого на экран выводятся цифры 12 и "enter".



Решение:
Мораль рассказа, введите это символ, как и любой другой, и вводится в буфер, и потребляются из буфера на% с просто как любой другой символ ASCII. Чтобы исправить это, попробуйте использовать этот код вместо:


int main(){ 
int x; 
char y; 
scanf("%d", &x); 
scanf("\n%c", &y); /* note the \n !! */ 
printf("%d %c", x, y); 
} 


**

Как это исправить эту проблему?


** Таким образом, вы снова ввести «1»,»2’ ,» \ п». Первый scanf читает «1» и «2», преобразует их в десятичные двенадцать и оставляет «\ n» в буфере. Следующий scanf теперь ожидает '\ n' в начале следующего ввода. Он находит «\ n» в буфере, читает его и отбрасывает. Теперь буфер пуст, и scanf ждет пользователя для ввода символа. Произнесите пользовательские входы 'c', а затем введите ключ. 'C' теперь , присвоенный y, NOT "enter". Поэтому printf выводит «12 c» на экран . ПРИМЕЧАНИЕ. В очереди теперь есть «\ n». Поэтому, если вам нужно сделать еще один scanf для одного символа, вам нужно будет «потреблять», что «\ n» перед тем, как взять другого пользователя от пользователя.

Это не является проблемой для любого другого спецификатора формата, так как все они игнорируют пробелы до входе.

+0

Ввод символов пробела (как указано в функции isspace) пропускается, если только спецификация содержит спецификатор ** [, c или n ** – chux

+1

Большая часть вашего ответа отформатирована как цитаты. Если вы цитируете какой-то источник, я предлагаю его зачислить; если нет, просто напишите обычный текст. –

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