你如何编写一个C程序来通过按键递增一个数字并每秒自动递减一次?

Rit*_*ika 13 c windows user-input

我正在尝试编写一个程序,其中一个数字从0开始,但当你按任意键时,它会增加1.如果没有按任何一个,它会继续每秒减少1,直到它达到0.每个增量或递减显示在控制台窗口中.

我的方法的问题是,在我按下一个键之前没有任何反应(也就是说,它检查是否有任何按下getch()).如何检查没有按下任何内容?当然,!getch()不起作用,因为要工作,它仍然需要检查按键,这会使目的本身无效.

操作系统:Windows 10企业版,IDE:代码::块

void main()
{
    int i, counter = 0;
    for (i = 0; i < 1000; i++)
    {
        delay(1000);
        // if a key is pressed, increment it
        if (getch())
        {
            counter += 1;
            printf("\n%d", counter);
        }
        while (counter >= 1)
        {
            if (getch())
            {
                break;
            }
            else
            {
                delay(1000);
                counter--;
                printf("\n%d", counter);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*ins 11

以下简短程序既不需要ncurses也不需要线程.但是,它确实需要更改终端属性 - 使用tcsetattr().这适用于Linux和类Unix系统,但不适用于Windows - 不包括termios.h头文件.(如果您对该主题感兴趣,也许可以看这篇文章.)

#include <stdio.h>
#include <string.h>
#include <termios.h>

int main(int argc, char *argv[]) {
    struct termios orig_attr, new_attr;
    int c = '\0';
    // or int n = atoi(argv[1]);
    int n = 5;

    tcgetattr(fileno(stdin), &orig_attr);
    memcpy(&new_attr, &orig_attr, sizeof(new_attr));
    new_attr.c_lflag &= ~(ICANON | ECHO);
    new_attr.c_cc[VMIN] = 0;
    // Wait up to 10 deciseconds (i.e. 1 second)
    new_attr.c_cc[VTIME] = 10; 
    tcsetattr(fileno(stdin), TCSANOW, &new_attr);

    printf("Starting with n = %d\n", n);
    do {
        c = getchar();
        if (c != EOF) {
            n++;
            printf("Key pressed!\n");
            printf("n++ => %d\n", n);
        } else {
            n--;
            printf("n-- => %d\n", n);
            if (n == 0) {
                printf("Exiting ...\n");
                break;
            }
            if (feof(stdin)) {
                //puts("\t(clearing terminal error)");
                clearerr(stdin);
            }
        }
    } while (c != 'q');

    tcsetattr(fileno(stdin), TCSANOW, &orig_attr);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

关键点是

new_attr.c_lflag &= ~(ICANON | ECHO);
Run Code Online (Sandbox Code Playgroud)

使终端退出规范模式(并禁用字符'echo'),

new_attr.c_cc[VMIN] = 0;
Run Code Online (Sandbox Code Playgroud)

将它置于轮询(而不是"阻塞")模式,和

new_attr.c_cc[VTIME] = 10;
Run Code Online (Sandbox Code Playgroud)

指示程序等待直到输入10个十分.

更新(2019-01-13)

  • 添加clearerr(stdin)清除(在某些平台EOFstdin似乎是必要的)


mat*_*att 2

这是一个在 Linux 上运行的 pthread 示例。这个概念是好的,但是可能有现有的循环/库。

#include <stdio.h>
#include<pthread.h>


void *timer(void* arg){
    int* counter = (int*)arg;
    while(*counter > 0){
        int a = *counter;
        printf("counter: %d \n", a);
        *counter = a - 1;
        sleep(1);
    }
}

int main(int arg_c, char** args){
    int i = 100;
    pthread_t loop;

    pthread_create(&loop, NULL, timer, &i);

    while(i>0){
        i++;
        getchar();
        printf("inc counter: %d \n", i);
    }
    printf("%d after\n", i);

    pthread_join(loop, NULL);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这将启动第二个线程,其中有倒计时。这会每秒减少计数器一次。在主线程上它有一个带有 getchar 的循环。他们都修改i.