我有这个程序:
#include <stdio.h>
#define SIZE 19
int main(){
char string[SIZE];
while (string[0] != 'A'){
printf("\nEnter a new string.\n");
fgets(string,SIZE,stdin);
int storage = 0;
while (storage != '\n')
{
storage = getchar();
}
}
}
如果输入的字符串超过string []可以容纳的最大字符数,则存在带有getchar()的嵌套while循环。如果不存在,则输入一个包含20个字符的字符串,将导致输出为:
Enter a new string.
12345123451234512345
Enter a new string.
Enter a new string.
问题是,这需要我按Enter两次才能输入新字符串:一次是“ fgets”,一次是嵌套的while循环(这是我对正在发生的事情的理解)。
是否有一种方法可以更改此值,所以我只需要按一次Enter键,或者可以将整个while循环更改为更优雅的方法?
答案 0 :(得分:1)
如果从fgets
接收的缓冲区包含换行符,则说明它读取了输入的所有内容,因此您无需执行其他任何操作。如果不是,则使用额外的循环刷新缓冲区。
答案 1 :(得分:1)
您的想法正确,您只需要仔细考虑如何以及何时需要清空输入缓冲区。
所有面向行的 输入函数(fgets
和POSIX getline
)将读取并在其填充的缓冲区中包含尾随'\n'
({ {1}},只有在缓冲区中有足够的空间时。
使用fgets
时,只有两个可能的返回值:(1)指向已填充缓冲区的指针,或者(2)错误时或当文件结束时出现“ fgets
没有读取任何字符。“
如果NULL
返回一个有效的指针,则由您决定是否读取了完整的输入行,或者输入是否超出缓冲区大小,从而使输入缓冲区中的字符未被读取。 / p>
要进行确定,请检查缓冲区中的最后一个字符是否为fgets
,如果不是,则检查缓冲区中是否包含'\n'
个字符,这些字符指示仍保留在字符中。输入缓冲区。您可以通过多种方式做到这一点,可以使用SIZE-1
(获取指向strchr
的指针),'\n'
(获取索引)或使用过时的{{1 }}(以获取字符串的长度),然后检查strcspn
处的字符。
(关于首选项的注释,您可以使用任何喜欢的方法,但是在strlen
或len-1
的任何一种情况下,请保存索引或长度,以便可以用来验证输入是否超出缓冲区的大小,或者用户是否通过生成手动strcspn
结束输入。您保存索引或长度以防止必须对其中一个进行重复的函数调用
创建一个简单的 helper-function 清除输入缓冲区,以避免在需要检查的地方放置循环也很有帮助。一个简单的函数就可以解决问题,例如
strlen
如果您更喜欢紧凑但可读性较低的版本,则可以使用单个EOF
循环,例如
/* simple function to empty stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
可以将示例的其余部分构造为完成上述每个测试,以提供您所描述的输入处理(尽管使用缓冲区的第一个字符为for
来控制循环有点奇怪) ),例如
void empty_stdin (void)
{
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
}
一种可能更有用的方法是,如果没有输入任何内容(例如,仅在空白行上按下 Enter 时,则退出循环)。测试将为'A'
。更好的方法是简单地使用#include <stdio.h>
#include <string.h>
#define STRSIZE 19
/* simple function to empty stdin */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
char string[STRSIZE] = ""; /* initialize string all 0 */
while (*string != 'A') { /* up to you, but 'A' is a bit odd */
size_t len = 0; /* variable for strlen return */
printf ("enter a string: "); /* prompt */
if (!fgets (string, STRSIZE, stdin)) { /* validate read */
putchar ('\n'); /* tidy up with POSIX EOF on NULL */
break;
}
len = strlen (string); /* get length of string */
if (len && string[len-1] == '\n') /* test if last char is '\n' */
string[--len] = 0; /* overwrite with nul-character */
else if (len == STRSIZE - 1) /* test input too long */
empty_stdin(); /* empty input buffer */
}
return 0;
}
控制输入循环。在那里,您已在进入循环之前验证了读取。您还可以将整个内容包装在while (*string != '\n')
循环中,并根据您选择的任何输入条件控制循环退出。
这些都是可以考虑的可能性。仔细研究一下,如果您还有其他问题,请告诉我。
答案 2 :(得分:0)
fgets()
确实会读取换行符IF(并且仅当缓冲区足够长才能到达并包含它)以及尾随nul终止符。
您的示例输入为20个字符,其后是换行符,然后是nul终止符。那不会有19个字符的缓冲区。
简单的方法是循环使用fgets()
,直到换行符包含在缓冲区中为止。
printf("\nEnter a new string.\n");
do
{
fgets(string,SIZE,stdin);
/*
handle the input, noting it may or may not include a trailing '\n'
before the terminating nul
*/
} while (strlen(string) > 0 && string[strlen(string) - 1] != '\n');
此循环将清除输入内容(包括第一个换行符),并且还允许您显式处理(如果需要,则舍弃)所有收到的输入。因此,没有必要对getchar()
使用第二个循环。
您没有检查fgets()
是否返回NULL
,所以也没有检查。建议您检查一下,因为这可能表明输入错误。