2009-12-02 58 views
1

我目前正在爲Beginner C編程類做一個項目,我應該爲公司制定一個基本的訂購系統。 我有一個問題,我的一個功能,它作爲一個單獨的程序很好,但作爲訂購程序中的功能,它不會讓我輸入一個新的項目,它退出該功能之前。 然而,它似乎貫穿get(item)之後的所有事物;因爲我每次運行它時都會添加\ n。C函數在輸入之前退出

這裏是我的代碼:

do{ 
printf("Menu here"); 
scanf("%c", &menu); 
switch(menu) 
{ 
    case 'A': 
     listItem(); 
     break; 

    case 'B': 
     addItem(); 
     break; 

    ... 

    case 'X': 
     break; 
} 

printf("Press Enter to continue."); 
scanf("%c%c", &enter, &enter); 
system("cls"); 

}while(menu != 'X'); 


void addItem() 
{ 
    char item[30]; 
    printf("\nAdd new item: "); 
    gets(item); 
    FILE * output; 
    output = fopen("items.txt", "a"); 
    fputs(item, output); 
    fprintf(output, "\n"); 
    fclose(output); 
} 

開關後的東西是我的老師認爲將是一個醜陋的,但有效的方法來解決這樣的事實,我們沒有深入探究他所謂的「怪癖的C輸入「。

我很感激任何提示和答案,並會在必要時提供更多我的代碼。

+3

從不使用gets。 EVER。 – 2009-12-03 01:54:16

回答

5

正在發生的事情是這樣的:

  1. 程序打印菜單。
    • 用戶類型「B <enter>」。
    • scanf讀取B字符。 <enter>仍在輸入流中等待。
    • addItem被調用。
    • gets()被調用,讀取仍在等待的<enter>,並返回一個空行。

您可以通過閱讀並放棄一切直到幷包括下一個換行符你scanf閱讀菜單選擇角色後修復:

int c; 

printf("Menu here"); 
scanf("%c", &menu); 
do { 
    c = getchar(); 
} while (c != EOF && c != '\n'); 
1

我注意到了一件直接的事情。您的do while循環正在檢查val"X",而該值實際上是menu

除了這種可能性(val可能是"X"開頭,無論輸入的值如何都可能導致退出循環),沒有任何內容跳出顯然會導致過早退出函數或循環。我想你會更好地發佈你的完整代碼庫,所以我們不會猜測太多。

更新:

不要使用下面的功課 - 你幾乎肯定會失敗剽竊(因爲你的教育者,假設他們不是傻瓜總額,將採取的尋找工作來自這些網站)。

我只是想給你的,你可以使用什麼用戶I/O,以使你的程序多了幾分穩健的想法。作爲一個有用的靈魂所指出的,你不應該使用沒有緩衝器超限運行的保護作爲一個選項,因爲這幾乎肯定會允許惡意輸入到崩潰的代碼(這是最好的情況下,輸入程序,最壞的情況是,他們將接管你的電腦)。

這意味着沒有gets,您需要使用fgets,因爲它可以限制實際輸入的信息量。此外,我傾向於避免使用scanffscanf因爲在這些功能中的任何故障實際離開輸入文件指針在一個不確定的位置。

我覺得這是更好的使用fgets得到一整行,請檢查您實際上一整行,然後在該行中使用sscanf。這樣,你可以肯定你是一個行邊界上,你已經有了一個完整的線,你可以再sscanf該行你的心臟的內容,直到你的東西相匹配。

爲此,您可能想看看在下面的代碼:

#include <stdio.h> 

#define FSPEC "file.txt" 

// Skip to the end of the line. This is used in some 
// places to ensure there's no characters left in the 
// input buffer. It basically discards characters 
// from that buffer until it reaches the end of a line. 

static void skipLine (void) { 
    char ch = ' '; 
    while ((ch != '\n') && (ch != EOF)) 
     ch = getchar(); 
} 

 

// Get a line of input from the user (with length checking). 

