C 有人能解释为什么当我输入的字符串大小超过允许值时,我的FGET会跳过行吗
我在使用stdin缓冲区时遇到了问题,如果您有任何见解,我将不胜感激。我有一个函数,它接受用户输入姓氏C 有人能解释为什么当我输入的字符串大小超过允许值时,我的FGET会跳过行吗,c,fgets,getchar,C,Fgets,Getchar,我在使用stdin缓冲区时遇到了问题,如果您有任何见解,我将不胜感激。我有一个函数,它接受用户输入姓氏 void lastName(int *counter, User *pt) { for (int i = *counter; i < (*counter + 1); i++) { pt[i].lastName = calloc (MAX_LENGTH, sizeof(char)); printf("Enter Last Name: ");
void lastName(int *counter, User *pt) {
for (int i = *counter; i < (*counter + 1); i++) {
pt[i].lastName = calloc (MAX_LENGTH, sizeof(char));
printf("Enter Last Name: ");
fgets(pt[i].lastName, MAX_LENGTH, stdin);
strtok(pt[i].lastName, "\n");
}
}
如果我输入了一个很长的姓氏,它将被剪切并显示为最大长度,但是ID的FGET将被跳过,否则它可以正常工作。我想知道我的fgets在这种情况下是如何工作的?最大长度为10。我尝试用while(getchar()!='\n')清除缓冲区;它可以工作,但我必须按enter键两次
Enter First Name: Test
Enter Last Name: Williamsamsmases
Enter the ID of Test: Would you like to enter a User?(Y/N):N
调用
fgets
时,它将从stdin
读取输入,直到插入的变量已满。一旦完成,输入缓冲区上的其余输入仍保留在那里。一种解决方案是在读取每个值后清除输入缓冲区
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
基本上从缓冲区读取并丢弃值,直到达到
\n
或EOF
为止。如果输入的行长度超过目标缓冲区可以容纳的长度,则fgets
将读取它可以读取的所有内容,直到目标已满。其余的输入保留在输入缓冲区中,因此下一个fgets
调用将读取剩下的内容
如果目标缓冲区中不存在换行符,则有3个选项:
fgets
,直到缓冲区中有换行符void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
然后,当你意识到这个世界上没有新行时,你可以调用它
目标缓冲区。但不要每次调用fgets
时都调用它,您只能
当您知道输入中还有字符时,调用此函数
缓冲区(当目标缓冲区中没有换行符时),
否则,函数将等待用户输入getline
将负责分配所需的内存
它:
如果getline
在您的系统上不可用,那么您可以编写一个函数
模拟getline
,如下所示:
char *fgets_long(FILE *fp)
{
size_t size = 0, currlen = 0;
char line[1024];
char *ret = NULL, *tmp;
while(fgets(line, sizeof line, fp))
{
int wholeline = 0;
size_t len = strlen(line);
if(line[len - 1] == '\n')
{
line[len-- - 1] = 0;
wholeline = 1;
}
if(currlen + len >= size)
{
// we need more space in the buffer
size += (sizeof line) - (size ? 1 : 0);
tmp = realloc(ret, size);
if(tmp == NULL)
break; // return all we've got so far
ret = tmp;
}
memcpy(ret + currlen, line, len + 1);
currlen += len;
if(wholeline)
break;
}
if(ret)
{
tmp = realloc(ret, currlen + 1);
if(tmp)
ret = tmp;
}
return ret;
}
此函数的工作原理类似于fgets
,但它保证您可以阅读整个文档
行,该函数负责为目标分配足够的内存它不会被跳过。它正在吞噬上一次调用尚未完成的内容。如果输入的行长度超过目标缓冲区所能容纳的长度,则
fgets
将读取它所能读取的所有内容,直到目标已满。其余的输入仍保留在输入缓冲区中,因此下一个fgets
调用将读取剩下的内容。您是否建议清除缓冲区?fflush(stdin)似乎对我不起作用,fseek(stdin,0,SEEK_END)fflush(stdin)
是未定义的行为。您可以getchar
,直到遇到\n
为止stdin
不是可搜索流,您不能将fseek
与stdin
void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
char *line = NULL;
size_t n = 0;
if(getline(&line, &n, stdin) == -1)
{
// error
}
...
free(line);
char *fgets_long(FILE *fp)
{
size_t size = 0, currlen = 0;
char line[1024];
char *ret = NULL, *tmp;
while(fgets(line, sizeof line, fp))
{
int wholeline = 0;
size_t len = strlen(line);
if(line[len - 1] == '\n')
{
line[len-- - 1] = 0;
wholeline = 1;
}
if(currlen + len >= size)
{
// we need more space in the buffer
size += (sizeof line) - (size ? 1 : 0);
tmp = realloc(ret, size);
if(tmp == NULL)
break; // return all we've got so far
ret = tmp;
}
memcpy(ret + currlen, line, len + 1);
currlen += len;
if(wholeline)
break;
}
if(ret)
{
tmp = realloc(ret, currlen + 1);
if(tmp)
ret = tmp;
}
return ret;
}