I am learning binary search tree. Given below is the main function of a program to perform basic BST operations. The option variable chooses which operation to perform for switch
int main()
{
struct node* tree=NULL;
struct node* ptr=NULL;
struct node* ptrm=NULL;
int val;
int option;
do
{
printf("\n1.Insert Node\n2.Preorder Traversal\n3.Postorder Traversal\n4.Inorder Traversal\n5.find_smallest_element\n6.find_largest_element\n7.Delete Element\n8.Total_nodes\n9.total_external_nodes\n10.total_internal_nodes\n11.Mirror image\n12.Exit\n");
printf("\nEnter option");
scanf("%d",&option);
switch(option)
{
case 1:
printf("\nEnter value to be inserted");
scanf("%d",&val);
tree=insert_element(&tree,val);
printf("\n%d Inserted\n",val);
break;
case 2:
preorder(&tree);
break;
case 3:
postorder(&tree);
break;
case 4:
inorder(&tree);
break;
case 5:
ptr=find_smallest_element(&tree);
printf("\nSmallest element:%d",ptr->data);
break;
case 6:
ptr=find_largest_element(&tree);
printf("\nLargest element:%d",ptr->data);
break;
case 7:
printf("\nEnter value of element to be deleted");
scanf("%d",&val);
tree=delete_node(&tree,val);
break;
case 8:
printf("\nTotal nodes%d",total_nodes(&tree));
break;
case 9:
printf("\nTotal External nodes%d",total_external_nodes(&tree));
break;
case 10:
printf("\nTotal Internal nodes%d",total_internal_nodes(&tree));
break;
case 11:
ptrm=mirror_image(&tree);
}
}while(option!=12);
return 0;
Everything works fine when i give int data as input for 'option'.However, when i give a char input the program goes into infinite loop and displays option list repeatedly.
Why does this happen?
Since you used %d format specifier in the scanf() format string,
scanf("%d",&val);
will successfully assign to val only if an integer was given as the input. If a char is given instead, scanf() (which returns the number of successful assignments) will return 0 here and will leave the char in the input buffer unconsumed.
During the next iteration of the loop, this char would still be in the input buffer and scanf() would end up trying to read the same thing and will won't assign to val once again.
This will go on and on resulting in an infinite loop.
To solve this, check the value returned by scanf(). If it is not 1, clear the input buffer till the next \n (newline) like
int t;
while( (t=getchar()) != `\n` );
This will consume the old data till a \n from the input buffer.
You could then use the continue statement to skip the rest of that iteration of the loop.
Read about getchar() here.
Why does this happen?
The roots of this issue stem all the way back to how scanf indicates error codes to your code (not at all, because your code discards them), and what scanf("%d", &val) is expected to do when non-decimal input is encountered; it stops reading input, possibly returning an error code, but your code discards that and continues on merrily trying to delete the node indicated by the value which may not have been read, leading to possible use of an uninitialised variable later...
Some people take the guessing to an extreme, and think it's appropriate to use fflush(stdin) to solve this (it isn't; don't do that...). You've not gone that far, but I think it might be a good idea to start reading the manuals of the functions you're using. The scanf manual is here. Make note of that URL, and realise that you can look up other standard functions (both C99 and POSIX standard) by substituting the name of the function.
The first thing your code must do is check that return value, which your manual will document in the RETURN VALUES section; as with most standard library functions, scanf has a return value which your code should most likely contain critical logic regarding! From there, how you handle errors is your business. Perhaps it might be appropriate to use something simple yet user-unfriendly, like:
perror(scanf);
exit(EXIT_FAILURE);
You should seek the simpler solutions where possible, to avoid overcomplicating things. If your input doesn't come directly from the user, or you just want to prototype, you should use the solution above. You can always change exit(EXIT_FAILURE) to return EXIT_FAILURE; and return 0; on success, if necessary later.
If you choose to keep your program running, how much of the user input gets discarded due to the typo is up to you. By far the simplest option is to just read a single character (using getchar();)...
You could choose to discard a word of input, like so: scanf("%*s");. The * informs scanf to read and discard the input, rather than reading and assigning.
Neither of those options strike me as being particularly user-friendly. If you're going to the effort of making a user-friendly interface, you'll probably want to choose one of the following options.
Using the * assignment-suppression modifier, you can also discard a line of input, like so:
scanf("%*[^\n]");
getchar();
The getchar(); is necessary to discard the newline character, which we expect to be discarded when a line is discarded.
Using the command line arguments for your input, rather than using stdin (or other files/streams). Some surprisingly simple yet versatile menus have been produced this way, such as the ones your compiler presents to you. Your mode of input then changes to using friendlier functions such as sscanf, and developing your program not as a looping program that remains open, but as an instant program which gets executed every now and then, when necessary, to update records or what-not.
Using the graphical user interface instead of the console. Well, that one really makes the ol' noggin' flog, eh? You could use... a context menu such as the File/Edit/etc menus in Windows, or a listbox (which would be more touch-screen friendly) to prompt your user for a selection.
Suffice to say, this looks like homework, so you probably don't have the choice to design a more appropriate user interface... In this case, I suggest using the * assignment-suppression modifier as per above (the first bolded section).
Related
So I have this piece of code which is written for reading the user input which is supposed to be between the numbers 1-9. In the code there is and int "choice" declared. But instead of directly scanning the user input using scanf("%d", choice); the programmer has used a char buffer and scanned the buffer instead and then used the atoi function to convert the char input to an integer. I'm confused why has it been done like that instead of directly doing it the easy way. My assumption is that the programmer has done this so that if the user enters a character instead of a number, the code doesn't malfunction. But if that's the case then how would the atoi convert an alphabet to an integer? Here's the code:
int readMenuChoice() {
while (1) {
char buffer[50];
size_t buffLen = 10;
int choice;
showMenu(); //another function that displays all options from 1 to 9
printf("Choose a menu option: ");
scanf("%[^\n]", buffer);
getchar();
choice = atoi(buffer);
if (choice > 0 && choice < 9) {
return choice;
}
printf("Invalid input\n\n");
}
}
We can only guess intention from the coder.
But a pretty likely reason is to make sure that the input stream is empty between each input. I personally do things like that too. But I would have done like this instead:
while (1) {
char buffer[50];
int choice;
showMenu();
printf("Choose a menu option: ");
if(!fgets(buffer, sizeof buffer, stdin)) {
/* Handle error */
}
if(sscanf(buffer, "%d", &choice) != 1) {
/* Handle error */
}
if (choice > 0 && choice < 9) {
return choice;
}
printf("Invalid input\n\n");
}
atoi is an unsafe function. If the argument cannot be parsed to a number, it invokes undefined behavior. And since x = atoi(s) is completely equivalent to sscanf(s, "%d", &x), there's no reason to use the unsafe function. sscanf returns the number of successful assignments, so it CAN be error checked.
The problem of reading user input safely, limiting the input to a certain set of "allowed" inputs, while cleanly disregarding "disallowed" inputs, can be a surprisingly tricky one.
Also surprising, perhaps, is how poor a function scanf is for performing this task, and how difficult it is to solve the problem completely using any algorithm built around scanf.
You asked why this code didn't "directly do it the easy way". By "the easy way" I assume you mean something like
scanf("%d", &choice);
The problem here is that, yes, it can be remarkably difficult to proceed correctly if the user types some non-numeric input.
There are two general avenues to take when trying to handle the possibility that the user types something wrong:
Continue to call scanf("%d") to read the input, but then, try to patch things up if scanf fails. (Obviously the first step here is to check scanf's return value.)
Read a line of input, as text, using something other than scanf. Then attempt to validate that line, and convert it to the desired form.
In my opinion, there is only one choice here, and it is #2. This answer will become far too long if I discuss all the reasons, but the bottom line is that approach #1 is futile. The scanf function has one virtue and one virtue only, and that is that a call like scanf("%d", &choice) is indeed very simple. But the error handling is almost useless. By the time you've built up a reasonable amount of error handling around it, the amount of work you'll have had to do is about three times as much as for approach #2, and you still won't have fully satisfactory results.
So most experienced C programmers will agree that #2 is the only viable approach in the long run. There's a central question advising on good ways of doing input using something other than scanf.
The problem with the code you've posted, IMO, is that it manages to combine the worst of both worlds. It does try to read a line of input as text, then process it later, but the way it reads that line of input is with... the dreaded scanf! And despite trying to be careful in several other ways, this code doesn't even check scanf's return value, so there are some classic problems (like premature EOF) that this code is still vulnerable to.
This code also contains a mysterious extra call to getchar, which is typical of scanf-using code, since stray newlines are almost always a problem.
This code also uses %[...], which is my least favorite scanf format. As I said, scanf's only virtue is simplicity, but a locution like "%[^\n]" is anything but simple. Yes, I know what it does, but IMO it completely defeats the purpose of using scanf for dirt-simple (if less than robust) user input.
But, yes, the primary intent of writing the code this way is probably "so that if the user enters a character instead of a number, the code doesn't malfunction". The code reads a line of text, as text, then attempts to convert the text to a number. You asked what the atoi function does with alphabetic input, and the answer is that (most of the time, anyway) it quietly returns 0. Since 0 isn't a valid input, this code will reject it, so in that sense it works.
To improve this function, the first thing to do would be to replace the calls to scanf and getchar with fgets. The next thing to do would be to replace atoi with strtol. And then it wouldn't be too bad.
I need a little help im sort of new to C programming. I'm having some trouble, for some reason the program won't read the line that im trying to take choice as input from the user which is causing me to have infinite loop neither the menu is printing.
Also stuff like this happen with me a lot of the time like when I copy my friends' code how it is it dosent run any loops even my teacher doesn't know why so if you can help in this too please do .
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main (){
int choice ,score=0;
char name [30];
puts("Welcome to our game , Have fun !\n ");
puts("Enter your name");
scanf("%c",name);
printf("1-Start new game\t2-show recorde\n3-Help \t4-Show score\n5-Reset score \t6-Quit game");
scanf("%d",choice);
while(choice!=6){
switch(choice){
case 1 :
break;
case 2 :
break;
case 3 :
break;
case 4 :
break;
default :
puts("\n invalid input ");
break;
}//end switch
}//end while loop
}//end main
Your usage of scanfis wrong.
scanf("%c",name);
Format specifier %c is not suitable to read a string. It only reads 1 single character.
The other members of name array will be untouched and as local variables are not initialized to 0, that is not a valid nul-terminated string.
As soon as you try to print name or perform any string operations with it, this will result in undefined behaviour.
As a result, whatever you type after first character, stays in input buffer and is fetched during next read attempt.
To fix this, use format specifier %s.
When you now try to read the choice as an integer
scanf("%d",choice);
the input buffer contains remaining letters and also \n from first call, which does not match any number.
After the call choice is not modified and still contains its indetermined content (You don't initialize it)
You should always check return value of scanf to see how many parameters were read. It would show you that it didn't find any value.
Besides that, you also provide invalid parameter. You must provide the address of an integer. This is undefined behaviour.
This is the reason why you always enable warnings in your compiler. It should warn you about this error.
To fix this, use
int ret = scanf(" %d", &choice);
if (ret != 1)
// error handling, try again, etc.
Note the space in the format string to skip whitespace including \n.
Finally, you enter your loop with a "random" value in choice and never try to read again. How would you expect to leave the loop without this?
If your teacher really doesn't know why, the missing indentation might be a reason.
This is the only block of code where scanf doesn't seem to pick up the entered values correctly.
It always works as designed the very first time it executes the code. When it asks the second time (after executing newGame once) no matter what you type it always takes the value 1 and then on the second iteration of the infinite loop it works correctly. Using pointers didn't help like I thought it would.
Edit: updated the code for new readers, this doesn't work either
void newGame(void){
int option;
puts("Would you like to play a new game? 1: Yes 2: Return to the main menu");
while (1) {
scanf("%d", &option);
switch(option) {
case 1:
newGame();
break;
case 2:
return;
default:
printf("Invalid input %d!\n", option);
break;
}
}
If I understand the observed misbehavior correctly, it manifests like this (for example):
The function emits the prompt
You type "1" and hit [enter]
The function emits the prompt
You type "2" and hit [enter]
Nothing seems to happen
You type "2" and hit [enter]
Control passes to the next statement after the initial call to newGame()
At least, that's an observable behavior of the function presented. Interpreting that to describe the problem assumes that the "Nothing seems to happen" at (5) is what the question describes as "no matter what you type it always takes the value 1". I find it hard to reconcile those, but I assume that the code presented actually manifests the problem, so I have to somehow connect the claim to the actual behavior.
That particular behavior (having to type "2" twice or more to return to the main menu) arises from the recursive implementation of the function. It goes like this:
Control enters the function on the initial call to it.
The function prints the prompt.
The function enters the while loop, where:
it scans the user's choice (and will run into trouble either then or later if the user has entered anything non-numeric);
the user having entered "1", the function calls itself recursively, in which new execution it
prints the prompt,
enters the while loop,
scans the user's input ("2" this time),
returns from the recursive call.
(back in the top-level newGame() execution) the function reaches the bottom of the while loop and loops back to scan a new input (another "2" in the example session).
The function returns from the top-level execution of newGame().
The simplest way to revise the code so that the user only needs to select option "2" once would be to add a return statement immediately after the recursive call to newGame(). The recursive call will not return until the user has chosen option "2", so there is no need to loop back for more input in that case.
But the best solution would be to structure the menu system to be non-recursive. In real-world programs, recursion is almost never the right answer. Even in this case, the recursive approach puts a (system dependent) limit on how many games can be played in a row before the program overflows its stack. That might be in the hundreds or perhaps even thousands, but there doesn't need to be any limit at all.
You need to check the return value of scanf to ensure that the input value was actually a number -- if it is not, scanf will return 0 and not read anything. It also might return EOF if an end-of-file is reached. So you want something like:
if (scanf("%d", &option) != 1) {
if (feof(stdin)) {
printf("Unexpected end of file");
exit(0); }
printf("Unexpected character %c in input", getchar());
continue; }
in your while loop to read your number.
I'm writing a program in C that displays a menu that asks the user to make a decision.
I want to bring up the menu multiple times in the program so I put it into function.
Each choice has a number associated with it:
(1) Add
(2) Subtract
The function displays the menu and then then I scanf the int response to a local variable and then return the variable (I of course declare the variable at the beginning of the function).
int function ()
{
int choice;
// *insert print menu code here*
scanf(" %i", &choice);
return choice;
}
Can I make this shorter by somehow doing a: return scanf(" %i", stdin);
I'm not sure if stdin would be the right choice, but that's what searching tells me.
Sure you can:
int scanInt(void) {
int result;
return (scanf(" %i", &result), result);
}
But is it useful? Probably not.
Note that this might look like undefined behaviour at first glance, because you're writing and reading from the same memory location in one expression. But it is not, as the comma operator introduces a sequence point.
You can't do this with scanf: you'd be returning the return value of scanf, which only indicates the number of items successfully read. If you need to return choice then you'll need to call scanf to fill choice and return it in two separate steps.
Another point here is that you should check the return value of scanf: it will fail if it's unable to convert the input. In your code, scanf will fail if the input is not an integer.
Furthermore, scanf reads from stdin - standard input - by default, you can't pass that as an argument unless you're using fscanf, which otherwise behaves in the same way.
Have you looked at using fgets for your input? It does return the next input line, which would allow you to do the read in the return statement since fgets returns the next line of input as a string. But you'd still need to parse the input yourself, which should probably happen within your function. In any case, fgets is typically a better choice for user input because it separates reading the input from parsing it, and avoids problems when using scanf due to input that doesn't match your format string.
You can, sort of -- but don't.
scanf returns the number of items scanned. You can't make it return the value of one of the scanned items.
return scanf(" %i", &choice), choice;
This uses the comma operator (not to be confused with the comma delimiter between function arguments), which evaluates both operands and yields the result of the right operand.
But there is no good reason to do this. There is no great virtue in making your source code more compact like this. The multi-line form is clearer, and it's easier to modify by adding error handling (what happens if the user enters something other than a number?)
Or you could write your own function that calls scanf and returns the value you want, but that still doesn't address the issue of error handling.
And if your goal is simply to put them on one line:
scanf(" %i", &choice); return choice;
But again, this is not an improvement.
No, you can't with scanf. The function needs a memory location to store the result, and doesn't return it. So you just have to live with the extra code.
when i'm trying to use scanf and gets, i'm having trouble, i need to put gets twice, if i put it once my program is terminated, it's homework and i have to use those functions in those places.
the code :
int main()
{
int i=0,operation=0;
char str[100];
printMenu();
scanf("%d",&operation);
switch (operation)
{
case 1:
printf("Please, enter your sentence >");
gets(str);
gets(str);
if (checkChars(str))
inputSent(str);
else
printf("ERROR: Incorrect data, try again.");
break;
}
return 0;
}
So, we have a stdin stream of data. This is the input that you write at the terminal.
When you call scanf, it only reads the decimal number that you wrote. It does not read the newline after it. Therefore, you need two calls to gets because the first call only sees '\n' while the second sees your actual data.
To fix this, I'd recommend that you use gets to read the full line when you get the operation, and then use sscanf to get the operation.
For example:
printMenu();
gets(str)
sscanf(str, "%d", &operation);
switch (operation) {
What's happening is after your first scanf() is that there's still data lingering in the input buffer (any form of whitespace that delimits things, usually a return) and when you call the next gets() it returns immediately because it read the "enter" you hit after typing in a number.
In order to solve this, you'll need to flush the input buffer. This is good practice especially when switching between reading individual character words and sentences. Here's a small snippet I found from another thread that may help you (this would go after your scanf()):
while (getchar() != EOF);
What it does is continually read characters out of the input buffer until none are left. This may not be the best solutions for all situations but it should be enough to help you through this assignment.