While scanf!=EOF or scanf==1? - c

Ceteris paribus (well formed data, good buffering practices and what not), is there a reason why I prefer to loop while the return of scanf is 1, rather than !EOF? I may have read this somewhere, or whatever, but I may have it wrong as well. What do other people think?

scanf returns the number of items succesfully converted ... or EOF on error. So code the condition the way it makes sense.
scanfresult = scanf(...);
while (scanfresult != EOF) /* while scanf didn't error */
while (scanfresult == 1) /* while scanf performed 1 assignment */
while (scanfresult > 2) /* while scanf performed 3 or more assignments */
Contrived example
scanfresult = scanf("%d", &a);
/* type "forty two" */
if (scanfresult != EOF) /* not scanf error; runs, but `a` hasn't been assigned */;
if (scanfresult != 1) /* `a` hasn't been assigned */;
Edit: added another more contrived example
int a[5], b[5];
printf("Enter up to 5 pairs of numbers\n");
scanfresult = scanf("%d%d%d%d%d%d%d%d%d%d", a+0,b+0,a+1,b+1,a+2,b+2,a+3,b+3,a+4,b+4);
switch (scanfresult) {
case EOF: assert(0 && "this didn't happen"); break;
case 1: case 3: case 5: case 7: case 9:
printf("I said **pairs of numbers**\n");
break;
case 0:
printf("What am I supposed to do with no numbers?\n");
break;
default:
pairs = scanfresult / 2;
dealwithpairs(a, b, pairs);
break;
}

Depends what you want to do with malformed input - if your scan pattern isn't matched, you can get 0 returned. So if you handle that case outside the loop (for example if you treat it the same as an input error), then compare with 1 (or however many items there are in your scanf call).

From http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
On success, the function returns the
number of items succesfully read. This
count can match the expected number of
readings or fewer, even zero, if a
matching failure happens. In the case
of an input failure before any data
could be successfully read, EOF is
returned.
The only way to be sure that you read the number of items intended is to compare the return value to that number.

Related

Do while loop with switch case in C language not working

I'm trying to do this loop in C, where you would press enter and be in it and you either press 0 to exit or 3 to continue in it. But somehow the Switch commands are no being activated. Note that there is a different messages on each of them that is supposed to differentiate them from the other outcomes. Can someone help me understand the problem with this code?`Note: the code is obviously within int main().
int I = 1;
printf("Press enter to start the loop...");
getchar();
do
{
printf("\nYou are in a LOOP. Would you like to stay in it, or leave it? \nPress 0 to leave the loop or press 3 to stay in it: ");
scanf_s("%d", &I);
getchar();
switch (I)
{
case'3':
printf("\nYou are STILL inside the LOOP. Press 0 to leave it or press 3 to stay in it: ");
getchar();
break;
case'0':
printf("\nExiting the LOOP...");
break;
default:
printf("\nPlease, enter a valid command...: ");
if (scanf_s("%d", &I) != 3 || scanf_s("%d", &I) != 0);
{
fflush(stdin);
}
break;
}
while (I != 0);
printf("\nCongratulations! You are OUT of the LOOP!");
As others have pointed out, you are reading in an integer with scanf_s(), but comparing against a character literal inside the switch statement.
switch'3': should be written as switch 3: (using an integer literal instead). Same goes for the 0 case.
Also, your example is missing a curly brace } before while(I != 0);.
It is also worth mentioning that scanf_s() "returns the number of fields successfully converted and assigned" (from https://msdn.microsoft.com/en-us/library/w40768et.aspx). That is, your scanf_s() call in the default switch case will only ever return 0 or 1 when reading in a single integer (or EOF on error).

Use switch-case construction to count how many times a number has been typed

Create a C-program that counts how many times each of the numbers 0-4 have been typed. Use a switch-case construction. Use default to count the number of other characters. Print the amount of times a certain number has been typed.
Here is my code:
int main()
{
int a;
int num_0 = 0;
int num_1 = 0;
int num_2 = 0;
int num_3 = 0;
int num_4 = 0;
int num_other = 0;
printf("Input something\n");
while ((a = getchar()) != EOF)
{
switch (a)
{
case 0:
num_0++;break;
case 1:
num_1++;break;
case 2:
num_2++;break;
case 3:
num_3++;break;
case 4:
num_4++;break;
default:
num_other++;break;
};
}
printf("0 has been typed %d", num_0);printf(" times\n");
printf("1 has been typed %d", num_1);printf(" times\n");
printf("2 has been typed %d", num_2);printf(" times\n");
printf("3 has been typed %d", num_3);printf(" times\n");
printf("4 has been typed %d", num_4);printf(" times\n");
printf("other characters have been typed %d", num_other);printf(" times\n");
return 0;
}
No matter what I input, all the numbers including 0,1,2,3,4 were counted as other characters. Could someone tell me why my code didn't work.
switch (a) will compare the code of a. If you typed digits, it should be;
case '0':
num_0++;break;
case '1':
num_1++;break;
...
switch on character values not integers (int value of 0 is not 0, for example in ASCII it is 48, but let's not use the value directly, so it's fully portable)
Maybe a better thing to do would be to create a table instead:
int count[10] = {0};
....
a -= '0'; // removes the offset
if ((a >= 0) && (a < 10)) // check bounds
{
count[a]++;
}
Your answer is in man getchar (emphasis mine)
fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.
getc() is equivalent to fgetc() except that it may be implemented as a macro which evaluates stream more than once.
getchar() is equivalent to getc(stdin).
After that, the numerical representation of a character need not be the same as the character value (and mostly, is not), i.e., a character 0 ('0') does not have the numerical value of 0, in ASCII encoding, it has a decimal value of 48.
So, to count a character '0', you should set the case values to '0', not 0.
a = getchar()
When you are reading characters, the value gets stored in variable is the ASCII value. When you type 1 the value getting stored in a is 49.
switch (a)
{
case 1:
num_0++;
break;
}
In this code you are comparing with ASCII value 49(ASCII value for 1) with ASCII value 1 and comparison return false.
Similarly all the conditions give false and goes to default case.
There are some mistake in your code .
1) You are taking input through getchar() function , so it takes character in the input .
2) Take the input variable 'a' as char not int .
3) Mark single quotes in case options like case '1' because you are taking input as a character so you must mark single quotes .

