我正在尝试从用户收集数据,我想使用fgets()完成任务。

在我的main.c文件中:

do
    {
        user = ask_user_info();

        // ... Code exporting data to file ...

        free(user);

        fprintf(stdout, "Do you want to add another user?\nChoice: ");
        scanf("%c[^\n]", &choice);

    } while (choice == 'y');

以下是我为完成工作而编写的函数:

UserData *ask_user_info()
{
    char firstname[STRLEN];
    char lastname[STRLEN];
    char username[STRLEN];
    char password[STRLEN];
    char email[STRLEN];

    fprintf(stdout, "First Name: ");
    get_user_input(firstname);
    flush_stdin();

    fprintf(stdout, "Last Name: ");
    get_user_input(lastname);
    flush_stdin();

    fprintf(stdout, "Username: ");
    get_user_input(username);
    flush_stdin();

    fprintf(stdout, "Password: ");
    get_user_input(password);
    flush_stdin();

    fprintf(stdout, "Email: ");
    get_user_input(email);
    flush_stdin();

    return fill_fields(firstname, lastname, username, password, email);
}

void get_user_input(char *input)
{
    int length;
    char *buffer = (char *) malloc (STRLEN * sizeof(char));
    (*buffer) = '\0';

    if (fgets(buffer, STRLEN, stdin) != NULL)
    {
        length = strlen(buffer)-1;
        buffer[length] = '\0';
        strncpy(input, buffer, length+1);
    }

    free(buffer);
}

UserData *fill_fields(const char firstname[], const char lastname[], 
                        const char username[], const char password[], const char email[])
{
    UserData *user = (UserData *) malloc (sizeof(UserData));

    user->firstname = (char *) malloc (strlen(firstname) * sizeof(char));
    strncpy(user->firstname, firstname, strlen(firstname));
    user->lastname = (char *) malloc (strlen(lastname) * sizeof(char));
    strncpy(user->lastname, lastname, strlen(lastname));
    user->username = (char *) malloc (strlen(username) * sizeof(char));
    strncpy(user->username, username, strlen(username));
    user->password = (char *) malloc (strlen(password) * sizeof(char));
    strncpy(user->password, password, strlen(password));
    user->email = (char *) malloc (strlen(email) * sizeof(char));
    strncpy(user->email, email, strlen(email));

    return user;
}

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

一切都在编译,一切似乎都能正常工作,但是当程序要求用户输入时(大多数情况下),它需要用户两次Enter键继续下一个输入。

一方面我知道这种行为是由flush_stdin()函数引起的。 另一方面,我无法摆脱flush_stdin()函数,因为它确保不会跳过任何输入字段。 如果我这样做,程序将输出类似First Name: Last Name:

如何避免双击并确保收集所有输入?

===============>>#1 票数:2

真正的诀窍是不要将fgets()使用与scanf()和相关函数混合使用。 原因是它们以不同方式处理换行符的存在。 如果缓冲区足够长以容纳一个完整的行, fgets()会读入它。 scanf() ,取决于格式字符串的选择,在换行符处停止并将其留在流中 - 这将导致下一次调用fgets()立即返回。

尝试使用fgets()来处理来自用户的所有读数。 您可以使用sscanf()来解释用户在需要时输入的字符串。

这样做的一个好处是你实际上不需要flush_stdin()函数,因为新行有时不需要丢弃虚假的情况,有时也不需要丢弃。

===============>>#2 票数:1 已采纳

double-enter的问题来自于看起来像这样的调用组合:

get_user_input(some_field);
flush_stdin();
  • 第一行代码要求用户按Enter键以向fgets指示他已完成键入响应。
  • 第二行代码要求用户按Enter键以结束flush_stdinwhile循环

要解决此问题,您应该删除对flush_stdin调用,并修改get_user_input以跳过空行:

void get_user_input(char *input) {
    int length;
    *input = '\0';
    do {
        if (fgets(buffer, STRLEN, stdin) == NULL) {
            break;
        }
        length = strlen(buffer)-1;
        buffer[length] = '\0';
    } while (length == 0);
}

do / while循环将跳过输入中的意外'\\n' ,因为它从用户获取新数据,而不必显式刷新输入。

请注意,您可以从get_user_input删除malloc / free以及字符串复制,因为调用者已经提供了足够的缓冲区。 您的代码假定缓冲区的长度至少为STRLEN ,但最好将显式长度作为第二个参数传递给函数。

  ask by haunted85 translate from so

未解决问题?本站智能推荐: