You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言控制台猜词游戏:getchar()等待回车时如何实时更新剩余时间?

Solution for Real-Time Countdown While Waiting for Enter in C Console Game

Hey there! Let's fix that real-time countdown issue in your word guessing game. The core problem here is that getchar() is a blocking function—it stops your program dead in its tracks until the user presses a key, so your remaining time can't update until then. Here are two practical ways to handle this:

Approach 1: Use select() to Listen for Input and Time Simultaneously

The select() function lets you monitor file descriptors (like standard input) for activity, with a timeout. This way, you can check for user input every second, and update the countdown if no input is received.

Here's how to modify your code:

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

// Assume these are defined in your code:
// char *parole[];
// int n;
// int indovinate = 0;
// int secLeft = 60;

int main() {
    // Initialize random seed for proper word selection
    srand(time(NULL));
    char parola[256]; // Adjust size based on your longest word
    struct timeval tv;
    fd_set readfds;

    while (secLeft > 0) {
        system("clear");
        // Pick a random word
        snprintf(parola, sizeof(parola), "%s", parole[rand() % n]);
        // Print game state immediately
        printf("\n\n[%d]\t\t%s\t\t%d seconds left", indovinate, parola, secLeft);
        fflush(stdout); // Ensure output isn't buffered

        // Set up select to wait 1 second for input
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
        tv.tv_sec = 1;
        tv.tv_usec = 0;

        int result = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);

        if (result > 0) {
            // User pressed a key—clear the input buffer until Enter
            char c;
            while ((c = getchar()) != '\n' && c != EOF);
            // Increment correct guess count
            indovinate++;
        } else if (result == 0) {
            // 1 second passed without input—decrement remaining time
            secLeft--;
        } else {
            // Handle select() error
            perror("select failed");
            break;
        }
    }

    // Game over screen
    system("clear");
    printf("\n\nTime's up! You guessed %d words correctly.\n", indovinate);
    return 0;
}

Key Details:

  • select() checks if input is ready on standard input. If not, it waits the full 1-second timeout before continuing, letting us update the countdown.
  • fflush(stdout) ensures the game state prints right away—without this, buffered output might not show until the program unblocks.
  • We read all characters until Enter to clear the input buffer, so leftover keystrokes don't mess up the next round.

Approach 2: Use Signals for Periodic Updates

Another option is to use a SIGALRM signal that triggers every second to update the countdown. You'll need to handle interruptions to getchar() caused by the signal.

Here's a working implementation:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

int secLeft = 60;
int indovinate = 0;
char *parole[] = {"apple", "banana", "cherry"}; // Example word list
int n = 3;
char current_word[256]; // Track current word for signal handler

void update_countdown(int sig) {
    secLeft--;
    // Refresh game display
    system("clear");
    printf("\n\n[%d]\t\t%s\t\t%d seconds left", indovinate, current_word, secLeft);
    fflush(stdout);
    // Re-arm the alarm for the next second
    alarm(1);
}

int main() {
    srand(time(NULL));
    struct sigaction sa;

    // Set up signal handler for SIGALRM
    sa.sa_handler = update_countdown;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGALRM, &sa, NULL);

    // Start the periodic alarm
    alarm(1);

    while (secLeft > 0) {
        system("clear");
        // Pick and store current word
        snprintf(current_word, sizeof(current_word), "%s", parole[rand() % n]);
        printf("\n\n[%d]\t\t%s\t\t%d seconds left", indovinate, current_word, secLeft);
        fflush(stdout);

        // Handle input—retry if interrupted by the alarm signal
        char c;
        while ((c = getchar()) != '\n' && c != EOF) {
            if (errno == EINTR) {
                // Retry the read if it was interrupted by SIGALRM
                continue;
            }
        }

        if (secLeft > 0) {
            indovinate++;
        }
    }

    system("clear");
    printf("\n\nTime's up! You guessed %d words correctly.\n", indovinate);
    return 0;
}

Key Details:

  • The SIGALRM signal fires every second, triggering update_countdown() to decrement time and refresh the display.
  • When getchar() is interrupted by the signal, it returns -1 and sets errno to EINTR—we check for this and retry the input read.
  • We store the current word in a global variable so the signal handler can display it consistently.

Either approach will let you update the remaining time in real-time while waiting for the user to press Enter. The select() method is generally more portable and avoids signal-handling pitfalls, making it a solid first choice.

内容的提问来源于stack exchange,提问作者Tom Riddle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:26:01