Read single key input from keyboard and evaluate it - c

I want to read one keyboard input - and depending whether it is valid or not proceed with the operation or do something else. If it's invalid the input should be repeated.
At this point I'm aware already scanf is not the tool of my desire, but that here would be the default-code (if scanf would work as intended):
char val;
int incorrect = 0;
printf("Do you wish to proceed?: <Yy/Nn>");
do
{
incorrect = 0;
scanf(" %c", &val); //Changed to " %c" alread from "%c"
//getchar(); //Tried already, doesn't solve the problem
if (!(val == 'y' || val == 'Y' || val == 'n' || val == 'N'))
{
printf("Invalide Input!\n");
incorrect = 1;
}
} while (incorrect);
The problem is if instead of a one-character input there is a longer input the error-message will be repeated by the number of the characters.
Also, if instead of for instance 'n' the input is "nasdlfjas" it is still considered as a valid input.
Changing the scanf to val = getchar(); if (kind != EOF) (with or without the EOF-part) as suggested here doesn't change the behavior. But the Error-message is added right after the question.
The "GetStuff()" from this solution suffers from the same problem. The error-output is multiple and one single correct character in the whole input determines the result.
This variant however is doing better, but evaluates the result on the first character of the entire string.
Other variants which include a while((c = getchar()) != EOF); which is the preferred variant to use getchar have similar issues of going through the loop-body before the input of the character (and therefore printing the error).
I decided to read a string instead of a character and then just evaluate the result by dealing with the string itself. Something like:
do{
int c, line_length = 0;
int i = 0;
while ((c = getchar()) != EOF && c != '\n' && line_length < MAX_LINE - 1)
{
sentence[i++] = c;
line_length++;
}
// String Stuff
if (!(val == 'y' || val == 'Y' || val == 'n' || val == 'N'))
{
printf("Invalide Input!\n");
incorrect = 1;
}
} while (incorrect);
But again there will "Invalide Input!" be printed before entering anything.
What exactly would be the proper way to evaluate just the input of a single character?

Related

How to only allow specific Input in C

My Code:
#include<stdio.h>
char checkInput0(void);
int main() {
char output;
output = checkInput0();
printf("The output is %c", output);
}
char checkInput0(void){
char option0 = '\0',check0;
char c;
do{
printf("Please enter your choice: ");
if(scanf("%c %c",option0, &c) != 'A' || c != 'B' ){
while((check0 = getchar()) != 0 && check0 != '\n' && check0 != EOF);
printf("[ERR] Please enter A or B.\n");
}else{
break;
}
}while(1);
return option0;
}
I would like to only allow the user to input only "A" or "B" and if anything else would be entered I would like to reprompt the user with the following message: [ERR] Please enter A or B.\n
I have written a funktion which worked with numbers but I can't get the one above (checkInput0) to work, what have I done wrong
scanf does not return c, it returns the number of variables successfully set. Comparing that to 'A' is pretty pointless.
Change your scanf call to scanf("%c %c", &option0, &c): currently the behaviour is undefined: the variable arguments need to be pointer types.
x != 'A' || x != 'B' is 1 for any value of x.
Consider moving scanf outside the if conditional: checking the return value of scanf explicitly. On the third point, did you want &&?
Also be careful with ace code that writes c on one side of an operator, and reads it on the other. It's fine in this instance since || is a sequencing point, but you are quite close to undefined behaviour here.

C user input only integers, return value from scanf

