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.
Related
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.
I'm having trouble finding out how to set up a loop where i enter input and then
stop the input by pressing 'e' or 'E'. The input entered is integers but needs to be stopped with a character. That is where i get lost. I have seen a bunch of information about using ascii conversions but i dont know how efficient that would be. This code is broken but it is as far as i could get. Any information would be helpful.
int main(void)
{
char num;
int sub;
while (sub != 'e' || sub != 'E') {
scanf("%d", &num);
sub = #
printf("%d", num);
}
return 0;
}
Simple.
#include <stdio.h>
#include <ctype.h>
int main(void) {
char c = getchar();
int num;
while (c != 'e' || c != 'E') {
if (isdigit(c))
num = c - '0';
c = getchar();
}
return 0;
}
But you don't have to use an ascii character as a way to stop input. You can use EOF which is -1. It is Ctrl-D on UNIX systems and Ctrl-Z on Windows.
int c;
while ((c = getchar()) != EOF)
A direct way to distinguish between an input of int, 'e' and , 'E' is to read a line of user input with fgets() and then parse it.
#define LINE_SZ 80
char buf[LINE_SZ];
while (fgets(buf, sizeof buf, stdin) && buf[0] != 'e' && buf[0] != 'E') {
if (sscanf(buf, "%d", &num) != 1) {
Handle_other_non_int_input();
}
sub = #
printf("%d", num);
}
As noted in the comments, (sub != 'e' || sub != 'E') is always true. If sub can never be e and E at the same time.
Note that sub is an int and not an integer pointer (int *).
The line sub = # assigns sub with num's address.
And the value of sub is used in the control expression of the while loop before it is initialised. sub has garbage value at that point which is indeterminate. You have to initalise it with some value before using it.
Do
int num, rv;
while( 1 )
{
rv=scanf("%d", &num);
if(rv==0)
{
if( (num=getchar())=='e' || num=='E' )
{
break;
}
else
{
while(getchar()!='\n');
continue;
}
}
printf("\n%d", num);
}
A value is read into num by scanf() whose return value is stored in rv.
scanf() returns the number of successful assignments which in this case should be 1 if an integer value was read into num since %d is the format specifier.
If rv is 1, it is a number and is printed. Otherwise it could be a character which won't read by the scanf() and would remain unconsumed in the input buffer. The first byte of this data is read by the getchar() and if this is e or E, the loop is exited but otherwise the input buffer is cleared till a \n is encountered and the next iteration of the loop is done without going into the part where the printing takes place.
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;
}
For example, if I want to write a code to average an unspecified number of numbers that the user enters, how can I make it so that the user can determine the number of numbers? ie. if the user wants to average just three numbers, he types them in one at a time, and then types in something to signal that this is it.
I wrote something like
while(i!=EOF){
printf("type in a number: \n");
scanf("%f",&i);
array[x]=i;
x++;
}
"and then some code to average the numbers in the array".
The idea was that if the user wants to signal that he finished entering numbers, he types in EOF and then the while loop will stop, however this isn't working. When I type in EOF at the terminal, it just writes "type in a number:" indefinitely.
scanf returns information in two different ways: in the variable i, and as its return value. The content of the variable i is the number that scanf reads, if it is able to return a number. The return value from scanf indicates whether it was able to read a number.
Your test i != EOF is fundamentally a type error: you're comparing the error indicator value EOF to a variable designed to hold a floating-point number. The compiler doesn't complain because that is accidentally valid C code: EOF is encoded as an integer value, and that value is converted to a floating-point value to perform the comparison. In fact, you'll notice that if you enter -1 at the prompt, the loop will terminate. -1 is the value of the EOF constant (on most implementations).
You should store the return value of scanf, and store it into a separate variable. If the return value is EOF, terminate the loop. If the return value is 1, you have successfully read a floating-point value.
If the return value is 0, the user typed something that couldn't be parsed. You need to handle this case appropriately: if you do nothing, the user's input is not discarded and your program will loop forever. Two choices that make sense are to discard one character, or the whole line (I'll do the latter).
double i;
double array[42];
int x = 0;
int r = 0;
while (r != EOF) {
printf("type in a number: \n");
r = scanf("%f", &i);
if (r == 1) {
/* Read a number successfully */
array[x] = i;
x++;
} else if (r == 0) {
printf("Invalid number, try again.\n");
scanf("%*[^\n]"); /* Discard all characters until the next newline */
}
}
You should also check that x doesn't overflow the bounds of the array. I am leaving this as an exercise.
I want to do it by typing in something that's not a number
Then get the input as a string, and exit if it cannot be converted to a number.
char buf[0x80];
do {
fgets(buf, sizeof(buf), stdin);
if (isdigit(buf[0])) {
array[x++] = strtod(buf);
}
} while(isdigit(buf[0]);
In case of no input scanf() does not set i to EOF but rather can return EOF. So you should analyze scanf() return code. By the way you can receive 0 as result which actually means there is no EOF but number cannot be read.
Here is example for you:
#include <stdio.h>
#define MAX_SIZE 5
int main()
{
int array[MAX_SIZE];
int x = 0;
int r = 0;
while (x < MAX_SIZE)
{
int i = 0;
printf("type in a number: \n");
r = scanf("%d",&i);
if (r == 0)
{
printf("ERROR!\n");
break;
}
if (r == EOF)
{
printf("EOF!\n");
break;
}
array[x]=i;
x++;
}
}
You cannot write 'EOF'.. since you are reading into a number...
EOF equals -1.. so if he enterd that, the loop would stop
You can test for the return value of the scanf function. It returns EOF on matching failure or encountering an EOF character.
printf("type in a number:" \n);
while(scanf("%f",&i)!=EOF){
array[x]=i;
x++;
printf("type in a number:" \n);
}
Here is some C code trying simply to prevent the user from typing a character or an integer less than 0 or more than 23.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char *input;
char *iPtr;
int count = 0;
int rows;
printf("Enter an integer: ");
scanf("%s", input);
rows = strtol(input, &iPtr, 0);
while( *iPtr != '\0') // Check if any character has been inserted
{
printf("Enter an integer between 1 and 23: ");
scanf("%s", input);
}
while(0 < rows && rows < 24) // check if the user input is within the boundaries
{
printf("Select an integer from 1 to 23: ");
scanf("%s", input);
}
while (count != rows)
{
/* Do some stuff */
}
return 0;
}
I made it halfway through and a small push up will be appreciated.
Use scanf("%d",&rows) instead of scanf("%s",input)
This allow you to get direcly the integer value from stdin without need to convert to int.
If the user enter a string containing a non numeric characters then you have to clean your stdin before the next scanf("%d",&rows).
your code could look like this:
#include <stdio.h>
#include <stdlib.h>
int clean_stdin()
{
while (getchar()!='\n');
return 1;
}
int main(void)
{
int rows =0;
char c;
do
{
printf("\nEnter an integer from 1 to 23: ");
} while (((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) || rows<1 || rows>23);
return 0;
}
Explanation
1)
scanf("%d%c", &rows, &c)
This means expecting from the user input an integer and close to it a non numeric character.
Example1: If the user enter aaddk and then ENTER, the scanf will return 0. Nothing capted
Example2: If the user enter 45 and then ENTER, the scanf will return 2 (2 elements are capted). Here %d is capting 45 and %c is capting \n
Example3: If the user enter 45aaadd and then ENTER, the scanf will return 2 (2 elements are capted). Here %d is capting 45 and %c is capting a
2)
(scanf("%d%c", &rows, &c)!=2 || c!='\n')
In the example1: this condition is TRUE because scanf return 0 (!=2)
In the example2: this condition is FALSE because scanf return 2 and c == '\n'
In the example3: this condition is TRUE because scanf return 2 and c == 'a' (!='\n')
3)
((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())
clean_stdin() is always TRUE because the function return always 1
In the example1: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is TRUE so the condition after the && should be checked so the clean_stdin() will be executed and the whole condition is TRUE
In the example2: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is FALSE so the condition after the && will not checked (because what ever its result is the whole condition will be FALSE ) so the clean_stdin() will not be executed and the whole condition is FALSE
In the example3: The (scanf("%d%c", &rows, &c)!=2 || c!='\n') is TRUE so the condition after the && should be checked so the clean_stdin() will be executed and the whole condition is TRUE
So you can remark that clean_stdin() will be executed only if the user enter a string containing non numeric character.
And this condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) will return FALSE only if the user enter an integer and nothing else
And if the condition ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) is FALSE and the integer is between and 1 and 23 then the while loop will break else the while loop will continue
#include <stdio.h>
main()
{
char str[100];
int num;
while(1) {
printf("Enter a number: ");
scanf("%[^0-9]%d",str,&num);
printf("You entered the number %d\n",num);
}
return 0;
}
%[^0-9] in scanf() gobbles up all that is not between 0 and 9. Basically it cleans the input stream of non-digits and puts it in str. Well, the length of non-digit sequence is limited to 100. The following %d selects only integers in the input stream and places it in num.
You could create a function that reads an integer between 1 and 23 or returns 0 if non-int
e.g.
int getInt()
{
int n = 0;
char buffer[128];
fgets(buffer,sizeof(buffer),stdin);
n = atoi(buffer);
return ( n > 23 || n < 1 ) ? 0 : n;
}
char check1[10], check2[10];
int foo;
do{
printf(">> ");
scanf(" %s", check1);
foo = strtol(check1, NULL, 10); // convert the string to decimal number
sprintf(check2, "%d", foo); // re-convert "foo" to string for comparison
} while (!(strcmp(check1, check2) == 0 && 0 < foo && foo < 24)); // repeat if the input is not number
If the input is number, you can use foo as your input.
You will need to repeat your call to strtol inside your loops where you are asking the user to try again. In fact, if you make the loop a do { ... } while(...); instead of while, you don't get a the same sort of repeat things twice behaviour.
You should also format your code so that it's possible to see where the code is inside a loop and not.
this is a reply to
prevent users from entering wrong data types
If you're dealing with just numbers
declare
char catchpan;
and then right after your scanf for a number input
put
scanf("%c", &catchpan);
its not a complete fix but if you have code that handles out of bounds stuff (assuming zero isn't a part of the bounds) it'll clear right up.
it ain't perfect and it ain't the general solution.