尝试编写 fgets 函数的一个新版本 tfgets——tfgets 函数的输入与 fgets 函数一致。 (1) tfgets 函数可设定一个超时时限,比如 10 秒,即用户如果不在 10 秒内键入一个正确的输入行,则 tfgets 返回一个警告提示信息; 否则 tfgets 返回一个指针,该指针指向用户键入的输入行; (2) 用户键入的信息需要与预设信息一致,即视为正确输入,可以 给出相关提示,让用户猜测应该输入什么(不得直接给出答案); (3) 如果用户连续输错三次,则尝试使用非本地跳转,给出提示, 并不允许该用户再次尝试。
时间: 2024-02-17 13:59:40 浏览: 85
好的,我可以为您提供一个参考实现版本,如下所示:
```c
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#define TIMEOUT 10 // 超时时间,单位:秒
#define MAX_TRIES 3 // 最大尝试次数
static jmp_buf env_alrm; // 保存 longjmp 调用之前的程序状态
static int tries = 0; // 记录当前尝试次数
// SIGALRM 信号处理函数,超时时会被调用
static void sig_alrm(int signo) {
longjmp(env_alrm, 1); // 跳转到 setjmp 返回的位置,返回值为 1
}
// tfgets 函数
char *tfgets(char *buf, int bufsize, const char *prompt, const char *expected) {
char *ptr;
int c;
struct sigaction sa;
sigset_t newmask, oldmask, zeromask;
// 设置信号处理函数
sa.sa_handler = sig_alrm;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
// 设置超时时限
alarm(TIMEOUT);
// 保存当前程序状态
if (setjmp(env_alrm) != 0) {
// 超时时,跳转到此处
alarm(0); // 关闭定时器
fputs("Time out! Please try again.\n", stderr);
tries++;
if (tries >= MAX_TRIES) {
fputs("Too many tries! Exiting.\n", stderr);
exit(1);
}
return NULL;
}
// 关闭 SIGINT 信号,避免中断输入
sigemptyset(&newmask);
sigemptyset(&zeromask);
sigaddset(&newmask, SIGINT);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
// 显示提示信息
printf("%s", prompt);
// 获取用户输入
ptr = buf;
while ((c = getchar()) != EOF && c != '\n' && (ptr - buf) < bufsize - 1) {
*ptr++ = c;
}
*ptr = '\0';
// 恢复信号状态
sigprocmask(SIG_SETMASK, &oldmask, NULL);
alarm(0); // 关闭定时器
// 校验用户输入是否正确
if (strcmp(buf, expected) != 0) {
tries++;
if (tries >= MAX_TRIES) {
fputs("Too many tries! Exiting.\n", stderr);
exit(1);
}
printf("Wrong input! Please try again.\n");
return NULL;
}
tries = 0; // 重置尝试次数
return buf;
}
```
该函数的实现过程如下:
1. 首先,我们定义了超时时间和最大尝试次数两个常量,并声明了一个 jmp_buf 类型的变量 env_alrm 用于保存程序状态。
2. 然后,我们定义了一个 SIGALRM 信号处理函数 sig_alrm,用于处理超时事件。在该函数中,我们调用 longjmp 函数跳转到 setjmp 函数返回的位置。
3. 接着,我们定义了 tfgets 函数。在该函数中,我们首先设置了信号处理函数和超时时限,并调用 setjmp 函数保存程序状态。
4. 如果程序在超时时限内没有从 setjmp 函数返回,说明超时事件发生了,我们关闭定时器,输出超时提示信息,并尝试重新获取用户输入。如果连续尝试次数超过了最大尝试次数,就退出程序。
5. 如果程序在超时时限内从 setjmp 函数返回,说明用户已经输入了信息,我们关闭定时器,并获取用户输入。注意,在获取用户输入前,我们还需要关闭 SIGINT 信号,避免中断输入。
6. 获取用户输入后,我们恢复信号状态,并校验用户输入是否正确。如果用户输入错误,我们输出错误提示信息,并尝试重新获取用户输入。如果连续尝试次数超过了最大尝试次数,就退出程序。
7. 如果用户输入正确,我们返回用户输入的字符串。
需要注意的是,该实现版本仅供参考,可能存在一些不足之处,您可以根据自己的实际需求进行修改和优化。
阅读全文