当我输入更多允许的字符串大小时,有人可以解释为什么我的fgets正在跳过行

时间:2018-04-16 19:59:37

标签: 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: ");
        fgets(pt[i].lastName, MAX_LENGTH, stdin);
        strtok(pt[i].lastName, "\n");
    }
}

我也有这个接受ID

用户输入的功能
void id(int *counter, User *pt) {

    char num[MAX_LENGTH];
    long temp;
    for (int i = *counter; i < *counter + 1; i++) {
        printf("Enter the ID of %s: ", pt[i].firstName);
        fgets(num, MAX_LENGTH, stdin);
        strtok(num, "\n");
        temp = strtol(num, NULL, 10);
        pt[i].id = (int) temp;
    }
}

这就是我在主要

中调用它们的方式
lastName(&counter, pt);
id(&counter, pt);

如果我输入一个非常长的姓氏,它会被剪切并显示为MAX_LENGTH但是ID的fgets会被跳过,否则它会正常工作。我想知道我的fgets在这种情况下是如何工作的? MAX_LENGTH为10.我尝试用while(getchar()!='\ n')清除缓冲区;它有效,但我必须按两次输入。

Enter First Name: Test
Enter Last Name: Williamsamsmases
Enter the ID of Test: Would you like to enter a User?(Y/N):N

2 个答案:

答案 0 :(得分:2)

如果输入的行长于目标缓冲区可以容纳的行,则fgets将读取目标已满的所有内容。输入的其余部分保留在输入缓冲区中,因此下一个fgets调用会读取已留下的内容。

如果目标缓冲区中不存在换行符,则有3个选项:

  1. 输入的行长于目标可以容纳的行。在这种情况下,您必须继续调用fgets,直到换行符在缓冲区中。
  2. 您可以使用此功能“清理”输入缓冲区:

    void clean_stdin(void)
    {
        int c;
        while((c = getchar()) != '\n' && c != EOF);
    }
    

    然后当你意识到没有换行符时你可以调用它 目标缓冲区。但是每次拨打fgets时都不要打电话给你,你只能这样做 当您知道输入中还有字符时调用此函数 缓冲区(当目标缓冲区中没有换行符时), 否则该功能将等待用户输入。

  3. 如果您的系统支持getline,那么您可以使用它来阅读 整行和getline将负责分配所需的内存 它:

    char *line = NULL;
    size_t n = 0;
    
    if(getline(&line, &n, stdin) == -1)
    {
        // error
    }
    
    ...
    free(line);
    

    如果您的系统上没有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类似,但它可以保证您阅读整个内容 在该行中,该函数负责为目标分配足够的内存。

答案 1 :(得分:1)

当您致电stdin时,它会从int ch; while ((ch = getchar()) != '\n' && ch != EOF); 读取输入,直到插入的变量已满。一旦它,输入缓冲区上的其余输入仍然存在。一种解决方案是在读取每个值后清除输入缓冲区。

\n

您基本上是从缓冲区中读取并丢弃值,直到达到EOFRange