I am trying to get some user input, and I want to make sure that they enter integers, and if they don't I will just ask them to type again (loop until they get it right).
I have found a lot of different approaches to do this; some more complicated then others. But I found this approach which seems to work.
But I just don't really get why this is tested in the code:
scanf("%d%c", &num, &term) != 2
I can understand that scanf outputs the number of items successfully matched and assigned, but I don't get why it outputs 2 if it is an integer.
The code in C is:
int main(void)
{
int num;
char term;
if (scanf("%d%c", &num, &term) != 2 || term != '\n')
printf("failure\n");
else
printf("valid integer followed by enter key\n");
}
Trying to put it in loop:
int main(void){
int m, n, dis;
char m_check, n_check, dis_check;
do{
m = 0; n = 0; dis = 0;
m_check = ' '; n_check = ' '; dis_check = ' ';
printf("Please enter number of rows m in the matrix (integer): ");
if(scanf("%d%c", &m, &m_check) !=2 || m_check != '\n')
m_check = 'F';
printf("Please enter number of columns n in the matrix (integer): ");
if(scanf("%d%c", &n, &n_check) !=2 || n_check != '\n')
n_check = 'F';
printf("Should the random numbers come from a uniform or normal distribution?...
Please press 1 for uniform or 2 for normal: ");
if(scanf("%d%c", &dis, &dis_check) !=2 || dis_check != '\n' || dis != 1 || dis !=2)
dis_check = 'F';
}while(m_check == 'F' || n_check == 'F' || dis_check == 'F');
I've tried just inputting m = 3, n = 3, dis = 2, and then the loop just starts over and asks me to input number of rows. And if I when asked for this press f or something it just start looping like crazy over the printf-statements :)
scanf returns the number of fields it converted. You have the format string %d%c; it has:
%d - first field
%c - second field
so scanf returns 2.
If the user enters a number e.g. 123 and presses Enter, your num will be equal to 123, and term will be \n.
If the user enters a number with garbage at the end, e.g. 123garbage and presses Enter, your num will be equal to 123, the term will be g, and arbage\n will remain in the input buffer.
In both cases, scanf read an int and a char, so it returns 2.
A different example: the user enters garbage123. In this case, scanf will fail to read an integer, and return 0.
So your code checks for two different forms of incorrect output.
Entering an integer will match to the formatter %d and will assign the value to the variable num. The %c formatter will take the newline character ('\n') and store it in the variable term. scanf returns 2 cause 2 elements where correctly assigned (num and term)
If you don't enter an integer the formatter %d won't match correctly, and scanf won't return 2, producing a failure
Edit: Your do-while loop goes crazy cause your conditions in the last scanf are wrong (dis != 1 || dis !=2). It should be
if(scanf("%d%c", &dis, &dis_check) !=2 || dis_check != '\n' || (dis != 1 && dis !=2))
scanf("%d%c", &num, &term) != 2
This checks the return value of scanf . It will return number of arguments correctly matched . So , if a integer and a character is entered , they are store in vairables num and term and scanf returns 2 .
scanf will not return 2 if both the arguments are not correctly matched , in that case failure will be displayed as output.
Oops - now see OP wants to know why approached failed and was not necessarily looking for a how-to do it. Leaving this up as a reference as it does assert the fundamental problem: scanf(). Do not use it for user input.
If code truly needs to "get some user input, and wants to make sure that they enter integers", then use fgets() to get the line and then process the input.
Mixing user input with scanning/parse invariably results in some user input defeating the check, extra user input in stdin or improperly waiting for more input.
// true implies success
bool Read_int(int *value) {
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) == NULL) return false; // EOF or error
// Now parse the input
char *endptr;
errno = 0;
long number = strtol(buffer, &endptr, 10);
if (errno) return false; // long overflow
if (number < INT_MIN || number > INT_MAX) return false; // int overflow
if (endptr == buffer) return false; // No conversion
while (isspace((unsigned char) *endptr)) endptr++;
if (*endptr) return false; // non-white-space after number
*value = (int) number;
return true;
}

Ignore whitespace getchar()

I am having trouble ignoring the whitespace/tab. When a user enters a character from a command prompt, it should only accept any characters except whitespace or tab spaces.
eg:
$ ./a.out Character: =
Then, it's =
if
$ ./a.out Character: =
With bunch of spaces, then it should detect as =
I have already declared variable a.
char a;
printf("Character: ");
a = getchar();
Code:
while((a = getchar()) != EOF){
if( a != ' ' || a != '\t'){
a = getchar();
break;
}
}
Any help would be great. Thanks.
Update: As chux observed, getchar() returns type int, and you cannot successfully read the full range of possible characters if you assign that result to a variable of type char. In fact (I add), you risk invoking implementation defined behavior by doing so. In short, variable a should have type int.
With that said, it looks like you want something along these lines:
do {
a = getchar();
} while (a == (unsigned char) ' ' || a == (unsigned char) '\t');
Note that EOF, differs from both ' ' and '\t', so you can safely defer testing for it until after the loop.
Note also that if you want to ignore newlines and other whitespace characters too, then you might get good use out of the standard isspace() library function.
How about:
#include <ctype.h>
int a;
do
{
a = getchar();
} while (isspace(a));
as EOF is not a whitespace character, you don't need to handle it specially.
You can put that in a little function of its own if you like:
int
getcharnospace()
{
int a;
do
{
a = getchar();
} while (isspace(a));
return a;
}
int a;
while(a=getchar()){
if(a==' ' || a=='\t')
continue;
else
putchar(a);
}
By using break, you stop the while loop. Use continue instead:
while((a = getchar()) != EOF){
if( a != ' ' || a != '\t') continue;
[...]
}
You can modify the while() loop body as
while((a = getchar()) != EOF){
if( a == ' ' || a == '\t')
continue; // if space ot tab is detetected, scan for next input
else
{
putchar(a); //neither a space nor a tab, print it.
break;
}
}
Also, as the return type of getchar() is int, you should use int a.
Space ' ' is not the only whitespace char in C.
Tab '\t' is one of C's whitespace char.
Use int ch rather than char ch to distinctly save all the different results from getchar().
isspace(EOF) is always false.
Use issapce(), it is the C standard function for detecting white-space.
// char a;
int a;
printf("Character: ");
// All that is needed to consume white-space characters
while(isspace(a = getchar()));

