2009-12-02 61 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提供的缓冲。