getchar not working properly after using scanf in C - c

I am writing this code:
int b;
char c;
scanf("%d", &b);
while((c = getchar()) != EOF) {
if(c >= 9 || c < 0) {
printf("Invalid number!\n");
exit(0);
}
}
When I assign b, automatically c is equal to b.
For example, if my input for b is 10, it automatically goes into the if-statement and exits the code.
Does anyone know why?

Finding problems and solving them
You have plenty of errors in the code that are listed below.
The getchar(3) says:
getchar() is equivalent to getc(stdin).
The prototype of getc() is:
int getc(FILE *stream);
That is, the getchar() returns an integer (from unsigned char cast). Thus, we need to change the type from char to int to accept its return value correctly.
Note that EOF is not a valid unsigned char. It expands to signed int -1.
Never ignore the return value of the scanf(3). It returns the number of correctly passed arguments. In this case, to make the code reliable, we should put:
if (scanf("%d", &b) != 1) {
fprintf(stderr, "Value must be an integer.\n");
return EXIT_FAILURE;
}
There is a semantic error in the condition:
if (c >= 9 || c < 0)
^^____________ logically, 9 is a valid one digit number
so removing '=' from here makes more sense
One notable thing is that the condition and the type of the comparator – both should be changed. See the next step.
The fixed loop should look like:
while ((c = getchar()) != EOF) {
if (c == '\n') // Since c = getchar() can be '\n' too
continue; // so, better ignore
if (c >= '0' && c <= '9') // Change the loop like this
printf("Valid number %d %c.\n", c, c);
else
printf("Invalid number.\n");
}
Sample test case output
1
10 // --- Note: 10 are two chars for two getchars
Valid number 49 1.
Valid number 48 0.
3
Valid number 51 3.
9
Valid number 57 9.
-
Invalid number.
a
Invalid number.
<
Invalid number.
.
Invalid number.

Related

Two conditions for DO WHILE loop in C

Could you please explain me why this condition works with || and does not with &&.
I fixed this on my own. I just do not understand why this is OR and not AND.
This program must quit the loop when user inputs Q0.
#include <stdio.h>
int main() {
char character;
int integer;
printf("Loop started\n\n");
do {
printf("Enter Q0 to quit the loop: ");
scanf(" %c%d", &character, &integer);
if (character != 'Q' || integer != 0) {
printf("Invalid value(s)!\n\n");
}
else {
printf("Correct value(s)!\n");
}
} while (character != 'Q' || integer != 0);
printf("\nLoop ended\n");
return 0;
}
Code link
The code is correct and the loop will be exited if and only if the user enters a Q followed by a integer with a value of 0. The test (character != 'Q' || integer != 0) is equivalent to !(character == 'Q' && integer == 0). In plain English, the latter is a more direct translation of continue unless the user typed a Q and the number 0.
Note however these remarks:
using a do / while loop makes you repeat the test inside the loop at as the exit condition. It would be simpler to user a for (;;) loop, aka for ever loop, and use a break statement to exit the loop explicitly when the user types the appropriate sequence, using a positive test.
you do not check the scanf() return value, which must be 2 for proper operation. If the user types a sequence that cannot be parsed with " %c%d", the behavior may be incorrect and possibly undefined. For example an input of 10QA will be misinterpreted as a correct value. It is much more reliable to read the input as a string with fgets(), parse it with sscanf and check the return values.
%d will convert sequences such as 00, +0 and -0 as the number 0 which may or may not be expected. If the input sequence must match Q0 exactly, the test must be performed some other way.
Here is a modified version:
#include <stdio.h>
int main() {
printf("Loop started\n\n");
for (;;) {
char buf[128];
char character, c2;
int integer;
printf("Enter Q0 to quit the loop: ");
if (!fgets(buf, sizeof buf, sizeof buf)) {
printf("Unexpected end of file!\n\n");
break;
}
if (sscanf(" %c%d %c", &character, &integer, &c2) != 2) {
printf("Invalid format: must have a character and an integer!\n\n");
continue;
}
if (character == 'Q' && integer == 0) {
printf("Correct values!\n");
break;
}
printf("Invalid values: %c%d!\n\n", character, integer);
printf("Try again.\n");
}
printf("\nLoop ended\n");
return 0;
}
if (character != 'Q' || integer != 0) {
printf("Invalid value(s)!\n\n");
}
else {
printf("Correct value(s)!\n");
}
These statements translate to:
"If character is not equal to Q OR if integer is not equal to 0, print invalid value.
Else, print correct value."
So, if character is Q or integer is 0, the expression will evaluate to true and correct value would be printed.
Could you please explain me why this condition works with || and does
not with &&.
Because if the first operand of the logical AND operator evaluates to false, the second operator is not evaluated. So if character is not equal to Q, then the second expression is never evaluated (even if integer is 0).
If the above code was written as:
if (character != 'Q' && integer != 0) {
printf("Invalid value(s)!\n\n");
} else {
printf("Correct value(s)!\n");
}
which translates to:
"If character is not equal to Q AND integer is not equal to 0, print incorrect value. Else, print correct value."
It'll only print correct value when the input was Q0 and both the expressions evaluated to true.

Understanding K&R's getint() (Chapter 5: Pointers & Arrays, Exercise 1)?

