I'm learning C in my school for 2 months and I have to make a Halma's Game in the console, so I'm a newbie for now.
I use Clion and CodeBlock but I prefer Clion for his internal console.
The game work pretty good, but I've got 2 weird issues that I can't fix by myself:
- My loop is presumed to stop with the scanf,but it doesnt.
("saut" variable).
It work only in the 2nd(or more) passage in the loop.
-The variable "h" increment during the loop (in order to ignore the next condition when you are out the loop), but the program always get in.
I don't know why..
Check my code:
MY CODE (IN FRENCH DON'T WORRY ABOUT
Thanks for your help.
Robin.
On some platforms (especially Windows and Linux) you can use fflush(stdin);:
Do modify your code like :-
while(saut==1)
...
....
scanf("%d",&saut);
fflush(stdin);
}
fflush(stdin);
these is another trick to solve this issue :-
It goes into an infinite loop because scanf() will not consumed the input token if match fails. scanf() will try to match the same input again and again. you need to flush the stdin.
if (!scanf("%d", &sale.m_price)) fflush(stdin)
Related
Suppose I want to run the following C snippet:
scanf("%d" , &some_variable);
printf("something something\n\n");
printf("Press [enter] to continue...")
getchar(); //placed to give the user some time to read the something something
This snippet will not pause! The problem is that the scanf will leave the "enter" (\n)character in the input stream1, messing up all that comes after it; in this context the getchar() will eat the \n and not wait for an actual new character.
Since I was told not to use fflush(stdin) (I don't really get why tho) the best solution I have been able to come up with is simply to redefine the scan function at the start of my code:
void nsis(int *pointer){ //nsis arconim of: no shenanigans integer scanf
scanf("%d" , pointer);
getchar(); //this will clean the inputstream every time the scan function is called
}
And then we simply use nsis in place of scanf. This should fly. However it seems like a really homebrew, put-together-with-duct-tape, solution. How do professional C developers handle this mess? Do they not use scanf at all? Do they simply accept to work with a dirty input stream? What is the standard here?
I wasn't able to find a definite answer on this anywhere! Every source I could find mentioned a different (and sketchy) solution...
EDIT: In response to all commenting some version of "just don't use scanf": ok, I can do that, but what is the purpose of scanf then? Is it simply an useless broken function that should never be used? Why is it in the libraries to begin with then?
This seems really absurd, especially considering all beginners are taught to use scanf...
[1]: The \n left behind is the one that the user typed when inputting the value of the variable some_variable, and not the one present into the printf.
but what is the purpose of scanf then?
An excellent question.
Is it simply a useless broken function that should never be used?
It is almost useless. It is, arguably, quite broken. It should almost never be used.
Why is it in the libraries to begin with then?
My personal belief is that it was an experiment. It tries to be the opposite of printf. But that turned out not to be such a good idea in practice, and the function never got used very much, and pretty much fell out of favor, except for one particular use case...
This seems really absurd, especially considering all beginners are taught to use scanf...
You're absolutely right. It is really quite absurd.
There's a decent reason why all beginners are taught to use scanf, though. During week 1 of your first C programming class, you might write the little program
#include <stdio.h>
int main()
{
int size = 5;
for(int i = 0; i < size; i++) {
for(int j = 0; j < size; j++)
putchar('*');
putchar('\n');
}
}
to print a square. And during that first week, to make a square of a different size, you just edit the line int size = 5; and recompile.
But pretty soon — say, during week 2 — you want a way for the user to enter the size of the square, without having to recompile. You're probably not ready to muck around with argv. You're probably not ready to read a line of text using fgets and convert it back to an integer using atoi. (You're probably not even ready to seriously contemplate the vast differences between the integer 5 and the string "5" at all.) So — during week 2 of your first C programming class — scanf seems like just the ticket.
That's the "one particular use case" I was talking about. And if you only used scanf to read small integers into simple C programs during the second week of your first C programming class, things wouldn't be so bad. (You'd still have problems forgetting the &, but that would be more or less manageable.)
The problem (though this is again my personal belief) is that it doesn't stop there. Virtually every instructor of beginning C classes teaches students to use scanf. Unfortunately, few or none of those instructors ever explicitly tell students that scanf is a stopgap, to be used temporarily during that second week, and to be emphatically graduated beyond in later weeks. And, even worse, many instructors go on to assign more advanced problems, involving scanf, for which it is absolutely not a good solution, such as trying to do robust or "user friendly" input validation.
scanf's only virtue is that it seems like a nice, simple way to get small integers and other simple input from the user into your early programs. But the problem — actually a big, shuddering pile of 17 separate problems — is that scanf turns out to be vastly complicated and full of exceptions and hard to use, precisely the opposite of what you'd want in order to make things easy for beginners. scanf is only useful for beginners, and it's almost perfectly useless for beginners. It has been described as being like square training wheels on a child's bicycle.
How do professional C developers handle this mess?
Quite simply: by not using scanf at all. For one thing, very few production C programs print prompts to a line-based screen and ask users to type something followed by Return. And for those programs that do work that way, professional C developers unhesitatingly use fgets or the like to read a full line of input as text, then use other techniques to break down the line to extract the necessary information.
In answer to your initial question, there's no good answer. One of the fundamental rules of scanf usage (a set of rules, by the way, that no instructor ever teaches) is that you should never try to mix scanf and getchar (or fgets) in the same program. If there were a good way to make your "Press [enter] to continue..." code work after having called scanf, we wouldn't need that rule.
If you do want to try to flush the extra newline, so that a later call to getchar might work, there are several questions here with a bunch of good answers:
scanf() leaves the newline character in the buffer
Using fflush(stdin)
How to properly flush stdin in fgets loop
There's one more unrelated point that ends up being pretty significant to your question. When C was invented, there was no such thing as a GUI with multiple windows. Therefore no C programmer ever had the problem of having their output disappear before they could read it. Therefore no C programmer ever felt the need to write printf("Press [enter] to continue..."); followed by getchar(). I believe (another personal belief) that it is egregiously bad behavior for any vendor of a GUI-based C compiler to rig things up so that the output disappears upon program exit. Persistent output windows ought to be the default, for the benefit of beginning C programmers, with some kind of non-default option to turn that behavior off for those who don't want it.
Is scanf broken? No it is not. It is an excellent input function when you want to parse free form input data where few errors are to be expected. Free form means here that new lines are not relevant exactly as when you read/write very long paragraphs on a normal screen. And few errors expected is common when you read from files.
The scanf family function has another nice point: you have the same syntax when reading from the standard input stream, a file stream or a character string. It can easily parse simple common types and provide a minimal return value to allow cautious programmers to know whether all or part of all the expected data could be decoded.
That being said, it has major drawbacks: first being a C function, it cannot directly control whether the programmer has passed types meeting the format specifications, and second, as beginners are not consistenly hit on their head when they forget to control its return value, it is really too easy to make fully broken programs using it.
But the rule is:
if input is expected to be line oriented, first use fgets to get lines and then sscanf testing return values of both
only if input is expect to be free form (irrelevant newlines), scanf should be used directly. But never without testing its return value except for trivial tests.
Another drawback is that beginners hope it to be clever. It can indeed parse simple input formats, but is only a poor man's parser: do not use it as a generic parser because that is not what it is intended for.
Provided those rules are observed, it is a nice tool consistent with most of C language and its standard library: a simple tool to do simple things. It is up to programmers or library implementers to build richer tools.
I have only be using C language for more than 30 years, and was never bitten by scanf (well I was when I was a beginner, but I now know that I was to blame). Simply I have just tried for decades to only use it for what it can do...
I am fully aware that this is due to some error overlooked by me while writing my text-based calculator project in C, but I have only started learning C less than a week ago, so please help me out!
Since the entire code is 119 lines, I'll just post the necessary snippet where the real issue lies: (There are no errors during compiling, so there is no error beyond these lines)
char choice[15];
printf("Type 'CALCULATE' or 'FACTORISE' or 'AVERAGE' to choose function :\n");
gets(choice);
if (choice == "CALCULATE")
The bug is that even after perfectly entering CALCULATE or FACTORISE or AVERAGE, I still get the error message that I programmed in case of invalid input (i.e, if none of these 3 inputs are entered). It SHOULD be going on to ask me the first number I wish to operate on, as written for the CALCULATE input.
The code runs fine, no errors in VS 2013, and so I'm sure its not a syntax error but rather something stupid I've done in these few lines.
If you use == you are comparing the addresses of 2 arrays, not the contents of the arrays.
Instead, you need to do:
if (strcmp(choice, "CALCULATE") == 0)
Two things to mention here:
Never use gets() it has serious security issues and is removed from the latest standard. Use fgets() instead.
To compare strings, you should use strcmp(), not ==.
The problem is you're trying to compare a string literal with a char array. C isn't found those things being the same, since the '==' comparison operator is not implemented in that way.
You have two options for performing that comparison :
1) Use the strcmp() function, from string.h library
2) Manually comparing the chars in your array, and the string literal
Definitely, the first option is the easiest and cleanest one.
I'm trying to make the 20 questions game using c. The following is the code excerpt of one of the functions.
int question_input(void)
{
char q[100];
int i=0;
printf("Enter the question or say if you want to guess\n");
scanf("%[^\n]",q);
i=check_if_guess(q);
if(i==0)
{
printf("Say yes or no\n");
scanf("%s",q);
}
return i;
}
I get a general protection fault when I execute and on debugging, I found that the problem is with the
scanf("%[^\n]",q)
statement.
If the same statement is changed to "%s", then, I get no segmentation fault. Functions like gets (general protection fault) and fgets(doesn't ask for input at all) also fail to take inputs.
The thing which is more curious is that when I execute these statements in a seperate file, without the rest of the code, they execute properly.
Even if I try "%99[^\r\n]", it shows the same.
Please help
Well, I found an answer to my question by myself. One of my previous functions in my code had
scanf("%d",&n)
It is a known fact that after we enter our input we press the enter key. This is taken as a '\n' by the compiler and is stored in the buffer. My next scanf statement( the one which I got error in)(scanf("%[^\n]",q) straight away took the '\n' from the buffer. Hence it could not take any input, since \n terminates input. The compiler I use is turbo C++. In some cases of empty strings, it reports an error. Hence I got the error message. To solve this problem, I had to use
getchar()
statement before the scanf("%[^\n]",q) statement, so that the '\n' is removed from the buffer and taken as an input for the getchar statement.
Here is an example. For small programs that's fine to use , but what if we are developing a real time project or Application . Need some suggestions
while (TRUE )
{
int temp =0 ;
printf ( "How many no's would you like to enter : " ) ;
temp = scanf ( "%d" , &n ) ;
if ( temp==1 )
break ;
else
{
printf ("Invalid input. Try again. \n" ) ;
fflush ( stdin ) ;
}
}
The trouble with any loops, be they while(TRUE) or while(condition), is their tendency to have a sneak infinite loop condition - like this one.
OP's code depends on 2 results of scanf("%d",...,: 1 and not 1.
If user enters "123", all is good. scanf() returns 1, loop exits, we all leave work and have a pint.
If user enters "abc", scanf() returns 0, code does a fflush(stdin) to empty the stdin. (This is really UB, but let us pretend it works.) Code loops, prompts again, our drinks get warm, but hopefully we will eventually enter digits.
But let us imagine the user closed stdin - maybe code had re-directed input and scanf() eventually returns EOF. Code loops, but fflush(stdin) does not re-open stdin, and scanf() again returns EOF - and again and again - true infinite loop - code will not pause for input and just says ""Invalid input. Try again." which translates into "dumb guy, dumb guy, dumb guy ...". Looks like the crew will start their brews without us.
Moral of the story: loop when code is working as intended (User entered good data). Watch out for loops when functions loops on the unexpected.
If you're asking about style, recommendations are going to be somewhat subjective.
If you're afraid that your loops may turn into true infinite loops when undesired, then you need to do something about that. For example:
redesign your code to be an explicit state machine with clearly documented and implemented conditions for when the state changes and when it remains the same
think through the various error conditions that may occur (and thus potentially cause hanging in a specific state indefinitely) and handle them the best you can, also think of those conditions that are fatal and can't be handled gracefully (do you crash and burn? do you log an error? do you show it on some dash board? do you eject the driver's seat with the driver? do you dial an emergency phone number if applicable? etc etc), incorporate that into the state machine
review the code with your peers (maybe even hire industry experts for this)
implement and use tests (unit/integration/scenario-based/scalability/stress/security/etc etc)
I have this code.
#include <stdio.h>
int main(void)
{
int dogs;
printf("How many dogs do you have?\n");
scanf("%d", &dogs);
printf("So you have %d dog(s)!\n", dogs);
return 0;
}
To my knowledge, when executing, the program will say 'How many dogs do you have' and I enter a number. Instead, I get a blank page, and I have to first enter a digit. Then I get
How many dogs do you have?
So you have 3 dog(s)! (if I input 3)
I am using Eclipse + MinGW, and its my first time using C, so I'm not sure what I have/had to set up.
I managed to solve this problem. The problem was that eclipse was first processing all the scan statements, and then processing all the print statements. This would be hard to solve if your program has more than one scan statement.
The fix is somewhat simple. Download the binary fix from the following link.
You then need to paste the starter.exe in the path where you have Eclipse installed.
In my case it was this eclipse\plugins\org.eclipse.cdt.core.win32.x86_64_5.2.0.201309180223\os\win32\x86_64
Yours may very a bit. Overwrite the existing starter.exe and it should work.
printf() buffers output. In general (in UNIX) stdlib is smart enough to flush stdout before reading stdin but it might not be the case in MingW. Consider using fflush() or outputting to stderr.