我正在尝试从用户收集数据,我想使用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:
如何避免双击并确保收集所有输入?
答案 0 :(得分:2)
真正的诀窍是不要将fgets()
与scanf()
及相关功能的使用混为一谈。原因是它们以不同方式处理换行符的存在。如果缓冲区足够长以容纳完整的行,fgets()
会读取它。 scanf()
,取决于格式字符串的选择,在换行符处停止并将其保留在流中 - 这将导致下一次调用fgets()
立即返回。
尝试使用fgets()
处理来自用户的所有读数。您可以使用sscanf()
来解释用户在需要时输入的字符串。
这样做的一个好处是你实际上并不需要flush_stdin()
函数,因为有时候需要丢弃新行的虚假案例,有时候不会丢弃。
答案 1 :(得分:1)
双输入的问题来自于看起来像这样的调用组合:
get_user_input(some_field);
flush_stdin();
fgets
表明他已完成输入回复。while
flush_stdin
循环
要解决此问题,您应该删除对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'
,因为它会从用户获取新数据,而无需您明确刷新输入。
请注意,您可以从malloc
删除free
/ get_user_input
以及字符串复制,因为调用者已经提供了足够的缓冲区。您的代码假定缓冲区长度至少为STRLEN
,但最好将长度作为第二个参数显式传递给函数。