为什么我必须连续两次使用 gets() 函数?
Why do I have to use gets() function twice in a row?
我对下面的代码有一个不寻常的问题。
void Menu()
{
bool end = 0;
int n;
while (!end)
{
scanf("%d", &n);
switch(n)
{
case 1:
my_strlen_show();
break;
//other irrelevant cases 2-6
case 7:
end = 1;
break;
default:
printf("ERROR");
break;
}
}
}
int my_strlen(const char *str)
{
int count = 0;
for (; *str != '[=10=]' ; str++)
{
count++;
}
return count;
}
void my_strlen_show()
{
char tab[1000];
printf("\n\nEnter a sentence: ");
gets(tab);
gets(tab);
printf("\nWritten sentence has %d characters.\n\n", my_strlen(tab));
return;
}
我不知道为什么我必须写两次 gets(tab)
才能使程序正常运行。当我使用一次时,my_strlren_show()
函数立即执行并显示该句子有 0 个字符。我知道我可以在 for 循环中使用其他方法,例如 scanf() 函数,但我很好奇为什么这种方法适用于一种奇特的方式。
谁能解释为什么会这样?我将不胜感激。
您的第一个 scanf
仅从 stdin
中读取一个整数。当您在输入整数后按回车键时,一个换行符 (\n
) 将发送到 stdin
,它就停留在那里 - 等待被从 stdin
读取的下一个函数拾取。
下一个 gets
然后读取这个换行符并立即 returns。所以你需要另一个 gets
来实际读取输入。
话虽如此,您甚至不应该首先使用 gets
- 这是一个已弃用的函数。最重要的是,考虑将 fgets
用于 读取输入 。 scanf
其实是输入解析函数,不是读取函数。它只读取它可以解析的内容,并将其他所有内容留在 stdin
.
中
如果您仍然决定走 scanf
路线,您应该使用 "%d\n"
在第一个输入中使用换行符 - 不仅如此,您 必须 还检查 scanf
的 return 值,它 return 是它能够解析的值的数量。
现在下一个 fgets
调用将不必使用剩余的换行符。它将等待另一行用户输入(注意换行符将包含在 fgets
读入的缓冲区中)-
char tab[1000];
printf("\n\nEnter a sentence: ");
if (fgets(tab, 1000, stdin) == NULL)
{
// handle error during reading
return;
}
// tab now has the user input, delimited with a `\n`
// if you want to get rid of this newline - use `strcspn`
tab[strcspn(name, "\n")] = 0
上的文档
不过,我建议您使用完整的 fgets
路线并使用 sscanf
进行整数解析。
int n;
char buff[4096];
if (fgets(buff, 4096, stdin) == NULL)
{
// handle error during reading
return;
}
if (sscanf(tab, "%d", &n) != 1)
{
// parsing failed - sscanf should've parsed exactly 1 value
// handle error
return;
}
// use n here
这里有一份关于 how to move away from scanf
的完整指南 - 其中会提到这个具体问题。
不要使用gets()
。它危险的不安全性使它获得了属于一小部分函数的可疑区别,这些函数已从 C 语言标准中撤回。
但是,如果您更改为 fgets
:
,您可能会遇到同样的问题
fgets(tab, sizeof(tab), stdin);
问题是 gets()
和 fgets()
读完了当前行的末尾(或者在 fgets()
的情况下直到缓冲区被填满)。前面的 scanf()
只消耗了十进制整数末尾的字节,将该行的其余部分留在输入流中,等待读取。这至少包括一个标记行尾的换行符。在使用 fgets()
或 gets()
读取想要的输入之前,必须消耗掉它。实现这一目标的一种方法是:
if ((scanf("%*[^\n]") == EOF) || (getchar() == EOF)) {
// handle end-of-file or I/O error ...
}
scanf
读取并丢弃下一个换行符之前的任何字符,并且假设未到达文件末尾并且没有发生 I/O 错误,getchar()
消耗换行符本身。
我对下面的代码有一个不寻常的问题。
void Menu()
{
bool end = 0;
int n;
while (!end)
{
scanf("%d", &n);
switch(n)
{
case 1:
my_strlen_show();
break;
//other irrelevant cases 2-6
case 7:
end = 1;
break;
default:
printf("ERROR");
break;
}
}
}
int my_strlen(const char *str)
{
int count = 0;
for (; *str != '[=10=]' ; str++)
{
count++;
}
return count;
}
void my_strlen_show()
{
char tab[1000];
printf("\n\nEnter a sentence: ");
gets(tab);
gets(tab);
printf("\nWritten sentence has %d characters.\n\n", my_strlen(tab));
return;
}
我不知道为什么我必须写两次 gets(tab)
才能使程序正常运行。当我使用一次时,my_strlren_show()
函数立即执行并显示该句子有 0 个字符。我知道我可以在 for 循环中使用其他方法,例如 scanf() 函数,但我很好奇为什么这种方法适用于一种奇特的方式。
谁能解释为什么会这样?我将不胜感激。
您的第一个 scanf
仅从 stdin
中读取一个整数。当您在输入整数后按回车键时,一个换行符 (\n
) 将发送到 stdin
,它就停留在那里 - 等待被从 stdin
读取的下一个函数拾取。
下一个 gets
然后读取这个换行符并立即 returns。所以你需要另一个 gets
来实际读取输入。
话虽如此,您甚至不应该首先使用 gets
- 这是一个已弃用的函数。最重要的是,考虑将 fgets
用于 读取输入 。 scanf
其实是输入解析函数,不是读取函数。它只读取它可以解析的内容,并将其他所有内容留在 stdin
.
如果您仍然决定走 scanf
路线,您应该使用 "%d\n"
在第一个输入中使用换行符 - 不仅如此,您 必须 还检查 scanf
的 return 值,它 return 是它能够解析的值的数量。
现在下一个 fgets
调用将不必使用剩余的换行符。它将等待另一行用户输入(注意换行符将包含在 fgets
读入的缓冲区中)-
char tab[1000];
printf("\n\nEnter a sentence: ");
if (fgets(tab, 1000, stdin) == NULL)
{
// handle error during reading
return;
}
// tab now has the user input, delimited with a `\n`
// if you want to get rid of this newline - use `strcspn`
tab[strcspn(name, "\n")] = 0
上的文档
不过,我建议您使用完整的 fgets
路线并使用 sscanf
进行整数解析。
int n;
char buff[4096];
if (fgets(buff, 4096, stdin) == NULL)
{
// handle error during reading
return;
}
if (sscanf(tab, "%d", &n) != 1)
{
// parsing failed - sscanf should've parsed exactly 1 value
// handle error
return;
}
// use n here
这里有一份关于 how to move away from scanf
的完整指南 - 其中会提到这个具体问题。
不要使用gets()
。它危险的不安全性使它获得了属于一小部分函数的可疑区别,这些函数已从 C 语言标准中撤回。
但是,如果您更改为 fgets
:
fgets(tab, sizeof(tab), stdin);
问题是 gets()
和 fgets()
读完了当前行的末尾(或者在 fgets()
的情况下直到缓冲区被填满)。前面的 scanf()
只消耗了十进制整数末尾的字节,将该行的其余部分留在输入流中,等待读取。这至少包括一个标记行尾的换行符。在使用 fgets()
或 gets()
读取想要的输入之前,必须消耗掉它。实现这一目标的一种方法是:
if ((scanf("%*[^\n]") == EOF) || (getchar() == EOF)) {
// handle end-of-file or I/O error ...
}
scanf
读取并丢弃下一个换行符之前的任何字符,并且假设未到达文件末尾并且没有发生 I/O 错误,getchar()
消耗换行符本身。