Code making an infinite loop when ask input with scanf [duplicate] - c

This question already has answers here:
if my scanf variable is a float and a user inputs a character how can i prompt them to input a number? assuming the scanf is inside a do while loop
(2 answers)
Why is scanf() causing infinite loop in this code?
(16 answers)
I am not able to flush stdin. How can I flush stdin in C?
(8 answers)
Closed 3 years ago.
i have a function that ask to the user to enter a value to calculate its square root, however when i try to validate that the number of the input must be a number and not a char, it makes an infinite loop
void opcion1(void){
float A, K, i, aux;
int awnser;
ask:
fflush( stdin );
printf("enter the value for A: ");
sleep(1);
awnser = scanf("%f", &A);
if(awnser < 1){ // not a number
fputs("\nA is not a number\n", stderr);
goto ask;
}
if(A < 0 ){
aux = -A;
i = sqrt(aux);
if(A == (int)A) printf("\nthe square root of %.0f, is%.0fi", A, i);
else printf("the square root of %.3f, is %.4fi", A, i);
}else{
K = sqrt(A);
printf("the square root of A is %.2f", K);
}
}
output:
enter the value for A:
k
A is not a number
enter the value for A:
A is not a number
enter the value for A:
A is not a number
enter the value for A:
A is not a number
enter the value for A:

The main issue is that its hard to understand all these concepts when you are just starting with the language. Like where the hell does scanf take the input? What is buffering?
I won't talk about technical terms, you can always google them if you want to go deep, will try to keep it simple. Also I am just talking from unix side and donno anything about windows.
scanf(3) calls read(2) internally and printf(3) calls write(2). So why don't we use read(2) and write(2) directly? The issue is that read(2)/write(2) are slow because for them a switch needs to be made to from user mode to kernel mode and this is a time taking process. What scanf() and printf() do is that they stay in user mode and collect the information there and read/write it in one go i.e. they store it in a buffer for time being.
Now this makes some more things possible. As the input hasn't reached your variable yet and is in the buffer, scanf() can do additional checks. Like in your case, check if the input is as per your format specifier. If not it won't assign it to your variable and return. But scanf won't clear that buffer where it received input. In your case in scanf(), when your input is not as per %f, it returns 0 and your if condition makes it go up and input again. But it never cleared the buffer. So the buffer contains the same input as from before and it acts again on it causing the same problem again. This continues infinitely.
Now to the solution:
This is a little confusing due to "standards" issue.
When you see the manpage of fflush(3),
It states:
For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application.
But then at the bottom of the page,
The standards do not specify the behavior for input streams. Most other implementations behave the same as Linux.
So fflush(stdin) doesn't seem to work like that on your system. (just as it doesn't on mine)
Best ways to achieve this have already been discussed in many questions:
How to solve your problem:
Scanf skips every other while loop in C
Better way:
Using fscanf() vs. fgets() and sscanf()
Another way is to change fflush(stdin) to fpurge(stdin)(ITS NOT PORTABLE AND NOT STANDARD).
From the manpage of fpurge(3) which I don't see being discussed anywhere:
The function fpurge() clears the buffers of the given stream. For
output streams this discards any unwritten output. For input streams
this discards any input read from the underlying object but not yet
obtained via getc(3); this includes any text pushed back via
ungetc(3).
Also have a look at why its not a good idea to use goto in such scenarios. What is wrong with using goto?

Related

Can somebody explain why the line of this code containing fgets isn't getting executed? [duplicate]

