预计阅读本页时间:-
许多计算机程序使用菜单作为用户界面的一部分。菜单使程序对用户而言更友好,但也给编程人员提出了一些问题。我们来看一下其中涉及的问题。
菜单为用户的响应提供了可选项。下面是一个假设的例子:
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
理想情况下,用户输入这些选项之一,程序将根据选项采取行动。作为一名编程人员,您希望让这一过程顺利进行。第一个目标是让程序在用户遵循指令时顺利运行。第二个目标是让程序在用户没有遵循指令时也能顺利工作。正如您所料到的,第二个目标较难实现,因为预见程序所有可能遇到的用户错误行为是非常困难的。
8.7.1 任务
我们来更具体地考虑菜单程序需要执行的任务。该程序需要获取用户响应,并且需要基于该响应选择一系列动作。而且,程序还应该提供一种方法让用户可以回到菜单以做更多的选择。C的switch语句是选择动作的一个很方便的工具,因为每个用户选择可对应于一个特定的case标签。可以使用while语句来提供对菜单的重复访问。可以使用伪代码按照下列方式描述该过程:
8.7.2 使执行更顺利
在您决定计划的实施方法时应该考虑到程序顺利执行的目标(处理正确输入时顺利执行和处理错误输入时顺利执行)。例如,您能做的一件事是让“获取选项”部分筛选掉不合适的响应,从而仅使正确的响应被传送到switch语句。这表明须为输入过程提供一个只返回正确响应的函数。将其与while循环、switch语句相结合会产生下列程序结构:
定义get_choice()函数使其只返回值‘a’、‘b’、‘c’和‘q’。使用该函数正如使用getchar()那样:获取一个值并将其与一个终止值进行比较;在本例中,该终止值为‘q’。我们令实际的菜单选项十分简单,以使您把精力集中在程序结构上;我们很快会讨论count()函数。default语句是方便调试的。如果get_choice()函数没能将其返回值限制为预期值,则default语句可以使您了解发生了一些可疑的事情。
get_choice()函数
下面的伪代码是这个函数的一个可能的设计:
下面是一个虽然简单但使用起来不太方便的实现:
问题在于使用缓冲输入时,函数会将回车键产生的每个换行符都作为一个错误的响应对待。要使程序界面更加顺畅,该函数应该跳过换行符。
要实现这一目标有多种方法。一种方法是用一个名为get_first()的新函数代替getchar(),该函数读取一行的第一个字符并将其余字符丢弃掉。此方法还具有一个优点,就是将由act组成的输入行看作是输入了一个简单的a,而不是将其作为由代表count的c所产生的一个有效的响应。记住这一目标,您就可以将输入函数重写为如下形式:
8.7.3 混合字符和数值输入
创建菜单提供了将字符输入与数值输入相混合会产生问题的另一个实例。例如,假设count()函数(选项c)如下所示:
如果您通过输入3进行响应,则scanf()将读取3并留下一个换行符,把它作为输入队列中的下一个字符。对get_choice()的下一次调用会导致get_first()返回此换行符,从而导致不希望的动作。
解决该问题的一种方法是重写get_first()使其返回下一个非空白字符,而不是简单地返回它遇到的下一个字符。我们将这种方法留给读者作为练习。第二种方法是由count()函数自己来负责处理换行符。这就是下面的示例所采用的方法:
此函数还使用了程序清单8.7中的get_int()函数;回忆一下,该函数检查有效输入并给用户重新尝试的机会。程序清单8.8显示了最终的菜单程序。
程序清单8.8 menuette.c程序
下面是一个运行示例
让菜单界面按照您所希望的那样顺利工作是很困难的,但在您开发了一种可行的方法后,您就可以在多种情况下重用该界面。
另外要注意的一点是在面临较复杂的任务时,每个函数如何将任务指派给其他函数,这样就可使程序更加模块化。