文档章节

C Primer Plus 第8章 字符输入/输出和输入确认 8.7 菜单浏览

idreamo
 idreamo
发布于 2016/07/02 06:38
字数 1542
阅读 360
收藏 8

8.7.1  任务

我们来更具体的考虑菜单程序需要执行的任务。该程序需要获取用户的响应,并且需要基于该响应选择一系列的动作。而且,程序还应该提供一种方法让用户可以回到菜单以做更多的选择。C的switch语句是筛选动作的一个很方便的工具,因为每个用户选择可对应于一个特定的case标签。可以使用while语句来提供对菜单的重复访问。可以使用伪代码按照下列方式描述该过程:

get choice

while choice is not 'q'

        switch to desired chice and execute it 

        get next choice

8.7.2  使执行更顺利

程序顺利执行的目标:处理正确输入时顺利执行和处理错误输入时顺利执行。

例如,您能做的一件事是让“获取选项”部分筛选掉不合适的响应,从而仅使正确的响应被传送到switch语句。这表明须为输入过程提供一个只返回正确响应的函数。将其与while循环、switch语句相结合会产生下列的程序结构:
 

#include <stdio.h>
char get_choice (void);
void count(void);
int main(void)
{
    int choice ;
    while((choice=get_choice())!='q')
    {
        switch(choice)
        {
          case 'a' : printf("Buy low ,sell high.\n");
                     break;
          case 'b' : putchar('\a');  /*ANSI*/
                     break;
          case 'c' : count();
                     break;
          default : printf("program error!\n");
                    break;
        }
    }
    return 0;
}

定义get_choice()函数使其只返回值‘a' 'b' 'c'和'q'。我们令实际的菜单选项十分简单,以使您把精力集中在程序结构上;很快我们会讨论count()函数。default语句是方便调试的。如果get_choice函数没能将其返回值限制为预期值,则default语句可以使您了解发生了一些可疑的事情。

get_choice()函数

下面的伪代码是这个函数的一个可能的设计:

show choice

get response

while response is not acceptable

        prompt for more response

        get response

下面是一个虽然简单但使用起来不太方便的实现:
 

char get_choice (void)
{
    int ch;

    printf("Enter the letter of your choice:\n");
    printf("a.advice b.bell \n");
    printf("c.count  d.quit\n");
    ch=getchar();
    while ((ch<'a' || ch>'c') && ch !='q')
    {
        printf("Please respond with a,b,c or q.\n");
        ch=getchar();
    }
    return ch;
}

问题在于,使用缓冲输入时,函数会将回车键产生的每个换行符都作为一个错误的响应对待。要使程序界面更加顺畅,该函数应该跳过换行符。

要实现这一目标为多种方法。一种方法是用一个名为get_first()的新函数代替getchar();该函数读取一行的第一个字符并将其余字符丢弃掉。此方法还有一个优点,就是将由act组成的输入行看作是输入了一个简单的a,而不是将其作为由代表count的c所产生的一个有效的响应。记住这一目标,您就可以将输入函数重写为如下的形式:

char get_choice (void)
{
    int ch;

    printf("Enter the letter of your choice:\n");
    printf("a.advice b.bell \n");
    printf("c.count  d.quit\n");
    ch=get_first();  /*get_first()函数*/
    while ((ch<'a' || ch>'c') && ch !='q')
    {
        printf("Please respond with a,b,c or q.\n");
        ch=get_first();  /*get_first()函数*/
    }
    return ch;
}

char get_first(void)
{
    int ch;

    ch=getchar();  /*读取下一个字符*/
    while(getchar()!='\n')
       continue;  /*跳过本行的剩余部分*/
    return ch;
}

8.7.3 混合字符和数字输入

创建菜单提供了将字符输入与数值输入相混合会产生问题的另一个实例。例如,假设count()函数(选项C)如下所示:

void count (void)
{
    int n,i;

    printf("Count how far?Enter an integer: \n");
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        printf("%d\n",i);
}

如果您通过输入3进行响应,则scanf()将读取3并留下一个换行符,把它作为输入队列中的下一个字符。对get_choice()的下一次调用会导致get_first()返回此换行符,从而导致不希望的动作。

解决该问题的一种方法是重写get_first()使其返回下一个非空白字符,而不是简单的返回它遇到的下一个字符 。第二种方法是由count()函数自己来负责处理换行符

void count(void)
{
    int n,i;
    
    printf("Count how far?Enter an integer: \n");
    n=get_int();
    for(i=1;i<=n;i++)
        printf("%d",i);
    while(getchar()!='\n')
        continue;
}

此函数使用了程序清单8.7中的get_int()函数;回忆一下,该函数检查有效输入并给用户重新尝试的机会。

程序清单8.8 显示了最终的菜单程序