This question already has answers here:
fgets doesn't work after scanf [duplicate]
(7 answers)
Closed 1 year ago.
#include <stdio.h>
#include <string.h>
int main()
{
int num;
char answer[10];
char affirmation[10]="yes";
do
{
printf("Enter a number : \n");
scanf("%d",&num);
if (num % 97 == 0)
{
printf("No. is divisible by 97!\n");
}
else
{
printf("No. is not divisible by 97!\n");
}
printf("Once More ? [yes/no] \n");
fgets(answer,sizeof(answer),stdin);
}
while(strcmp(affirmation,answer) == 0);
return 0;
}
I expected from this program to check the divisibility of a provided number by 97 and then to ask if I again want it to check for another number if I input "yes". But it isn't prompting for my input .
If anybody can explain the reason behind this problem and suggest some ways to get through, it will be appreciated.The output is given below:
This output is for num = 194.
It is being executed but what it's reading is the newline character in the input stream that wasn't read when you did the scanf.
What your scanf does is to first skip any white space, then read an integer up to but not including the first non-digit character, which is probably the \n generated by the ENTER key.
Then, because fgets reads a line up to the next newline, you get an empty line.
In both the preceding two paragraphs, I'm assuming for simplicity ideal conditions such as ensuring it's a valid integer and that the line is not longer than the size you provided. Obviously, deviating from that could cause unruly behaviour.
It's generally not a good idea to mix the two input types unless you know in great detail what will be in the input stream. It's often better to just use line-based input and then sscanf that into more appropriate variables.
That way, you can be more sure about where your input stream is at any given point.
A quick fix in this particular case is simply to augment your scanf so that it skips to the start of the next line:
scanf("%d",&num);
while (getchar() != '\n') {}
The other problem you'll have after that is the fact that your fgets input will actually be "yes\n" rather than "yes", so that string comparison won't work.
If you're after a fairly robust line input function that takes care of that (and many other things), see here.

While loop never stops when I enter a character in a place [duplicate]

This question already has answers here:
Why is scanf() causing infinite loop in this code?
(16 answers)
Closed 5 years ago.
I have a problem with this loop when I enter a character for ˋscanfˋ. The loop will never stop. But when I enter a number all works good.
This Is The Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
int x;
printf("Enter 1 Or 2\n");
scanf("%i",&x);
while (x!=1 && x!=2) {
printf("Please Enter A Right Value \n");
scanf("%i",&x);
}
printf("Finish");
}
Well when you input character, scanf actually tries to get those wrong character inputs from the stdin but as it is not as per the conversion specification provided it fails. And then it keeps those wrong input in the stdin. And next time the scanf fails again due to those wrong inputs. So you need to clear it before you attempt to get the input again using scanf. Also check the return value of scanf and in case it failed clear the stdin.
The provided code checks for EOF and also return value of scanf the standard says explicitly about the return value of scanf :-
7.21.6.2p16
The fscanf function returns the value of the macro EOF if an
input failure occurs before the first conversion (if any) has
completed. Otherwise, the function returns the number of input
items assigned, which can be fewer than provided for, or even
zero, in the event of an early matching failure.
The code will be something like this. (This is using scanf).
Better even use fgets. you can easily and more better way control the erro neous inputs. With fgets you will read the entire line and then parse the integer input from it using strtol or strtoul. Yes in case of integer input there will be a case there also - you need to check if the parsed long or unsigned long is of proper size so that they can be kept in int variable.

fflush(stdin) not working on Xcode on Mac [duplicate]

This question already has answers here:
fflush(stdin) function does not work
(3 answers)
fflush() is not working in Linux
(9 answers)
Why fflush(stdin) does not remove buffer (stdin) [duplicate]
(2 answers)
How to clear input buffer in C?
(18 answers)
Closed 5 years ago.
This is the code which I'm trying to run on my Mac. In this the statement after fflush doesn't work. After fflush the compiler should stop and wait for the user input but it doesn't.
Can anyone tell me why this is happening or is there any other way to do it?
int main()
{
int pos,neg,zero,num;
char ans = 'y';
pos=neg=zero=0;
while(ans == 'y' || ans=='Y')
{
printf("\nEnter a number : ");
scanf("%d",&num);
if(num==0)
zero++;
if(num>0)
pos++;
if(num<0)
neg++;
fflush(stdin);
printf("\nDo you want to continue?\n\n");
scanf("%c",&ans);
}
printf("You entered %d positive numbers\n",pos);
printf("You entered %d negative numbers\n",neg);
printf("You entered %d zeros \n",zero);
return 0;
}
From standard 7.21.5.2
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes
any unwritten data for that stream to be delivered to the host
environment to be written to the file; otherwise, the behavior is
undefined.
You were having undefined behavior in your code. More clearly, fflush won't work. The most common way to do it would be something as shown below:
int c;
while ((c = getchar()) != '\n' && c != EOF){}
Another solution would be to use (much easier for you but not robust)
scanf(" %c",&ans);
^^
This will make sure all white space is being consumed. This will solve one of the problem that may arise, but not all. (The others arise due to use of scanf and wrong input).
Side note
Also another way to get rid of this problem altogether would be to use fgets or similar to read one line and then use strtol or strtod to get the desired input parsed from the inputted line. scanf is extremely useful for formatted input. The scenario which you will have - it is better to use fgets, there are too many cases with scanf that you have to deal with otherwise.
For wrong input you need to flush the standard input so that you don't have to deal with them again in the next scanf. If you use fgets then you will get the input line from the stdin and then if you can parse it and the input is correct - you go on processing it, else you discard the whole line and wait for the next fgets call.

