• 18.28 getchar()函数与缓冲区问题


      一个关于使用链表增加删除人名的小程序,在使用getchar()函数,得到输入的菜单选项时,出现了问题,现记录如下:

    【菜单部分代码如下:】

    #include <stdio.h>
    
    int main(int argc, char * argv [ ])
    {
          char cOpt;
          while(1)
          {                  
                 print();
                 cOpt = getchar();
    
                 switch(cOpt) /* switch里的变量只能是整型或字符型 */
                 {
                        case 'l':
                        {
                               list_name();
                               break;                        
                        }
                        case 'a':
                        {
                               add_name();
                               break;
                        }
                        case 'd':
                        {
                               del_name();
                               break;
                        }
                        case 'x':
                        {
                               return 0;
                               break;
                        }
                        default:
    
                        {
                               break;
                        }
                 }
          }
          return 0;
    }

    【错误现象:】

     

      输入菜单选项时,多输出一次菜单。

    【解决问题过程:】

    1.我在每一个语句后增加的打印语句。

      printf("1. test ");

      发现每次都会多执行一次default语句。

    2.查看cOpt输出结果

    cOpt = getchar();
    printf("1. cOpt = 0x%x
    ", cOpt);
    switch(cOpt)
    {
          …
    }

     

      发现cOpt的值有0xa,这是换行符的ASCII码。

    通过对缓冲区的研究发现以下结论:

      我的输入被放入了输入缓冲区,这里的回车操作,既有确定作用又是字符,所以回车' '它也跟着进了缓冲区,这个时候getchar()会从stdin流缓冲区中读取刚才的输入,一次只读一个字符,所以字符‘l’就被拿出来了,赋值给了cOpt,然后使用switch选择菜单项执行,这是第1次显示菜单栏。字符‘l’被取出的同时,也被缓冲区释放了,而此时缓冲区还有回车(' '。所以在while(1)第2次循环时,根本不需要输入就读出了回车(' '字符,赋值给cOpt,在switch里判断后回车(' '字符属于未定义的,必然要执行default分支。此时,回车字符也被缓冲区释放了,所以再次调用getchar时,程序就等着用户按键。

      所以,getchar的调用就是直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才等待用户按键。

    【解决方案:】

      【法1:】知道原因后,我在switch前的cOpt = getchar();后增加下列语句

    if (cOpt == '
    ')
    {
        cOpt = getchar();
    }

      【法2:】

    #include <stdio.h>
    
    int main(int argc, char * argv [ ])
    {
          char cOpt;
          while(1)
          {                  
          print();
        /* 解决方案2 */
    do{ cOpt = getchar(); }whiel((cOpt != 'l') && (cOpt != 'a') && (cOpt != 'd') && (cOpt != 'x')) if (cOpr == 'l') { list_name(); } else if (cOpr == 'a') { ShowPrePage(); } else if (cOpr == 'd') { del_name(); } else if (cOpr == 'x') { return 0; } } return 0; }

      目的是为了释放回车字符,使程序跳过对回车字符的操作。

     补充:

    缓冲区分为三种类型:全缓冲、行缓冲和不带缓冲。

    1、全缓冲

      在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

    2、行缓冲

      在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。

    3、不带缓冲

      也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

    缓冲区的刷新

    缓冲区会在以下三种情况下被刷新:

      1、缓冲区满

      2、执行flush刷新缓冲区的语句

      3、程序正常结束。


  • 相关阅读:
    day49-线程-事件
    day48-线程-信号量
    180-spring框架开启事务的两种方式
    094-SSM框架和控制层,业务层、持久层是什么关系?
    179-当创建FileInputStream会发生什么呢?
    178-链接查询association
    177-properties文件的中文注释是会出现乱码的?
    176-@Mapper注解是什么?
    092-linux都是怎么安装文件的?
    178-什么是dns解析呢?
  • 原文地址:https://www.cnblogs.com/baixu/p/11212216.html
Copyright © 2020-2023  润新知