Working of scanf and checking if input is int

I wanted to check whether input given is integer input or not. I did not wanted to store input in a string. After seeing several questions on stackoverflow and by hit and trial, I have created following code
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
if(a == '\n')
scanf("%c",&a);
else
{
while(a != '\n')
scanf("%c",&a);
}
}
It works but according to my understanding, the following should have also worked
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
while(a != '\n')
scanf("%c",&a);
}
Can someone please tell me why above did not worked ?? Also if someone has better solution please give it also.
Note :I am considering 12qwe also as an invalid input. I just want integers.
The problem with
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
while(a != '\n')
scanf("%c",&a);
}
is that if a happens to contain '\n' before the scan, and the scan fails, the inner while loop doesn't run at all. So
if the scan failed trying to parse an int from the input stream because the input was e.g. "ab c\n", the offending input remains in the input stream, the next scanf in the outer while loop control fails parsing an int again, a remains '\n', repeat.
if an input error occurred before reading a character from the stream into a, the scanf in the outer loop control fails because of a corrupted stream, repeat.
In the other version,
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
if(a == '\n')
scanf("%c",&a);
else
{
while(a != '\n')
scanf("%c",&a);
}
}
you make at least some progress as long as there is input to be read from the stream, since whatever a contains, you read at least one character from the input stream before attempting the next parsing of an int. It will also result in an infinite loop if the input stream is corrupted/closed/ends prematurely, e.g. if you redirect stdin from an empty file. You can have that loop also output multiple "Please enter an integer only : " messages by giving input like `"a\nb\nc\nd\n".
So you should check whether scanf encountered the end of the stream or some other read error before converting anything from the input, and abort in that case:
int reads;
while(((reads = scanf("%d%c", &num, &a)) != 2 && reads != EOF) || a != '\n')
{
printf("Please enter an integer only : ");
// read at least one character until the next newline
do {
reads = scanf("%c", &a);
}while(reads != EOF && a != '\n');
}
This is a wrong way to do. You can rather read the input using fgets() and then parse your string for integer ASCII range.
fgets(s, 1024, stdin)
for (i=0; s[i] ! = '\0';i++) {
if( s[i] <'0' && s[i] >'9')
// not an integer<br>
You can also use standard functions like isalnum, isalpha etc.
it works……
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
do{
scanf("%c",&a);
}while(a != '\n');
}

Putting numbers separated by a space into an array

I want to have a user enter numbers separated by a space and then store each value as an element of an array. Currently I have:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i++] = c - '0';
}
but, of course, this stores one digit per element.
If the user was to type:
10 567 92 3
I was wanting the value 10 to be stored in arr[0], and then 567 in arr[1] etc.
Should I be using scanf instead somehow?
There are several approaches, depending on how robust you want the code to be.
The most straightforward is to use scanf with the %d conversion specifier:
while (scanf("%d", &a[i++]) == 1)
/* empty loop */ ;
The %d conversion specifier tells scanf to skip over any leading whitespace and read up to the next non-digit character. The return value is the number of successful conversions and assignments. Since we're reading a single integer value, the return value should be 1 on success.
As written, this has a number of pitfalls. First, suppose your user enters more numbers than your array is sized to hold; if you're lucky you'll get an access violation immediately. If you're not, you'll wind up clobbering something important that will cause problems later (buffer overflows are a common malware exploit).
So you at least want to add code to make sure you don't go past the end of your array:
while (i < ARRAY_SIZE && scanf("%d", &a[i++]) == 1)
/* empty loop */;
Good so far. But now suppose your user fatfingers a non-numeric character in their input, like 12 3r5 67. As written, the loop will assign 12 to a[0], 3 to a[1], then it will see the r in the input stream, return 0 and exit without saving anything to a[2]. Here's where a subtle bug creeps in -- even though nothing gets assigned to a[2], the expression i++ still gets evaluated, so you'll think you assigned something to a[2] even though it contains a garbage value. So you might want to hold off on incrementing i until you know you had a successful read:
while (i < ARRAY_SIZE && scanf("%d", &a[i]) == 1)
i++;
Ideally, you'd like to reject 3r5 altogether. We can read the character immediately following the number and make sure it's whitespace; if it's not, we reject the input:
#include <ctype.h>
...
int tmp;
char follow;
int count;
...
while (i < ARRAY_SIZE && (count = scanf("%d%c", &tmp, &follow)) > 0)
{
if (count == 2 && isspace(follow) || count == 1)
{
a[i++] = tmp;
}
else
{
printf ("Bad character detected: %c\n", follow);
break;
}
}
If we get two successful conversions, we make sure follow is a whitespace character - if it isn't, we print an error and exit the loop. If we get 1 successful conversion, that means there were no characters following the input number (meaning we hit EOF after the numeric input).
Alternately, we can read each input value as text and use strtol to do the conversion, which also allows you to catch the same kind of problem (my preferred method):
#include <ctype.h>
#include <stdlib.h>
...
char buf[INT_DIGITS + 3]; // account for sign character, newline, and 0 terminator
...
while(i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL)
{
char *follow; // note that follow is a pointer to char in this case
int val = (int) strtol(buf, &follow, 10);
if (isspace(*follow) || *follow == 0)
{
a[i++] = val;
}
else
{
printf("%s is not a valid integer string; exiting...\n", buf);
break;
}
}
BUT WAIT THERE'S MORE!
Suppose your user is one of those twisted QA types who likes to throw obnoxious input at your code "just to see what happens" and enters a number like 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 which is obviously too large to fit into any of the standard integer types. Believe it or not, scanf("%d", &val) will not yak on this, and will wind up storing something to val, but again it's an input you'd probably like to reject outright.
If you only allow one value per line, this becomes relatively easy to guard against; fgets will store a newline character in the target buffer if there's room, so if we don't see a newline character in the input buffer then the user typed something that's longer than we're prepared to handle:
#include <string.h>
...
while (i < ARRAY_SIZE && fgets(buf, sizeof buf, stdin) != NULL)
{
char *newline = strchr(buf, '\n');
if (!newline)
{
printf("Input value too long\n");
/**
* Read until we see a newline or EOF to clear out the input stream
*/
while (!newline && fgets(buf, sizeof buf, stdin) != NULL)
newline = strchr(buf, '\n');
break;
}
...
}
If you want to allow multiple values per line such as '10 20 30', then this gets a bit harder. We could go back to reading individual characters from the input, and doing a sanity check on each (warning, untested):
...
while (i < ARRAY_SIZE)
{
size_t j = 0;
int c;
while (j < sizeof buf - 1 && (c = getchar()) != EOF) && isdigit(c))
buf[j++] = c;
buf[j] = 0;
if (isdigit(c))
{
printf("Input too long to handle\n");
while ((c = getchar()) != EOF && c != '\n') // clear out input stream
/* empty loop */ ;
break;
}
else if (!isspace(c))
{
if (isgraph(c)
printf("Non-digit character %c seen in numeric input\n", c);
else
printf("Non-digit character %o seen in numeric input\n", c);
while ((c = getchar()) != EOF && c != '\n') // clear out input stream
/* empty loop */ ;
break;
}
else
a[i++] = (int) strtol(buffer, NULL, 10); // no need for follow pointer,
// since we've already checked
// for non-digit characters.
}
Welcome to the wonderfully whacked-up world of interactive input in C.
Small change to your code: only increment i when you read the space:
while ((c = getchar()) != '\n')
{
if (c != ' ')
arr[i] = arr[i] * 10 + c - '0';
else
i++;
}
Of course, it's better to use scanf:
while (scanf("%d", &a[i++]) == 1);
providing that you have enough space in the array. Also, be careful that the while above ends with ;, everything is done inside the loop condition.
As a matter of fact, every return value should be checked.
scanf returns the number of items successfully scanned.
Give this code a try:
#include <stdio.h>
int main()
{
int arr[500];
int i = 0;
int sc = 0; //scanned items
int n = 3; // no of integers to be scanned from the single line in stdin
while( sc<n )
{
sc += scanf("%d",&arr[i++]);
}
}

Resources