C: Nested do while loop not looping correctly - c

This code is supposed to -
Count the number of characters from input sequence.
Repeat the action until user exits the program.
Use nested do-while loop to achieve this purpose.
But the inner loop is executed only once.
Why?
#include <stdio.h>
int main ()
{
int x;
char i, ans;
i = '\0';
do
{
i = '\0';
x=0;
printf("\nEnter sequence of character:");
do
{
i = getchar();
x++;
}
while(i!='\n');
printf("\nNumber of characters entered is: %d", --x);
printf("\nMore sequences (Y/N) ?");
ans = getchar();
}
while(ans =='Y' || ans == 'y');

After you read the answer yes/no (the line with ans = getchar();), you'll read an "y" and a "\n". You'll consume the "y" and process it, but the next iteration when you read i = getchar();, i will consume the remaining "\n", so will break that do-while loop.
Although it's not my favourite solution, a simple workaround is this:
#include <stdio.h>
int main ()
{
int x;
char i, ans;
i = '\0';
do
{
i = '\0';
x=0;
printf("\nEnter sequence of character:");
do
{
i = getchar();
x++;
}
while(i!='\n');
printf("\nNumber of characters entered is: %d", --x);
printf("\nMore sequences (Y/N) ?");
ans = getchar();
getchar();
}
while(ans =='Y' || ans == 'y');
}
So just consume that extra "\n". This will work only if you type "y" followed by "\n" in terminal. If you type any extra characters, you'll have undefined behaviour.
Note: In your version, try to type: "y1234" then enter when prompted if you want to input again. You'll see that in fact the nested do-while loop works and will count the 4 characters after "y".

What happened:
getchar is a macro that gets a character from stdin.
The delimiter ('\n' in this case) is counted as a separate
character that remains in the buffer and is retrieved the next time
getchar() is called.
This causes inner loop to exit.
What could be done:
Insert the following after ans = getchar();
i = getchar();
if(i != '\n')
ungetc(i,stdin);
New code explained:
ungetc(int x,FILE *stream) pushes a character back into input stream.
stdin is the standard input stream defined in <stdio.h>.
We are reading a character and putting it back if it is not '\n'.

Not exactly sure, but I think that when the user presses enter to finish the 1st input character the input buffer keeps then enter button as the \n character. Try adding if(i == '\n') getChar(); after the x++;.

Related

User input with scanf using while loop

I'm having a problem with multiple characters while using a while loop. I'm writing a code that would direct the user to a new function based on the input of either "y" or "n". When I scanf for one character it works fine; however, when the user types in multiple characters the while loop repeats.
#include <stdio.h>
int main()
{
char x;
printf("type in letter n or y\n");
scanf("%c", &x);
while (x!= 'Y' && x!='N' && x!= 'n' && x!='y')
{
printf("Invalid, please type Y/N to continue: \n");
scanf(" %c", &x);
}
if (x== 'Y' || x == 'y')
{
printf("y works");
}
if (x =='N' || x =='n')
{
printf("n works");
}
}
For example, if I type in hoyp, it would say "Invalid, ..." 2 times and then the "y works" would be written on the third line. How can the code be changed so that the invalid would only be said once, and the user must input again to allow the program to continue?
This is how scanf behaves. It keeps reading in all the characters you've entered. You can accept a string as input first using fgets and extract and check only its first character. fgets allows you to specify the exact number of characters to be read. I have first declared a char array of size 4096. This will work when the input is up to 4095 characters. You can adjust the size as per your needs.
#include <stdio.h>
int main()
{
char x, buffer[4096];
printf("type in letter n or y\n");
fgets(buffer, 4096, stdin);
x = buffer[0];
while (x!= 'Y' && x!='N' && x!= 'n' && x!='y')
{
printf("Invalid, please type Y/N to continue: \n");
fgets(buffer, 4096, stdin);
x = buffer[0];
}
if (x== 'Y' || x == 'y')
{
printf("y works");
}
if (x =='N' || x =='n')
{
printf("n works");
}
}
Here is my approach to the problem:
I have used fgets() instead of scanf(). See why
here.
I have used the suggestion by users jamesdlin and M.M in this question to solve the repeated printing issue when the input is more than one character or if the input is empty. I encourage you to read the whole thread to know more about this issue.
(Optional) Used some extra headers for better code readability in the loop conditions. I think the fgets() could be used in the condition of the while() but I got used to the pattern I have written below.
Edit: added a condition to reject inputs with length > 1. Previously, inputs that starts with 'y' or 'n' will be accepted (and are interpreted as 'y' or 'n' respectively) regardless of their length.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
void clearInput();
int main()
{
// allocate space for 'Y' or 'N' + '\n' + the terminator '\0'
// only single inputs will be accepted
char _inputbuff[3];
char choice;
bool isValidInput = false;
while(!isValidInput) {
printf("Please enter your input[y/n]: ");
// use fgets() instead of scanf
// this only stores the first 2 characters of the input
fgets(_inputbuff, sizeof(_inputbuff), stdin);
// don't accept empty input to prevent hanging input
if(_inputbuff[0] == '\n') {
printf("Empty input\n");
// go back to the top of the loop
continue;
}
// input is non-empty
// if the allocated space for the newline does not
// contain '\n', reject the input
if(_inputbuff[1] != '\n') {
printf("Input is more than one char.\n");
clearInput();
continue;
}
choice = _inputbuff[0];
// printf("The input is %c\n", choice);
// convert the input to uppercase for a 'cleaner' code
// during input validation
choice = toupper(choice);
// the input is not 'Y' or 'N'
if(choice != 'Y' && choice != 'N') {
printf("Please choose from Y or N only.\n");
// go back to the top of the loop
continue;
}
// the input is 'Y' or 'N', terminate the loop
isValidInput = true;
}
// conditions for 'Y' or 'N'
if(choice == 'Y') {
printf("The input is Yes.\n");
return 0;
}
if(choice == 'N') {
printf("The input is No.\n");
return 0;
}
}
void clearInput() {
int _clear;
// clear input stream to prevent repeated printing of invalid inputs
while ((_clear = getchar()) != '\n' && _clear != EOF ) { }
}
(This is my first time answering a question and it has been a while since I have used C so feel free to give suggestions/corrections regarding my answer. Thanks!)

Can I read in a character without the return key 'n'? (C)

Im trying to verify if the user enters the right value with the return values.
He should enter an even number between 0 and 100.
I think I got it right, but now my problem is, that the user has to enter the "enter" key twice to end the scanf function.
Do I have another possibility to avoid the user from doing so?
Heres the code I wrote:
#include <stdio.h>
#include <windows.h>
int main( void )
{
int ok, input = -1;
char c;
while(input < 1 || input > 100 || input%2 != 0) { //repeat loop if Input is not even or betwenn 0 and 100
printf("Enter an odd number between 1 und 100: ");
int ok = scanf("%d%c", &input, &c); //Input is correct if ok = 2 and c = 10'\n'
while((c = getchar()) != '\n' && c != EOF) {} //this loop empties the input buffer to avoid infinite loops if users enters a character
}
printf("You habe chosen the number %d ", input);
getchar();
return 0;
}
I believe you don't need the second while loop at all.
As suggested above, the scanf() is waiting for enter to be pressed once, and then getchar() is waiting after.
If you remove the second while loop, the code should run correctly and only require the enter key to be pressed once.
I hope this helps!

Scanning character caused problem in devC

So my code does the following:
Ask what's the option
If option is 1: Scan some numbers
If option is 2: Print those numbers
After each option, ask if user wanted to continue choosing (Y/N)
This is my main code
while(yesnocheck==1)
{
printf("What's your option?: ");
scanf("%d",&b);
switch(b){
case 1:
printf("How many numbers?: ");
scanf(" %d",&n);
a=(struct sv*)malloc(n*sizeof(struct sv));
for(int i=0;i<n;i++)
scanf("%d",&((a+i)->num));
break;
case 2:
for(int i=0;i<n;i++)
printf("%d\n",(a+i)->num);
break;
}
yesnocheck==yesnochecker();
}
And this is the yesnochecker function:
int yesnochecker()
{
char yesorno;
printf("Do you want to continue? (Y/N)");
while(scanf("%s",&yesorno))
{
if(yesorno=='Y')
return 1;
if(yesorno='N')
return 0;
printf("*Wrong input. Please reenter (Y/N): ");
}
}
So on dev C++, my code won't run correctly. After it's done option 1, when I enter "Y" then choose option 2, case 2 will display some weird numbers. However it works well on online C compilers.
And then, when I change the char yesorno in yesnochecker() function to char yesorno[2] and treat it as a string, the code does work.
Can someone shed some light?
It is a bad idea to read a char c with scanf("%s", &c);. "%s" requires a buffer to store a string. The only string which fits into a char is an empty string (consisting only of a terminator '\0' – not very useful). Every string with 1 character requires 2 chars of storage – 1 for the character, 1 for the terminator ('\0'). Providing a char for storage is Undefined Behavior.
So, the first hint was to use the proper formatter instead – "%c".
This is better as it removes the Undefined Behavior. However, it doesn't solve another problem as the following sample shows:
#include <stdio.h>
int cont()
{
char c; do {
printf("Continue (y/n): ");
scanf("%c", &c);
printf("Input %c\n", c);
} while (c != 'y' && c != 'n');
return c == 'y';
}
int main()
{
int i = 0;
do {
printf("Loop iteration %d.\n", ++i);
} while (cont());
/* done */
return 0;
}
Output:
Loop iteration 1.
Continue (y/n): y↵
Input 'y'
Loop iteration 2.
Continue (y/n):
Input '
'
Continue (y/n): n↵
Input 'n'
Live Demo on ideone
WTH?
The scanf("%c") consumes one character from input. The other character (inserted for the ENTER key) stays in input buffer until next call of any input function.
Too bad, without ENTER it is hard to confirm input on console.
A possible solution is to read characters until the ENTER key is received (or input fails for any reasons). (And, btw., getc() or fgetc() can be used as well to read a single character.):
#include <stdio.h>
int cont()
{
int c;
do {
int d;
printf("Continue (y/n): ");
if ((c = fgetc(stdin)) < 0) {
fprintf(stderr, "Input failed!\n"); return 0;
}
printf("Input '%c'\n", c);
for (d = c; d != '\n';) {
if ((d = fgetc(stdin)) < 0) {
fprintf(stderr, "Input failed!\n"); return 0;
}
}
} while (c != 'y' && c != 'n');
return c == 'y';
}
int main()
{
int i = 0;
do {
printf("Loop iteration %d.\n", ++i);
} while (cont());
/* done */
return 0;
}
Output:
Loop iteration 1.
Continue (y/n): y↵
Input 'y'
Loop iteration 2.
Continue (y/n): Hello↵
Input 'H'
Continue (y/n): n↵
Input 'n'
Live Demo on ideone
Please, note, that I changed the type for the read character to int. This is because getc()/fgetc() return an int which is capable to store any of the 256 possible char values as well as -1 which is returned in case of failing.
However, it isn't any problem to compare an int with a character constant (e.g. 'y'). In C, the type of character constants is just int (SO: Type of character constant).

Program looping two times (printing statement twice)

I'm trying to make a simple program for which the user is supposed to enter character 'a'. It is supposed to loop until 'a' is input. I have one statement printed if there is no input which works correctly. There is another statement if an incorrect letter or number is input, but the problem is that this causes the program to loop more than once and it prints the statements multiple times. Any help in fixing this is appreciated.
#include <stdio.h>
int main()
{
char input;
int i, len,num;
len = 1;
do
{
puts("Please enter alphabet 'a': ");
scanf("%c", &input);
for(i=0; i<len; i++)
{
if(isalpha(input)==0)
{
printf("Please input something.\n");
continue;
}
if(input == 'A' || input == 'a')
{
printf("Congratulations! You successfully input letter 'a'.");
return(0);
}
else
{
printf("That's not letter 'a'.");
}
}
}
while(1);
}
The problem is that after entering the character, you press newline and this is send to the input buffer. Now the next time scanf() is called, it reads the value from the buffer which is '\n' and scanf() thus stores this to input. Now this can be easily solved by the method pointed by #Gopi, but there is a better way. This is the code.
#include <stdio.h>
#include<ctype.h>
int main()
{
char input,ch;
do
{
puts("Please enter alphabet 'a': ");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF); // look here
if(isalpha(input)==0)
{
printf("Please input something.\n");
continue;
}
if(input == 'A' || input == 'a')
{
printf("Congratulations! You successfully input letter 'a'.");
return(0);
}
else
{
printf("That's not letter 'a'.");
}
}
while(1);
}
Now with the statement while((ch=getchar())!='\n' && ch!= EOF);, all the characters like '\n' are just flushed and not stored to input and thus solves the problem.
Also note that you don't need the for loop here, its useless for this code ( unless this is not your original code and there are other parts in it ).
There is a newline character in the buffer after the first input which is not flushed and that is being picked up by the %c in the second iteration.
Change your scanf() to
scanf(" %c", &input);
Note the space before %c which gobbles the newline character