Loop showing menu never ends

I'm trying to write a simple menu in C.
This is my proposed code:
while (end == 0) {
printf("Main menu\n");
printf("=========\n");
printf("1) Option 1.\n");
printf("2) Option 2.\n");
printf("3) Option 3.\n");
printf("4) Option 4.\n");
printf("0) Exit");
printf("\n");
printf("Choose an option: ");
fgets(&menu_option,1,stdin);
switch (menu_option) {
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
}
}
However, when executing this code, the loop never ends.
What's wrong?
Thank you.
EDIT: when I say "the loop never ends", I want to say that I can't write any option because the menu appears again and again.
From fgets
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.
Since you give a length of 1, n-1 will be 0 and so your input is never stored in menu_option. Change it to a char array
char menu_option[10];
// ...
fgets(menu_option, sizeof(menu_option), stdin);
switch (menu_option[0]) {
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
}
Update:
It is necessary to use char arrays, because you need enough space to store the input. The minimum size for a buffer is two characters, e.g. char buf[2], because fgets stores your input plus a terminating NUL character.
The loop iterates twice or even more times, because when you input e.g. 1 return or 1 3 2 return, it will first return 1, then 3, 2 and finally return. If you want to read the whole line and use the first digit only, your buffer must be larger than just 2, like e.g. 10 or even 256.
fgets reads a string instead of character. The statement
fgets(&menu_option,1,stdin);
Will store a string to menu_option but to store a string you need a size at least 2 bytes.
char menu_option[2];
...
fgets(menu_option,2,stdin);
int c;
while((c = getchar()) != '\n' && c != EOF); // This will be needed to flush your input buffer
switch (menu_option[0]) {
...
...
}
From: http://www.cplusplus.com/reference/cstdio/fgets/
fgets
char * fgets ( char * str, int num, FILE * stream );
Get string from stream.
Reads characters from stream and stores them as a C
string into str until (num-1) characters have been read or either a
newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a
valid character by the function and included in the string copied to
str.
A terminating null character is automatically appended after the
characters copied to str.
Since you have specified 1 for the number, 0 bytes are read, and the only thing that happens is that a terminating null character is appended. The result is an infinite loop in which nothing is read.
Since in the comments you expressed dislike for using strings, here's alternative implementation with minimal changes to the question code:
while (end == 0) {
printf("...menu print snipped...\n");
int ch = getchar();
switch (ch) {
case EOF: // end of file or error, fall through to exit option
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
// default: // add error message?
}
// ignore any extra chars in the same line
while ((ch = getchar() != '\n') {
// test for end of file and set end to true
if (ch == EOF) {
end = 1;
break;
}
}
}
Note the extra loop, which will read and discard rest of the input line. Without it, user can enter several options on one line, which is probably not desirable. Also note, if the option functions read more user input, consider how you handle long lines then. For example move the extra loop to be before switch (and add another variable to read discarded chars). Actually you should probably put the extra loop to it's own function discard_until_newline.

Program pauses at loop

I've got a simple C program, which loops to get an indefinite amount of numbers from the user (it's a CAS of sorts). I'm working on the program in multiple languages, and while the C++ version works perfectly, the C version stalls at the end of the loop, when the program asks for another user operation, requiring the user to input the operation twice. Here's how the program should work:
Enter an operation
4+2
6
6+2 // User adds 2 to the previous answer
8+x // User can continue adding like this indefinitely
Instead, here's what happens:
Enter an operation
4+2
6+2
// nothing happens until user enters "+2" again
+2
8+x
+x
[sum of 8+x]
and so on.
I initially thought this pause was caused by the program asking for user input twice, once at the start of the loop, and then at the end before looping. I put an iteration counter in the loop to determine what kind of input the program should get (either &num1,&op,&num2 or &op,&num2). For some reason, that didn't make a difference. Here's the relevant part of the code:
int opnubmer;
opnumber = 0;
printf("Enter an operation\n");
while(op != '=')
{
if (opnumber == 0)
{
scanf("%d%c%d",&num1,&op,&num2);
}
else if (opnumber != 0)
{
scanf("%s%d",&op,&num2);
}
switch(op)
{
case '+':
num2 += num1;
break;
case '-':
num2 -= num1;
break;
case '*':
num2 *= num1;
break;
case '/':
num2 /= num1;
break;
default:
printf("%s%c%s", "Unknown op: ", op, "\n");
exit(1);
}
printf("Solution: ");
printf("%d",num2);
opnumber++;
num1=num2;
}
Can anyone help me out?
It looks like you made a typo in the second scanf call, where you used %s instead of %c to read the op.
Furthermore, when using scanf to read input, you have to be very careful with whitespace. Trailing whitespace (including newlines) is left on the input stream, so the next time you read from the input stream, the whitespace is the first thing it'll see.
Instead of using scanf, use fgets to read the input one line at a time into a buffer, and then parse what you need out of that buffer. Eg. :
char line[256];
fgets(line, sizeof(line), stdin);
sscanf(line, "%d%c%d", &num1, &op, &num2);
It behaves absolutely fine, when you are not in the first iteration, you are looking for a string, even if you fix it with a change to %c your program expects only a character and a number not a number character number sequence.

