我正在学习二叉搜索树。下面给出了执行基本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输入时,程序进入无限循环并重复显示选项列表。
为什么会这样?
答案 0 :(得分:1)
由于您在%d
格式字符串中使用了scanf()
格式说明符,
scanf("%d",&val);
仅当给出整数作为输入时,才会成功分配给val
。如果给出char
,scanf()
(返回成功分配的数量)将返回此处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}}赋值抑制修饰符如上所述(第一个粗体部分)。