/*menuette.c--菜单技术*/
#include <stdio.h>
char get_choice (void);
char get_first (void);
int get_int (void);
void count (void);
int main (void)
{
    int choice;
    void count (void);

    while ((choice=get_choice())!='q')
    {
        switch (choice)
        {
            case 'a':printf("Buy low ,sell high.\n");
                     break;
            case 'b':putchar('\a');
                     break;
            case 'c':count();
                     break;
            default:printf("Program error!\n");
                    break;
        }
    }
    printf("Bye.\n");
    return 0;
}
void count(void)
{
    int n,i;
    printf("Count how far?Enter an integer: \n");
    n=get_int();
    for (i=1;i<=n;i++)
        printf("%d\n",i);
    while(getchar()!='\n')
        continue;
}

char get_choice(void)
{
    int ch;

    printf("Enter the letter of your choice:\n");
    printf("a.advice        b.bell\n");
    printf("c.count         q.quit\n");
    ch = get_first ();
    while((ch<'a' || ch>'c') && ch!='q')
    {
        printf("Please respond with a,b,c, or q.\n");
        ch=get_first();
    }
    return ch;
}

char get_first(void)
{
    int ch;

    ch=getchar();
    while(getchar()!='\n')
        continue;
    return ch;
}

int get_int(void)
{
    int input;
    char ch;

    while(scanf("%d",&input)!=1)
    {
        while((ch=getchar())!='\n')
            putchar(ch);    //剔除错误的输入
        printf(" is not an integer.\nPlease enter an ");
        printf("integer value,such as 25,-178,or 3: ");
    }
    return input;
}

让菜单界面按照您所希望的那样顺利工作是很难的,但在你开发了一种可行的方法后,您就可以在多种情况下重用该界面。

另外要注意的一点是在面临较复杂的任务时,每个函数如何将任务指派给其他函数,这样就可以使程序更加模块化。

 

© 著作权归作者所有

idreamo
粉丝 18
博文 139
码字总数 224743
作品 0
青岛
产品经理
私信 提问
加载中
C Primer Plus 第8章 字符输入/输出和输入确认 8.6 输入确认

程序清单8.7 使用两个函数来向一个算术函数传送整数,该函数计算特定范围内所有整数的平方和。程序限制这个特定范围的上界不应该超过1000,下界不应该小于-1000。 8.6.1 分析程序 首先集中讨...

idreamo
2016/06/30
54
0
C Primer Plus(5版)第8章编程题1_重定向实现

小伙伴们,对C语言编程有疑问的,可以加微信交流:poo_poo或者扫描我的头像,验证时请注明是“知友” 一、题目描述 本题是第8章编程题的第一道题,题目如下: 二、题目及思路分析 从题述来看...

石家的鱼
2017/07/11
0
0
C Primer Plus 第8章 字符输入/输出和输入确认 8.3 重定向和文件

输入和输出涉及到函数、数据和设备。例如,考虑echo_eof.c程序。该程序使用了输入函数getchar()、输入设备(我们已经假设)是键盘,输入数据流由单独的字符组成。假设您希望保持相同的输入函...

idreamo
2016/06/28
174
0
C Primer Plus 第8章 字符输入/输出和输入确认 8.11 编程练习答案

1、设计一个程序,统计从输入到文件结尾为止的字符数。 2、编写一个程序,把输入作为字符流读取,直到遇到EOF。令该程序打印每个输入字符及其ASCII编码的十进制值。注意在ASCII序列中空格字符...

idreamo
2016/07/05
383
0
C Primer Plus 第11章 11.13 编程练习答案

1、设计并测试一个函数,可以从输入读取n个字符(包括空格、制表符和换行符),把结果存储在一个数组中,这个数组的地址通过参数来传递。 2、修改并测试练习1中的函数,使得可以在n个字符后,...

idreamo
2016/09/22
721
0

没有更多内容

加载失败,请刷新页面

加载更多

cleanLastUpdated.bat

@echo offrem create by AnXiaole rem 这里写你的仓库路径set REPOSITORY_PATH=C:\Users\AnXiaole\.m2\repositoryrem 正在搜索...for /f "delims=" %%i in ('dir /b /s "%REPO......

安小乐
16分钟前
3
0
操作放大器的用法是什么?

  有区别   1、单级放大的倍数比较有限,一般在100倍以下。放大倍数很大的话,负反馈就比较浅,对于放大倍数的稳定性不利。假如需要放大倍数更高,就不得不动用多级放大电路了。单级放大...

仙溪
19分钟前
2
0
c++ 上传文件 curl

bool uploadFile(std::string url, std::string file, std::string auth) { boost::filesystem::path p(file); CURL *curl; CURLcode res; struct curl_httppost *for......

青黑
25分钟前
2
0
冒泡与插入排序的代码实现

// 冒泡排序,a 表示数组,n 表示数组大小public void bubbleSort(int[] a, int n) { if (n <= 1) return; for (int i = 0; i < n; ++i) { // 提前退出冒泡循环的标志位 ...

无名氏的程序员
27分钟前
3
0
centos7.6 +mhvtl1.6安装

以前的mhvtl都是在centos6.x,5.x上安装的mhvtl以前版本为1.4,现在最新的1.6出来,可以安装在centos7.6上,下面是安装过程: 1.安装基础包 centos7.6只要能上外网,默认是配置了yun源的,这些...

突突突酱
29分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部