2015-05-17 57 views
1

我想從用戶收集數據,我想用fgets()完成任務。避免`fgets()`double輸入匹配

在我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); 
} 

一切編譯,一切似乎正常工作,但該方案要求時對於用戶輸入(大部分時間),它要求用戶點擊輸入兩次以移動到下一個輸入。

一方面我知道這種行爲是由flush_stdin()函數引起的。另一方面,我無法擺脫flush_stdin()函數,因爲它確保沒有輸入字段被跳過。如果我做的程序會輸出類似於First Name: Last Name:

如何避免雙擊並確保收集所有輸入?

+2

我認爲所有'malloc()'調用都是不必要的。簡單地讀入緩衝區,將它們的長度和它們的指針一起傳遞。 – trojanfoe

回答

1

具有雙輸入的問題來自電話的組合,看起來像這樣:

get_user_input(some_field); 
flush_stdin(); 
  • 的第一行代碼需要用戶按爲了輸入以指示fgets他已完成輸入迴應。
  • 的第二行代碼需要用戶按以結束內部flush_stdin

while循環要解決這個問題,您應該刪除調用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',因爲它需要新數據F rom用戶,而不必顯式刷新輸入。

請注意,您可以從get_user_input中刪除malloc/free以及字符串複製,因爲調用方已經提供了足夠的緩衝區。您的代碼假定緩衝區的長度至少爲STRLEN,但最好將顯式長度作爲第二個參數傳遞給該函數。

2

真正的竅門是不要混合使用fgets()scanf()及相關功能。原因是他們處理換行符的方式不同。 fgets()如果緩衝區足夠長以容納一整行,則將其讀入。 scanf()(取決於格式字符串的選擇)停在換行符處,並將其保留在流中 - 這將導致下一次調用fgets()立即返回。

嘗試使用fgets()來處理全部的讀取來自用戶。如果需要,您可以使用sscanf()來解釋用戶輸入的字符串。

這樣做的一個好處是,你實際上不需要flush_stdin()函數,因爲不會有虛假的新行有時需要丟棄,有時不需要。