问题描述
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 != '\0' ; 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() 函数,但我很好奇为什么这种方法以一种特殊的方式工作。 >
谁能解释一下为什么会这样?我将不胜感激。
解决方法
不要使用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()
会消耗换行符本身。
您的第一个 scanf
仅从 stdin
读取单个整数。当您在输入整数后按 Enter 键时,一个换行符 (\n
) 被发送到 stdin
,它只是停留在那里 - 等待从 stdin
读取的下一个函数。
下一个 gets
然后读取这个换行符并立即返回。所以你需要另一个 gets
来实际读取输入。
话虽如此,您甚至不应该首先使用 gets
- 它是一个已弃用的函数。最重要的是,考虑使用 fgets
来读取输入。 scanf
实际上是一个输入解析函数,而不是一个读取函数。它只读取它可以解析的内容,而将其他所有内容留在 stdin
中。
如果您仍然决定走 scanf
路线,您应该使用 "%d\n"
在第一次输入时使用换行符 - 不仅如此,您还必须检查返回scanf
的值,它返回它能够解析的值的数量。
现在下一个 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
strcspn
上的文档
不过,我建议您走完整的 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
的完整指南 - 将提到这个特定问题。