Я создаю программу, запрашивающую пользователя ввести значение char, но если они вводят более одного символа, он переместится на следующую функцию и сломает программу. Я добавил второй метод, который запускается при вводе нескольких входов.Как ограничить ввод моего пользователя
ответ
Ваша проблема не в том, чтобы ограничить количество символов, записанных на cInput
; спецификатор формата %1s
делает это уже. Ваша проблема заключается в том, чтобы оставить необработанные символы во входном буфере. Вам необходимо удалить все символы из буфера, если последующий ввод не будет обрабатывать их. Например, если вы оставите буквенный символ в буфере, но позже прочитаете с помощью %d
, функция немедленно вернется (потому что неявно используется также строка новой строки), но символ останется буферизированным, поскольку он не является десятичным. Это будет продолжаться бесконечно, если вы никогда не очистите буфер.
Для одного символа, то вы можете проверить, не является символом новой строки, а затем повторно получить символы до новой строки не найден, следующим образом:
scanf("%c", &cInput) ;
while(cInout != '\n' && getchar() != '\n') { } // flush buffered line
Если вы хотите, чтобы убедиться, что пользователь вводит только один символ, то вы могли бы изменить выше, таким образом:
scanf("%c", &cInput) ; // Get a single character
if(cInput != '\n' && // If the input is not "empty",
getchar() != '\n') // but the first character entered was not
// immediately followed by a newline...
{
// Flush to the end of the entered line
while(getchar() != '\n') { }
// Invalidate the input to force retry
cInput = 0 ;
}
по крайней мере один символ будет буферном - в новой строки по крайней мере. Действительный ответ будет иметь два символа один в cInput
и newline. Приведенное выше условие if(...)
считывает второй символ, если он есть (с использованием оценки короткого замыкания cInput
) и проверяет, что это конец ввода (новая строка). Если это не так, он читает все буферизованные символы, то аннулирует cInput
(в случае, если говорить "No-way\n"
были введены, например, так, что cinput
содержал 'N'
Для ввода чисел, вы просто читать символы до новой строки не найден:.
scanf("%d", &nValue);
while(getchar() != '\n') { } // flush buffered line
Если конечные нечисловые символы должны оказывать весь входной недействителен, вы должны проверить, что следующий символ новой строки.
int converted = scanf("%d", &nValue);
if(converted == 0 || getchar() != '\n')
{
valid_input = false ;
while(getchar() != '\n') { } // flush buffered line
}
Обратите внимание, что существуют другие возможные решения. Это мое предпочтительное решение.
При нанесении на ваши функции (с другими упрощениями):
int intAskUser(void)
{
char cInput = 0 ;
while(cInput != 'N' && cInput != 'Y')
{
printf("Do you want to enter a value? Y or N\n");
scanf("%c", &cInput) ;
if(cInput != '\n' && getchar() != '\n')
{
while(getchar() != '\n') { } // flush buffered line
cInput = 0 ;
}
else
{
cInput = toupper(cInput) ;
}
}
// Return answer code 0 to 1
return (cInput == 'N') ? 0 : 1 ;
}
int getValue(int nLower, int nUpper)
{
assert(nLower < nUpper) ; // precondition check
int nValue = 0 ;
bool valid_input = false ;
while(!valid_input)
{
printf("Enter a value between %d and %d: ", nLower, nUpper) ;
int converted = scanf("%d", &nValue);
if(converted == 0 || getchar() != '\n')
{
valid_input = false ;
while(getchar() != '\n') { } // flush buffered line
}
valid_input = nValue >= nLower &&
nValue <= nUpper ;
if(!valid_input)
{
printf("Please try again. ");
}
}
printf("Value: %d", nValue);
return nValue;
}
Обратите внимание, что toupper()
требует ctype.h
быть включен, и тип bool
требует stdbool.h
.
Если я правильно понимаю ваш вопрос, вы хотите, чтобы функция возвращала, если пользовательский ввод любого из
y
с последующим переводом строкиY
с последующим переводом строкиn
с последующим переводом строкиN
с последующим переводом на новую строку
Во всех остальных случаях вы хотите остаться в функции и получить новый пользовательский ввод (например, nYnhhh
, за которым следует новая линия: не возвращение).
Насколько я знаю, нет стандартной функции, которая может достичь этого, поэтому вам нужно написать свой собственный код.
При выполнении, что есть две вещи, чтобы помнить:
- Вы должны прочитать по крайней мере, 2 символов для того, чтобы проверить «слишком долго» входных строк.
- После неудачных входов вам необходимо очистить входной буфер перед чтением нового ввода. Неудачный ввод - это тот, который не имеет
\n
как последний символ.
В заключение я рекомендую использовать fgets()
вместо scanf()
, поскольку он намного проще в использовании. Не используйте gets()
, хотя - он опасно уязвим для переполнения буфера.
Ваш код может выглядеть следующим образом:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int AskUser(void)
{
char input[3] = {'\0'}; // Make room for a string of 2 chars + terminating null
int c;
int len;
printf("Do you want to enter a value? Y or N\n");
do
{
if (!fgets(input, 3, stdin))
{
printf("Input error");
exit(1);
}
len = strlen(input);
if (len)
{
if (input[len-1] != '\n') // Check whether last char is a newline
{
// It isn't so empty the input buffer
while ((c = getchar()) != '\n' && c != EOF) { }
}
}
if (len == 2) // Check for exactly 2 chars in input
{
if(toupper(input[0]) == 'Y' && input[1] == '\n')
{
return 1;
}
if(toupper(input[0]) == 'N' && input[1] == '\n')
{
return 0;
}
}
printf("Please enter a valid input, Y or N: \n");
} while(1);
}
int main(void) {
printf("Answer is %d\n", AskUser());
return 0;
}
Сделать буфер символов больше; вам не нужно использовать все это. Память дешевая. Массив, скажем, 100 символов, ничто. – Carcigenicate
Я пробовал это, но затем возвращает бесконечный цикл проверки проверки из другой функции. – Luke
зачем использовать строку, когда вы хотите получить символ? – 4386427