I'm a novice programmer who's self-studying C through K&R. I don't understand the design of their function getint(), which converts a string of digits into the integer it represents. I'll ask my question then post the code below.
If getch() returns a non-digit character that's not a '-' or '+', it pushes this non-digit character back onto the input with ungetch(), and returns 0. So, if getint() is called again, getch() will just return that same non-digit character that was pushed back, so ungetch() will push it back again, etc. The way I understand it (which could be wrong), the function breaks completely if it's passed any non-digit character.
The exercise doesn't have you fix this. It asks to fix the fact that a '-' or '+' followed by a non-digit is a valid representation of 0.
What exactly am I missing here? Did they design getint() to make an infinite loop if the input is anything other than 0-9? Why?
Here's their code for getint() [edit] with main calling getint():
int getint(int *);
int main()
{
int n, array[BUFSIZE];
for (n = 0; n < BUFSIZE && getint(&array[n]) != EOF; n++)
;
return 0;
}
int getch(void);
void ungetch(int);
int getint(int *pn)
{
int c, sign;
while (isspace(c = getch())
;
if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
ungetch(c); //this is what i don't understand
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '-' || c == '+')
c = getch();
for (*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
if (c != EOF)
ungetch(c);
return c;
}
int buf[BUFSIZE];
int bufp = 0;
int getch(void)
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
if (bufp >= BUFSIZE)
printf("ungetch: can't push character\n");
else
buf[bufp++] = c;
}
As it is currently written, getint() function is trying to read an integer from user input and puts it into *pn.
If user inputs a positive or negative number(with a sign or without it), *pn gets updated to that number and getint() returns some positive number (the next character after the number).
If user inputs a non valid number, *pn is not updated and getint() returns 0 (meaning it failed).
the function breaks completely if it's passed any non-digit character.
That's right. All subsequent calls to getint() will fail as the last character was passed to ungetch(). What you understand is correct.
But this is how getint() is supposed to handle garbage input. It'll simply reject it and return 0 (meaning it failed). It is not the responsibility of getint() to take care of non-integer input and prepare fresh input for next read. It is not a bug.
The only bug is that a '-' or '+' followed by a non-digit is currently being considered as a valid representation of 0. Which is left to reader as an exercise.
If user inputs EOF, *pn is not updated (multiplied by 1) and getint() returns EOF.
The reasoning is similar to scanf not consuming characters that don't match the conversion specifier - you don't want to consume something that isn't part of a valid integer, but may be part of a valid string or other type of input. getint has no way of knowing whether the input it rejects is part of an otherwise valid non-numeric input, so it has to leave the input stream the same way it found it.

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;
}

How to scan in values and ignore the characters

I am a newbie to C and I was looking over some questions where I pondered upon a question where we need to scan in values using the users input. Example
1 2 3 45 6 7. So Automatically we scan these values into a 2D array.
One thing that troubles me is what If the user inputs
1 2 3 2 3 Josh, how can we ignore Josh and only scan in the values into the array.
I looked at using getchar and use a flag variable but I am unable to figure out the conundrum of differentiating between the integer and character.
/* This is something that I tried */
#include <stdio.h>
int main(int argc, char *argv[]) {
int a;
int b;
int A[10];
while (((a = getchar()) != '\n') && (b = 0)) {
if (!(a >= "A" && a <= "Z")) {
scanf("%d", A[b]);
}
b++;
}
}
}
I think one good method for achieving what you want is using scanf with the format "%s", which will read everything as a string, effectively splitting the input according to white spaces. From the manual:
s
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character array that is long
enough to hold the input sequence and the terminating null
byte ('\0'), which is added automatically. The input string
stops at white space or at the maximum field width, whichever
occurs first.
To convert the string to integer, you can use atoi. From the manual:
The atoi() function converts the initial portion of the string
pointed to by nptr to int.
So, if it converts the initial portion of the string into an integer, we can use that to identify what is a number and what's not.
You can build a simple "word detector" for atoi.
Using the function isalpha from ctype.h you can do:
int isword(char *buffer)
{
return isalpha(*buffer);
}
And rewriting your reading program you have:
#include <stdio.h>
#include <ctype.h>
int isword(char *buffer)
{
return isalpha(*buffer);
}
int main(void)
{
char input[200];
int num;
while (1) {
scanf("%s", input);
if (!strcmp(input, "exit")) break;
if (isword(input)) continue;
num = atoi(input);
printf("Got number: %d\n", num);
}
return 0;
}
You should keep in mind that the name isword is fallacious. This function will not detect if buffer is, in fact, a word. It only tests the first character and if that is a character it returns true. The reason for this is the way our base function itoa works. It will return zero if the first character of the buffer is not a number - and that's not what you want. So, if you have other needs, you can use this function as a base.
That's also the reason I wrote a separate function and not:
if (!isalpha(input[0]))
num = itoa(input);
else
continue;
The output (with your input):
$ ./draft
1 2 3 2 3 Josh
Got number: 1
Got number: 2
Got number: 3
Got number: 2
Got number: 3
exit
$
About assigments and &&
while (((a = getchar()) != '\n') && (b = 0))
As I said in a comment, this loop will never work because you're making a logical conjunction(AND) with an assignment that will always return zero. That means the loop condition will always evaluate to false.
In C, assignments return the value assigned. So, if you do
int a = (b = 10);
a will have now hold the value 10. In the same way, when you do
something && (b = 0)
You're effectively doing
something && 0
Which will always evaluate to false (if you remember the AND truth table):
p q p && q
---------------
0 0 0
0 1 0
1 0 0
1 1 1
Your code is completely wrong. I suggest to delete it.
You could use scanf with %d to read in numbers. If it returns 0, there is some invalid input. So, scan and discard a %s and repeat this process:
int num = -1;
while(num != 0)
{
printf("Enter a number, enter 0 to exit:");
if(scanf("%d", &num) == 0) /* If scanf failed */
{
printf("Invalid input found!");
scanf("%*s"); /* Get rid of the invalid input (a word) */
}
}

Resources