带有' char'的无限循环输入

时间:2017-10-06 22:39:02

标签: c data-structures binary-search-tree

我正在学习二叉搜索树。下面给出了执行基本BST操作的程序的主要功能。 option变量选择要对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;

当我将int数据作为'选项'的输入时,一切正常。但是,当我给出一个char输入时,程序进入无限循环并重复显示选项列表。

为什么会这样?

2 个答案:

答案 0 :(得分:1)

由于您在%d格式字符串中使用了scanf()格式说明符,

scanf("%d",&val);
仅当给出整数作为输入时,

才会成功分配给val。如果给出charscanf()(返回成功分配的数量)将返回此处0并将char保留在输入缓冲区中。

在循环的下一次迭代期间,此char仍然在输入缓冲区中,scanf()最终会尝试读取相同的内容并且不会分配给{{ 1}}再次。

这将继续,导致无限循环。

要解决此问题,请检查val返回的值。如果不是scanf(),请清除输入缓冲区,直到下一个1(换行符)为止

\n

这将从输入缓冲区中消耗旧数据直到int t; while( (t=getchar()) != `\n` );

然后,您可以使用continue语句跳过循环迭代的其余部分。

了解\n here

答案 1 :(得分:1)

  

为什么会这样?

这个问题的根源一直是scanf如何向代码指示错误代码(完全没有,因为代码会丢弃它们),以及scanf("%d", &val)预期会做什么遇到非小数输入;它会停止读取输入,可能会返回错误代码,但是您的代码会丢弃该代码并继续快速尝试删除值指示的节点(可能尚未读取),导致可能使用未初始化的变量稍后......

有些人把猜测推向极端,并认为使用 fflush(stdin) 解决这个问题是合适的(事实并非如此;不要做那...)。你还没有走那么,但我认为开始阅读你正在使用的函数的手册可能是一个好主意。 scanf手册为here。记下该URL,并意识到您可以通过替换函数的名称来查找其他标准函数(C99和POSIX标准)。

您的代码必须做的第一件事是检查返回值,您的手册将在 RETURN VALUES 部分中记录;与大多数标准库函数一样,scanf具有返回值,您的代码最有可能包含关键逻辑!从那里,您如何处理错误是您的业务。也许使用简单但用户不友好的东西可能是合适的,例如:

perror(scanf);
exit(EXIT_FAILURE);

您应尽可能寻求更简单的解决方案,以避免过于复杂的事情。如果您的输入不是直接来自用户,或者您只是想要原型,那么您应该使用上面的解决方案。如果有必要,您可以随时将exit(EXIT_FAILURE)更改为return EXIT_FAILURE;return 0;

如果您选择让程序保持运行,那么有多少用户输入会由于打字错误而被丢弃。到目前为止,最简单的选择是只读取一个字符(使用getchar();)...

您可以选择丢弃输入的,如下所示:scanf("%*s");*通知scanf读取并放弃输入,而不是阅读和分配。

这些选项都没有让我觉得特别方便用户。如果您要努力创建用户友好的界面,您可能需要选择以下选项之一。

使用*分配抑制修饰符,您还可以丢弃输入,如下所示:

scanf("%*[^\n]");
getchar();

丢弃换行符需要getchar();,我们希望在丢弃一行时将其丢弃。

使用输入的命令行参数,而不是使用stdin(或其他文件/流)。通过这种方式生成了一些令人惊讶的简单而多功能的菜单,例如编译器提供给您的菜单。然后,您的输入模式将更改为使用更友好的函数(例如sscanf),并将程序开发为不作为循环程序保持打开,而是作为即时程序,在必要时不时执行以更新记录或什么不是。

使用图形用户界面代替控制台。好吧,那个真的让'noggin'鞭子,呃?您可以使用一个上下文菜单,例如Windows中的文件/编辑/等菜单,或一个列表框(对触摸屏更友好)来提示您的用户进行选择。 / p>

我只想说,这看起来像是家庭作业,所以你可能没有选择设计更合适的用户界面......在这种情况下,我建议使用{ {1}}赋值抑制修饰符如上所述(第一个粗体部分)。