Do while loop with choice as char in C

In my code given below if I press 'y' for once it will reapeat, but then it is not asking for next tome to repeat (or press 'y').Can someone help why this code is terminated after one loop?
main()
{
char choice;
do
{
printf("Press y to continue the loop : ");
scanf("%c",&choice);
}while(choice=='y');
}
That will be because stdin is buffered. So you are probably entering the string of a y followed by a \n (newline character).
So the first iteration takes the y, but the next iteration doesn't need any input from you because the \n is next in the stdin buffer. But you can easily get around this by getting scanf to consume the trailing whitespace.
scanf("%c ",&choice);
NOTE: the space after the c in "%c "
But, your program can get stuck in an infinite loop if the input ends with a y. So you should also check the result of the scanf. e.g.
if( scanf("%c ",&choice) <= 0 )
choice = 'n';
You should read out the newline character after that scanf() call. Otherwise, that gets into choice the next time around and so the while loop comes out.
#include<stdio.h>
int main()
{
char choice;
do
{
printf("Press y to continue the loop : ");
choice = getchar();
getchar();
}
while(choice=='y');
return 0;
}
At the first character of the scanf format string, insert a space. This will clear out all white space characters from stdin before reading data.
#include <stdio.h>
int main (void)
{
char choice;
do
{
printf("Press y to continue the loop : ");
scanf(" %c",&choice); // note the space
}while(choice=='y');
return 0;
}

Resources