C - printf and scanf buffer

I'm sorry about the generic title, but i didn't find anything better.
And I'm sorry if the question is stupid but I'm a novice and I could not find anything of use to me.
I have written this code to solve a simple problem: you have a sequence of positive integers terminated by a negative: for every integer you have to print a corresponding amount of * characters and go to a new line.
The code DOES WORK but I can't really understand WHY.
int main()
{
int d=0,i;
while (d>=0){
scanf("%d",&d);
for (i=0;i<d;i++)
{
printf("*");
}
printf("\n");
}
return 0;
}
I did a bit of research and I understand that terminal gives the integer sequence to scanf only when I press return.
I thought it would work this way:
scanf gets the integer sequence it registers the first one while the others are discarded
prints the amount of *s corresponding to the first integer
Instead it seems that scanf reads the first integer, then printf sends it to a buffer then the cycle restarts and scanf gets the second integer and so on.
When the last positive integer is reached printf flushes the buffer.
Am I wrong? And if not, why does it work this way?
scanf() does reads the first integer, then printf sends it to a buffer then the cycle continues and scanf gets the second integer and so on. After a negative integer is reached the rest of stdin is ignored. stdout is flushed with each \n and program ending.
This should clear your ideas about scanf
http://home.datacomm.ch/t_wolf/tw/c/getting_input.html

C programming elementary problem

#include <stdio.h>
#include <math.h>
int main (void)
{
float inches;
printf("Enter the number of inches\n");
scanf("%f\n",&inches);
float feet;
float cm;
float yards;
float meter;
feet = 12 * inches;
cm = 2.54 * inches;
yards = 36 * inches;
meter = 39.37 * inches;
printf("Amount in feet: %f\n", &feet);
printf("Amount in cm: %f\n", &cm);
printf("Amount in yards: %f\n", &yards);
printf("Amount in meters: %f\n", &meter);
getchar();
return 0;
}
I'm using Dev c++
Is the problem i'm problem I'm working on in C. Basically enter in a number in inches then print amount in cm,yards,meters and feet. This is giving me 0.0000 or something for all of them or actually the time it is up. I can't keep the screen up and I thought that was the purpose of getchar() but I must have been mistaken. Any help is great. Thanks!
EDIT 1
What about as far as keeping dev c++ on the screen instead of closing out after I put stuff in? I am also having to put 2 values in before it returns in anything when the screen pops up? Why??
Two problems:
The usual problem with using scanf(), in that it leaves the newline after the number unread and the following read operation (the getchar() here) reads it.
You shouldn't pass pointers to printf(), but the actual values.
You're trying to print the addresses of your floats as floats, you just want to say this:
printf("Amount in feet: %f\n", feet);
Note the lack of an address (&) operator on feet. You want to apply similar changes to your other printf calls.
With printf, you don't give it the address of the float values, you just give it the values. Remove the &s from the printf calls.
You need the address in scanf because the function modifies the variables that you pass in, but printf just needs the values. As it is, the printf is essentially reinterpreting the pointers as floats, which is why you get the garbage values displayed.
About I can't keep the screen up, it's a common problem to everyone trying to execute a console program in a graphical environment directly from the IDE, in particular Dev-C++. The problem is that there's no console for I/O, then one is provided but just for the time the program is running, and since programs are fast, if you do not add a pause after your last input and output, you won't have the time to read the output.
Many MS Windows Dev-C++ users add an horrorific system("pause"). I always suggest that, if Dev-C++ is not able to provide a console for I/O with the option "keep it opened even after the program ends", then it is better you open a shell (cmd or powershell on windows) and run your program directly from there.
About the input problem, unluckly scanf-ing has several buffering problem since the input that is not recognized for the given format is not discarded and is ready for the next reading. E.g.
scanf("%f", &aFloat);
scanf("%f", &theNextFloat); // in your case you have the extra getchar();
won't stop for the second scanf if you write 1.25 4.5 as first input, since the 4.5 is already available for the next scanf. In your case it was a newline that was left in the buffer and since getchar has found it, it does not need to wait for input. You could use a
while( getchar() != EOF ) ; instead, and then to exit you need to hit Ctrl-D.

Resources