fget 是如何工作的?
How fget works?
我正在使用 gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
我正在编写一个非常简单的脚本来将字符串作为输入并使用一些自定义消息打印相同的内容。第一个用户输入 T(获取字符串的次数),然后通过 fgets.
获取输入。我使用 this&this 作为参考。
我得到一个非常奇怪的输出,即 fgets 正在添加一些额外的新行,甚至循环对于 T=2 也不能正常工作,它只要求输入一次。
谁能解释我哪里出了问题与片段。提前致谢!
#include<stdio.h>
#include<string.h>
int main()
{
int T;
scanf("%d",&T);
while(T--){
char str[100]={""};
int i;
printf("Hello\n");
fgets(str,80,stdin);
i = strlen(str)-1;
if(str[i]=='\n')
str[i]='[=10=]';
printf("World\n");
printf("%s\n",str);
}
return 0;
}
请看T=2的图片参考,即使T=2也只取字符串一次,打印语句的顺序也不符合预期。
这一行
scanf("%d",&T);
读取输入,直到找到第一个非数字,即 newline
。然后 fgets()
读取第一个输入的换行符。
我建议也使用fgets()
来读取数字。
fgets(str,80,stdin);
sscanf(str, "%d", &T);
当您在第一个 scanf 中键入 2 后按 "enter" 时,输入流中有一个换行符。这最初由 fgets() 使用,因此它不打印任何内容(您将换行符替换为 [=10=]
)。
在下一行中,您的输入在 World
之后被读取和回显,因为您正在它之后打印它。
这是因为您的scanf()
电话
scanf("%d",&T);
不消耗您输入的换行符\n
。
当你输入T
时,你的输入是2回车.
scanf()
消耗 2
,看到 \n
并停止消耗,在输入缓冲区中留下 \n
。
当调用 fgets()
时,它会在缓冲区中看到 \n
并将其视为输入。
为了解决这个问题,你有几个选择(按照我主观偏好的降序排列):
使用fgets()
获取第一个输入,然后使用strtol()
解析得到T
.
在scanf()
后多加一个fgets()
。
加getchar()
多消耗一个字符。如果您确定输入后恰好会有一个 \n
,则此方法有效。例如,如果您键入 2SpaceEnter,它将不起作用。或者,您可以在 scanf()
之后使用 while(getchar() != '\n');
来使用新行之前的所有内容,但是如果空行是您稍后 fgets()
调用的有效输入,这可能会导致问题。
如果您的实现支持,您可以使用fpurge(stdin)
或__fpurge(stdin)
。
而且,非常重要的是,不要使用fflush(stdin)
除非您的实现明确定义了它的行为。否则它是未定义的行为。您可以参考 this question 了解更多详情。另外请注意,如果您的输入可以通过管道传输到程序中,fpurge()
和 fflush()
方法可能无法正常工作。
第一次调用 scanf 时,您允许用户输入一个整数作为循环次数。他们这样做,并使用回车 return 来表示输入结束。此时 scanf 读取整数,但将行尾 (\n) 留在流中。.
因此,当您调用 fgets 时,fgets 从流中获取信息,直到它到达第一个换行符 -- 在您的代码中,在第一个循环中,这是它遇到的第一个字符。
如果您在调用 fgets 之前丢弃换行符,您应该会得到想要的结果。您可以这样做,例如将前三行更改为:
int T;
char newline;
scanf("%d%c",&T, &newline);
虽然可能有一些在风格上更好的方法来做到这一点。
我正在使用 gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
我正在编写一个非常简单的脚本来将字符串作为输入并使用一些自定义消息打印相同的内容。第一个用户输入 T(获取字符串的次数),然后通过 fgets.
获取输入。我使用 this&this 作为参考。
我得到一个非常奇怪的输出,即 fgets 正在添加一些额外的新行,甚至循环对于 T=2 也不能正常工作,它只要求输入一次。
谁能解释我哪里出了问题与片段。提前致谢!
#include<stdio.h>
#include<string.h>
int main()
{
int T;
scanf("%d",&T);
while(T--){
char str[100]={""};
int i;
printf("Hello\n");
fgets(str,80,stdin);
i = strlen(str)-1;
if(str[i]=='\n')
str[i]='[=10=]';
printf("World\n");
printf("%s\n",str);
}
return 0;
}
请看T=2的图片参考,即使T=2也只取字符串一次,打印语句的顺序也不符合预期。
这一行
scanf("%d",&T);
读取输入,直到找到第一个非数字,即 newline
。然后 fgets()
读取第一个输入的换行符。
我建议也使用fgets()
来读取数字。
fgets(str,80,stdin);
sscanf(str, "%d", &T);
当您在第一个 scanf 中键入 2 后按 "enter" 时,输入流中有一个换行符。这最初由 fgets() 使用,因此它不打印任何内容(您将换行符替换为
[=10=]
)。在下一行中,您的输入在
World
之后被读取和回显,因为您正在它之后打印它。
这是因为您的scanf()
电话
scanf("%d",&T);
不消耗您输入的换行符\n
。
当你输入T
时,你的输入是2回车.
scanf()
消耗 2
,看到 \n
并停止消耗,在输入缓冲区中留下 \n
。
当调用 fgets()
时,它会在缓冲区中看到 \n
并将其视为输入。
为了解决这个问题,你有几个选择(按照我主观偏好的降序排列):
使用
fgets()
获取第一个输入,然后使用strtol()
解析得到T
.在
scanf()
后多加一个fgets()
。加
getchar()
多消耗一个字符。如果您确定输入后恰好会有一个\n
,则此方法有效。例如,如果您键入 2SpaceEnter,它将不起作用。或者,您可以在scanf()
之后使用while(getchar() != '\n');
来使用新行之前的所有内容,但是如果空行是您稍后fgets()
调用的有效输入,这可能会导致问题。如果您的实现支持,您可以使用
fpurge(stdin)
或__fpurge(stdin)
。
而且,非常重要的是,不要使用fflush(stdin)
除非您的实现明确定义了它的行为。否则它是未定义的行为。您可以参考 this question 了解更多详情。另外请注意,如果您的输入可以通过管道传输到程序中,fpurge()
和 fflush()
方法可能无法正常工作。
第一次调用 scanf 时,您允许用户输入一个整数作为循环次数。他们这样做,并使用回车 return 来表示输入结束。此时 scanf 读取整数,但将行尾 (\n) 留在流中。.
因此,当您调用 fgets 时,fgets 从流中获取信息,直到它到达第一个换行符 -- 在您的代码中,在第一个循环中,这是它遇到的第一个字符。
如果您在调用 fgets 之前丢弃换行符,您应该会得到想要的结果。您可以这样做,例如将前三行更改为:
int T;
char newline;
scanf("%d%c",&T, &newline);
虽然可能有一些在风格上更好的方法来做到这一点。