C语言缓冲区、输入输出、与阻塞式监听、非阻塞式监听

一、Windows中的非阻塞式监听实现

所谓键盘监听,就是用户按下某个键时系统做出相应的处理,本章讲到的输入输出函数也是键盘监听函数的一种,例如 getchar()、getche()、getch() 等。下面的代码演示了 getche() 函数的使用:

#include <stdio.h>
#include <conio.h>
int main(){
    char ch;
    int i = 0;
    
    //循环监听,直到按Esc键退出
    while(ch = getch()){
        if(ch == 27){
               break;
        }else{
            printf("Number: %d\n", ++i);
        }
    }
    return 0;
}

在 Windows 下的运行结果:
Number: 1  //按下任意键
Number: 2  //按下任意键
Number: 3  //按下任意键
Number: 4  //按下任意键
Number: 5  //按下Esc键退出

这段代码虽然达到了监听键盘的目的,但是每次都必须按下一个键才能执行 getch() 后面的代码,也就是说,getch() 后面的代码被阻塞了。
  阻塞式键盘监听用于用户输入时一般没有任何问题,用户输入完数据再执行后面的代码往往也符合逻辑。然而在很多小游戏中,阻塞式键盘监听会带来很大的麻烦,用户要不停按键游戏才能进行,这简直就是灾难,所以在小游戏中一般采用非阻塞式键盘监听:用户输入数据后程序可以捕获,用户不输入数据程序也可以继续执行。

在 Windows 系统中,conio.h头文件中的kbhit()函数就可以用来实现非阻塞式键盘监听。

conio.h 是 Windows 下特有的头文件,所以 kbhit() 也只适用于 Windows,不适用于 Linux 和 Mac OS。

用户每按下一个键,都会将对应的字符放到输入缓冲区中,kbhit() 函数会检测缓冲区中是否有数据,如果有的话就返回非 0 值,没有的话就返回 0 值。但是 kbhit() 不会读取数据,数据仍然留在缓冲区,所以一般情况下我们还要结合输入函数将缓冲区种的数据读出。请看下面的例子:

#include <stdio.h>
#include <windows.h>
#include <conio.h>
int main(){
    char ch;
    int i = 0;
//循环监听,直到按Esc键退出
    while(1){
        if(kbhit()){ //检测缓冲区中是否有数据
            ch = getch(); //将缓冲区中的数据以字符的形式读出
                if(ch == 27){
            break;
            }
        }
        printf("Number: %d\n", ++i);
        Sleep(1000); //暂停1秒
    }
    return 0;
}

运行结果:
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5  //按下Esc键

每次循环,kbhit() 会检测用户是否按下某个键(也就是检测缓冲区中是否有数据),没有的话继续执行后面的语句,有的话就通过 getch() 读取,并判断是否是 Esc,是的话就退出循环,否则继续循环。

C语言非阻塞式键盘监听_cbirdfly.的博客-CSDN博客

二、C语言输入输出缓冲区

【C】C语言输入输出缓冲区_Vincent's Blog的博客-CSDN博客

几个很“诡异”的例子

1、先来看一个小程序,分析一下运行结果

#include<stdio.h>
int main()
{
        printf("hello");
        int i = 0;
        for(;i<10;i++)
        {
                putchar('.');
                sleep(1);
        }
        return 0;
}

先来猜测一下程序的输出结果,首先,应该在屏幕上打印出hello,然后打印出一个“.”,然后每隔1秒钟,打印出一个“.”打印出10个小数点后,程序结束运行。看一下实际的运行结果。 
输入./a.out 
 
程序什么输出也没有,等待10s 
 
10s之后输出“hello……….” 
为什么会产生这么奇怪的结果,为什么putchar函数和printf函数会在sleep函数执行完了之后才得到执行?其实原因很简单,就是C语言的输入输出缓冲在作怪。

三、缓冲区(行缓冲与全缓冲)

一般情况下,由键盘输入的字符并没有直接送入程序,而是被存储在一个缓冲区当中。缓冲又分为两种,行缓冲和完全缓冲。对于完全缓冲来说,缓冲区满时被清空(内容被发送到指定的目的地)。这种缓冲通常出现在文件输入中。对于行缓冲来说,遇到一个换行符,则清空缓冲区,键盘输入是标准的行缓冲,因此,按下换行键的时候才会清空缓冲区。 
上面的程序当中

print("hello");
...
putchar('.');

将要输出到标准输出的字符存放在缓冲区当中,由于一直没有遇到换行符,因此一直不会输出到屏幕,等到程序结束后才输出到屏幕上。

四、第二个例子

我们在上面的例子当中加入一行

#include<stdio.h>
int main()
{
        printf("hello");
        fflush(stdout);//新添加的行,刷新输出缓冲区
        int i = 0;
        for(;i<10;i++)
        {
                putchar('.');
                sleep(1);
        }
        return 0;
}

fflush()函数的作用是刷新缓冲区,把缓冲区的内容输出到执行位置。
那么这个程序的运行结果应该是:先输出hello,然后等待10s输出10个小数点,实际运行证明确实是这样。
这里写图片描述

这里写图片描述

五、第三个例子

#include<stdio.h>
#include<unistd.h>
int main()
{
    fprintf(stderr,"hello");
    int i=0;
    for(;i<10;i++)
    {
        fprintf(stderr,".");
        sleep(1);
    }
    return 0;
}

这次我们

使用fprint函数将字符输出到标准错误输出上去,而不是标准输出。虽然stdout和stderr都是指向屏幕,但是两者还是有区别,stderr是立即回显,不会将字符送入缓冲区。因此,这个程序的输出结果应该是:先输出hello,再输出一个“.”然后每隔1s输出一个小数点,输出10个小数点后程序结束。

六、C语言中的输入输出流和缓冲区(重点)详解

C语言中的输入输出流和缓冲区(重点)详解_拥抱@的博客-CSDN博客_以缓冲的方式输出缓冲区的内容是什么意思

七、linux非阻塞键盘输入

linux非阻塞键盘输入_handsome_zcz的博客-CSDN博客

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值