static char *getLine (char *prompt, char *line, int sz) { 
    // Output prompt, get line if available. 
    // If no line available (EOF/error), output newline. 

    printf ("%s", prompt); 
    if (fgets (line, sz, stdin) == NULL) { 
     printf ("\n"); 
     return NULL; 
    } 

    // If line was too long (no '\n' at end), throw away 
    // rest of line and flag error. 

    if (line[strlen (line) - 1] != '\n') { 
     skipLine(); 
     return NULL; 
    } 

    // Otherwise line was complete, return it. 

    return line; 
} 

 

// Output the menu and get a choice from the user. 

static char doMenu (void) { 
    char cmd[1+2]; // need space for char, '\n' and '\0'. 

    // Output the menu. 

    printf ("\n"); 

    printf ("\n"); 
    printf ("Main menu\n"); 
    printf ("---------\n"); 
    printf ("1. Input a line\n"); 
    printf ("2. Output the file\n"); 
    printf ("3. Clear the file\n"); 
    printf ("\n"); 
    printf ("x. Exit\n"); 
    printf ("\n"); 

    // Get the user input and return it. 

    if (getLine ("Enter choice (1,2,3,x): ", cmd, sizeof(cmd)) == NULL) 
     return '\n'; 

    printf ("\n"); 

    return cmd[0]; 
} 

 

static void doOption1 (void) { 
    FILE *fh; 
    char *ln; 
    char buff[15+2]; // need space for line, '\n' and '\0'. 

    // Get and check line, add to file if okay. 

    if ((ln = getLine ("Enter line: ", buff, sizeof(buff))) == NULL) { 
     printf ("Bad input line\n"); 
    } else { 
     fh = fopen (FSPEC, "a"); 
     if (fh != NULL) { 
      fputs (ln, fh); 
      fclose (fh); 
     } 
    } 
} 

 

static void doOption2 (void) { 
    FILE *fh; 
    int intch; 

    // Output the file contents. 

    printf ("=====\n"); 
    fh = fopen (FSPEC, "r"); 
    if (fh != NULL) { 
     while ((intch = fgetc (fh)) != EOF) 
      putchar (intch); 
     fclose (fh); 
    } 
    printf ("=====\n"); 
} 

 

static void doOption3 (void) { 
    FILE *fh; 

    // Clear the file. 

    fh = fopen (FSPEC, "w"); 
    if (fh != NULL) 
     fclose (fh); 
} 

 

// Main program basically just keeps asking the user for input 
// until they indicate they're finished. 

int main (void) { 
    char menuItem; 

    // Get asking for user input until exit is chosen. 

    while ((menuItem = doMenu()) != 'x') { 
     switch (menuItem) { 
      case '1': doOption1(); break; 
      case '2': doOption2(); break; 
      case '3': doOption3(); break; 
      default: printf ("Invalid choice\n"); break; 
     } 
    } 

    return 0; 
} 
+0

break只會跳出switch-statement而不是while循環。 – Lucas 2009-12-02 23:26:43

+0

@盧卡斯,你的陳述是正確的,但我無法找到我實際上爭論的地方。我聲明,如果val設置爲「X」,則循環會退出,而不是退出循環的break語句。 – paxdiablo 2009-12-02 23:53:50

+0

菜單和val問題是我擰我的變量我的翻譯英語,我錯過了將最後一個val更改爲菜單,循環條件在我的原始代碼有效 – 2009-12-03 01:01:19

1

你每次讀一個字符,並scanf()做一些緩衝。如果我輸入「ABC」並按回車鍵,程序將讀取「A」,執行「A」的操作,打印「按回車繼續」,在緊接着的scanf中讀取「B」和「C」。所以當然它會很快回歸;你已經給了它一些輸入,即'B'和'C'。

我建議你使用另一種輸入方法。例如,您可以切換到基於行的命令(可能使用fgets()),這要求您在每一步都按Enter鍵。或者你可以使用curses或任何你需要做非緩衝輸入的平臺特定的東西,這樣你就可以對按下的按鍵做出反應,而不是由stdio提供的緩衝。