提问人:Riccardo Ricci 提问时间:11/10/2023 最后编辑:Riccardo Ricci 更新时间:11/10/2023 访问量:103
清除 fgets 缓冲区
Clear fgets buffer
问:
我的代码有问题。
int startProg()
{
char *method;
method= malloc(30*sizeof(char));
int isInteger=0;
int num;
do{
printf("Seleziona il metodo \n");
fgets(method,30,stdin);
//it must be nothing more than 1 char inside
if (method[1]!= 10)
{
printf("Insert just one char \n");
}else{
if (method[0]>='1'&&method[0]<='4'){
switch (method[0]){
case '1':
num=1;
break;
case '2':
num=2;
break;
case '3':
num=3;
break;
case '4':
num=4;
break;
}
isInteger=1;
//check the option choose
}else{
printf("Inserire un carattere valido\n");
}
}
}while(isInteger==0);
free (method);
return num;
}
//terminal output
Seleziona il metodo
123456789123456789123456781345646
Inserire solo un carattere
Seleziona il metodo
Inserire solo un carattere
Seleziona il metodo
这个想法是接收用户输入,检查是否是 1 到 4 之间的数字,检查女巫值是,然后返回值。 唯一的问题是,当我插入一个超过 30 位的值时。 我必须清理缓冲区,并且我需要我的代码是可移植的。 有人有想法吗? 谢谢
答:
2赞
pmg
11/10/2023
#1
我认为如果输入大于保留的缓冲区,则要清除所有字符直到行尾fgets()
因此,请检测是否是这种情况
if (!fgets(method, 30, stdin)) exit(EXIT_FAILURE);
size_t len = strlen(method);
if (len == 0) exit(EXIT_FAILURE); // input with '\0'????
if (method[len - 1] != '\n') {
// there is still data from the line in the input buffer
clearEOL();
}
您可以作为以下示例之一实现:clearEOL()
void clearEOL(void) {
int ch;
do {
ch = getchar();
} while ((ch != '\n') && (ch != EOF));
}
有些人可能更喜欢for循环:-)
void clearEOL(void) {
for (int ch = getchar(); (ch != '\n') && (ch != EOF); ch = getchar()) /* void */;
}
甚至是无限循环与内部break
void clearEOL(void) {
for (;;) {
int ch = getchar();
if (ch == '\n') break;
if (ch == EOF) break;
}
}
评论
0赞
Riccardo Ricci
11/10/2023
久经考验
1赞
Andrew Henle
11/10/2023
if (method[len - 1] != '\n')
如果读取长度为零的字符串,则将在缓冲区外部读取。fgets()
1赞
pmg
11/10/2023
@AndrewHenle,首先应该测试结果。When 不返回时,字符串将不是空字符串(假设输入中没有字节)。答案已编辑。fgets()
fgets()
NULL
'\0'
-1赞
Anthony C Howe
11/10/2023
#2
您正在为单个字符输入分配不必要的缓冲区。此外,如果没有更多输入,您应该处理 EOF(来自终端)。此代码利用了 ASCII 属性,其中数字 to 是一个连续的范围,EBCDIC(IBM 的字符编码系统)也是如此。^D
0
9
(经过修订以处理 和abc1abc
41
)
#include <ctype.h>
#include <stdio.h>
/*
* Return a value between 1..4 inclusive or 0 for EOF.
*/
int
startprog()
{
int ch, num;
do {
num = 0;
(void) printf("\rchoice (1-4): ");
while ((ch = getchar()) != EOF && isdigit(ch)) {
num = num * 10 + (ch - '0');
}
} while (ch != EOF && (num < 1 || 4 < num));
return num;
}
int
main(int argc, char **argv)
{
(void) printf("your choice %d\n", startprog());
return 0;
}
评论
1赞
Jabberwocky
11/10/2023
不确定他们想要这个。考虑如果输入为 。ABC1ABC
0赞
Anthony C Howe
11/10/2023
@Jabberwocky OP 没有具体说明输入的确切性质。stdio 输入被缓冲,因此在找到有效数字之前,不必要的输入将被忽略。
1赞
Riccardo Ricci
11/10/2023
是的,但是如果用户插入 41,例如,我想接收错误而不是 4
0赞
Riccardo Ricci
11/10/2023
谢谢,就像我说的,我很想用 fgets 来学习新东西。我让 alredy 用 char 代码制作了这样的函数,但我的 ex 处理 41 有问题。谢谢你的提示
0赞
Andrew Henle
11/10/2023
@Jabberwocky 如果用户输入 ,则此代码将调用未定义的行为,因为有符号整数溢出。1412314123122312412312312412312341
0赞
Riccardo Ricci
11/10/2023
#3
我以明确的方式重写我的代码 (加时赛)我知道我不需要 malloc 和其他的,只是为了尝试我仍在学习哈哈。 现在的代码是
void clearEOL() {
int ch;
do {
ch = getchar();
} while ((ch != '\n') && (ch != EOF));
}
int startprog()
{
int num;
char option[25];
int isInt=0;
do{
printf("insert a numer (1/4) \n");
fgets(option,20,stdin);
if(option[1]!='\n' || option[0]=='\n'){
printf("Inserire solo un carattere \n");
clearEOL();
}else
{
if ('1'<=option[0]&&option[0]<='4'){
num=(option[0]-='0');
isInt=1;
}else{
printf("Inserire 1 e 4\n");
clearEOL();
}
}
}while(isInt==0);
return num;
}
评论
0赞
Anthony C Howe
11/10/2023
在EOF的情况下,应进行测试结果。此外,它比硬编码大小更安全。fgets() == NULL
fgets(option, sizeof (option), stdin)
1赞
pmg
11/10/2023
如果输入是空行 ( 和 ),则将从用户那里清除下一行!!option[0] == '\n'
option[1] == '\0'
clearEOL()
0赞
Riccardo Ricci
11/10/2023
我试着把这条线(option[1]!='\n' || option[0]=='\n'),让我知道它是否正确。如果我没有收到正确的值,我必须按回车键才能继续。这正常吗?
0赞
pmg
11/10/2023
即使阅读了一整行,您也在打电话。您需要测试最后一个字符是否为换行符!clearEOL()
fgets()
0赞
Anklon
11/11/2023
你的回答没有解决问题的根源是什么,为什么会这样,以及你的回答如何解决问题。它不会帮助其他面临同样问题的人。
下一个:调用 fgets() 两次
评论
49
52
'1'
'4'
(method[1]!= 10
如果你的意思是,你应该使用'\n'
'\n'