C - Reading user input

I have a program where user input is required, a user types in a number 1-8 to determine how to sort some data, but if the user just hits enter a different function is performed. I get the general idea of how to do this and I thought what I had would work just fine but I'm having some issues when it comes to when the user just hits the enter key. Currently my code looks as follows:
//User input needed for sorting.
fputs("Enter an option (1-8 or Return): ", stdout);
fflush(stdout);
fgets(input, sizeof input, stdin);
printf("%s entered\n", input); //DEBUGGING PURPOSES
//If no option was entered:
if(input == "\n")
{
printf("Performing alternate function.");
}
//An option was entered.
else
{
//Convert input string to an integer value to compare in switch statment.
sscanf(input, "%d", &option);
//Determine how data will be sorted based on option entered.
switch(option)
{
case 1:
printf("Option 1.\n");
break;
case 2:
printf("Option 2.\n");
break;
case 3:
printf("Option 3.\n");
break;
case 4:
printf("Option 4.\n");
break;
case 5:
printf("Option 5.\n");
break;
case 6:
printf("Option 6.\n");
break;
case 7:
printf("Option 7.\n");
break;
case 8:
printf("Option 8.\n");
break;
default:
printf("Error! Invalid option selected!\n");
break;
}
}
Now I've changed the if statement to try input == "", input == " ", and input == "\n" but none of these seems to work. Any advice would be greatly appreciated. Currently from what I can see, the initial if statement fails and the code jumps to the else portion and then prints the default case.
Just to be clear the variables I declared for this code are as follows:
char input[2]; //Used to read user input.
int option = 0; //Convert user input to an integer (Used in switch statement).
The problem is in how you're doing the string comparison (if (input == "\n")). C doesn't have a "native" string type, so to compare strings, you need to use strcmp() instead of ==. Alternatively, you could just compare to the first character of the input: if (input[0] == '\n') .... Since you're then comparing char's instead of strings, the comparison doesn't require a function.
Try:
#include <string.h>
at the top and
if(strcmp(input, "\n") == 0)
in place if your if ( input == ... )
Basically, you have to use string comparison functions in C, you can't use comparison operators.
Try:
input[0] == '\n'
(or *input == '\n')
You need to use single quotes rather than double quotes
if(input == "\n")
compares the input address to the address of the string "\n",
What you want to do is to compare the first character of the input buffer
to the character literal \n like this
if(input[0] == '\n')
Note the use of single quotes around '\n'
You need to capture return code from sscanf, it will tell you how many of the field are "assigned", which in "Enter" key case, return code of 0
edit:
you should use strcmp when comparing string, not the operator "==".
The issue is with strings, you are comparing pointers, i.e. memory addresses. Since the input and "\n" aren't the same exact memory, it always fails (I assume input is a char *). Since you're looking for a single character, you can instead dereference input and compare to a char using single quotes instead of double.
(*input == '\n')
Should work as you intend.

Resources