我已经在这上面拔头发好几个小时了。基本上,我有一个程序要求用户输入他的密码(123),如果用户不输入任何东西5秒,那么程序将退出(游戏结束)。我一直在尝试使用time(空)和clock(),但仍然没有成功。有人能告诉我正确的方向吗?提前多谢!
这是我的代码:

#include <stdio.h>
#include <time.h>

 int main(){
   int password = 0;
   int num = 0;
   printf("%s\n", "Please enter your password");
   scanf("%d", &password);
   // Here I need to check if user didnt enter anything for 5 seconds,
   // and if he didnt enter anything then exit out of the program
   // I tried using time
   // time_t start = time(NULL);
   // time_t stop = time(NULL);
   //   if(((stop - start) * 1000) > 5000){
   //  printf("%s\n", "Game Over");
   //  break;
  //  }

   printf("%s\n", "Thank you for entering your password, now enter any number");
   scanf("%d", &num);
   return 0;
 }

最佳答案

您的主要挑战是scanf()-以及getchar()和类似的命令-正在阻塞。一个未知的时间间隔可能会在用户真正输入任何输入之前过去,而您的5秒可能已经到了那个阶段。
select()-监视超时的文件描述符
我认为最可行的选择之一是使用select()-它监视特定文件描述符集上的活动。具体来说,您需要监视stdin文件描述符上的活动。
下面的事情完成了一些接近你需要我相信的事情。

#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

int main(void) {
    char buf[16] = {'\0'};
    char *pass = buf;
    time_t time_update = 0, time_now = 0;
    struct timeval tm;
    int res = 0;
    struct termios term_attr, new_attr;
    fd_set rset;

    // Change terminal attributes (We don't want line-buffered mode.)
    tcgetattr(fileno(stdin), &term_attr);
    tcgetattr(fileno(stdin), &new_attr);
    new_attr.c_lflag &= ~(ICANON | ECHO);

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

    printf("Enter password: ");

    time_update = time(NULL);
    while (1) {
        tm.tv_sec = 0;
        tm.tv_usec = 50000;
        FD_ZERO(&rset);
        FD_SET(STDIN_FILENO, &rset);

        res = select(fileno(stdin) + 1, &rset, NULL, NULL, &tm);
        if (FD_ISSET(STDIN_FILENO, &rset)) {
            time_update = time(NULL);
            int c = getchar();
            if (c == '\n') {
                break;
            }
            *pass = c;
            pass++;
        }
        time_now = time(NULL);
        if (time_now - time_update >= 5) {
            puts("Timed out ...");
            break;
        }
    }

    pass = buf;

    printf("You entered: %s \n", pass);

    // Restore original terminal attributes
    tcsetattr(fileno(stdin), TCSANOW, &term_attr);

    return 0;
}

笔记:
select()的最后一个参数是一个struct timeval参数,它指定在指定的文件描述符上等待活动的时间。在这种情况下,我指定了50毫秒的超时。
终端需要置于字符缓冲模式,而不是行缓冲模式。(否则,每次出现新字符时都需要按回车键。)
操作系统支持
select()是POSIX规范的一部分,但我不知道它是否在Windows上实现。也许有人能澄清?
也。。。我不知道在Windows上设置终端属性是否也能按预期工作。(我只在Linux上测试过。)
我意识到这个解决方案可能比你希望的要长一点/复杂一点-但是我不知道一个更简单的方法。

关于c - 如何从程序退出前5秒开始计数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51957319/

10-12 16:15