C - 有没有办法读取用户输入的单个字符,而不让其余 "pushed down" 进入下一个输入请求?
C - Is there a way to read a single character of user input, and not have the rest "pushed down" to the next request for input?
所以,我正在用 C 开发一个简单的刽子手游戏,我有函数 read_guess,如下所示。
void read_guess(char *guesses, char *p_current_guess)
{
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgets(p_current_guess, 2, stdin);
if (!isalpha(*p_current_guess)) printf("Guesses must be alphabetic. Please try again.\n\n");
else
{
valid_guess = 1;
// Iterates over array of guesses and checks if letter has already been guessed
for (int i = 0; guesses[i] != '[=11=]'; i++)
{
if (guesses[i] == *p_current_guess)
{
printf("You have already guessed this letter. Please try again.\n\n");
valid_guess = 0;
break;
}
}
}
}
}
我已经尝试了所有标准输入函数(包括 getchar),但是对于所有这些函数,当提供大于一个字符的输入时,而不是只获取第一个字符并继续(或再次询问) ,输入的其余部分是 "pushed back",下次请求输入时,无论是因为输入包含非字母字符还是下一轮开始,都会自动处理输入的其余部分。这对输入的每个字符重复。
我怎样才能避免这种情况?
您可以在 windows 上使用 getch() 函数来获取单个字符。这是 linux 等效的
What is the equivalent to getch() & getche() in Linux?
您可以丢弃所有输入,直到行尾,每次您想要请求输入时。
void skip_to_eol(FILE* f, int c)
{
while (c != EOF && c != '\n')
c = fgetc(f);
}
...
char c = getchar(); // instead of fgets
skip_to_eol(stdin, c);
您正在使用 fgets
这很好,但不幸的是不是正确的方法...
fgets
读到行尾 或至多比要求的字符数 少 1。当然剩下的字符留给下一次读取操作...
惯用的方法是确保读取到行尾,无论长度如何,或者至少达到更大的长度。
简单但输入超过 SIZE 个字符时可能会失败:
#define SIZE 64
...
void read_guess(char *guesses, char *p_current_guess)
{
char line[SIZE];
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgets(line, SiZE, stdin); // read a line of size at most SIZE-1
p_current_guess[0] = line[0]; // keep first character
p_current_guess[1] = '[=10=]';
...
稳健但稍微复杂一些
/**
* Read a line and only keep the first character
*
* Syntax: char * fgetfirst(dest, fd);
*
* Parameters:
* dest: points to a buffer of size at least 2 that will recieve the
* first character followed with a null
* fd : FILE* from which to read
*
* Return value: dest if one character was successfully read, else NULL
*/
char *readfirst(dest, fd) {
#define SIZE 256 // may be adapted
char buf[SIZE];
char *cr = NULL; // return value initialized to NULL if nothing can be read
for (;;) {
if(NULL == fgets(buff, sizeof(buff), fd)) return cr; // read error or end of file
if (0 == strcspn(buff, "\n")) return cr; // end of file
if (cr == NULL) { // first read:
cr = dest; // prepare to return first char
dest[0] = buff[0];
dest[1] = 0;
}
}
}
然后您可以在您的代码中简单地使用它:
void read_guess(char *guesses, char *p_current_guess)
{
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgetfirst(p_current_guess, stdin);
所以,我正在用 C 开发一个简单的刽子手游戏,我有函数 read_guess,如下所示。
void read_guess(char *guesses, char *p_current_guess)
{
int valid_guess = 0;
// Repeatedly takes input until guess is valid
while (valid_guess == 0)
{
printf(">>> ");
fgets(p_current_guess, 2, stdin);
if (!isalpha(*p_current_guess)) printf("Guesses must be alphabetic. Please try again.\n\n");
else
{
valid_guess = 1;
// Iterates over array of guesses and checks if letter has already been guessed
for (int i = 0; guesses[i] != '[=11=]'; i++)
{
if (guesses[i] == *p_current_guess)
{
printf("You have already guessed this letter. Please try again.\n\n");
valid_guess = 0;
break;
}
}
}
}
}
我已经尝试了所有标准输入函数(包括 getchar),但是对于所有这些函数,当提供大于一个字符的输入时,而不是只获取第一个字符并继续(或再次询问) ,输入的其余部分是 "pushed back",下次请求输入时,无论是因为输入包含非字母字符还是下一轮开始,都会自动处理输入的其余部分。这对输入的每个字符重复。
我怎样才能避免这种情况?
您可以在 windows 上使用 getch() 函数来获取单个字符。这是 linux 等效的
What is the equivalent to getch() & getche() in Linux?
您可以丢弃所有输入,直到行尾,每次您想要请求输入时。
void skip_to_eol(FILE* f, int c)
{
while (c != EOF && c != '\n')
c = fgetc(f);
}
...
char c = getchar(); // instead of fgets
skip_to_eol(stdin, c);
您正在使用 fgets
这很好,但不幸的是不是正确的方法...
fgets
读到行尾 或至多比要求的字符数 少 1。当然剩下的字符留给下一次读取操作...
惯用的方法是确保读取到行尾,无论长度如何,或者至少达到更大的长度。
简单但输入超过 SIZE 个字符时可能会失败:
#define SIZE 64 ... void read_guess(char *guesses, char *p_current_guess) { char line[SIZE]; int valid_guess = 0; // Repeatedly takes input until guess is valid while (valid_guess == 0) { printf(">>> "); fgets(line, SiZE, stdin); // read a line of size at most SIZE-1 p_current_guess[0] = line[0]; // keep first character p_current_guess[1] = '[=10=]'; ...
稳健但稍微复杂一些
/** * Read a line and only keep the first character * * Syntax: char * fgetfirst(dest, fd); * * Parameters: * dest: points to a buffer of size at least 2 that will recieve the * first character followed with a null * fd : FILE* from which to read * * Return value: dest if one character was successfully read, else NULL */ char *readfirst(dest, fd) { #define SIZE 256 // may be adapted char buf[SIZE]; char *cr = NULL; // return value initialized to NULL if nothing can be read for (;;) { if(NULL == fgets(buff, sizeof(buff), fd)) return cr; // read error or end of file if (0 == strcspn(buff, "\n")) return cr; // end of file if (cr == NULL) { // first read: cr = dest; // prepare to return first char dest[0] = buff[0]; dest[1] = 0; } } }
然后您可以在您的代码中简单地使用它:
void read_guess(char *guesses, char *p_current_guess) { int valid_guess = 0; // Repeatedly takes input until guess is valid while (valid_guess == 0) { printf(">>> "); fgetfirst(p_current_guess, stdin);