1

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?

zahlen
  • 73
  • 2
  • 11

2 Answers2

2

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.

J...S
  • 5,079
  • 1
  • 20
  • 35
1

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).

autistic
  • 1
  • 3
  • 35
  • 80