C输入前退出function

我正在为一个初级C编程课做一个项目,我应该为公司制作一个基本的订购系统。 我的一个函数有一个问题,它作为一个单独的程序工作正常,但作为订购程序中的一个函数,它不会让我在退出函数之前输入一个新项目。 然而似乎在获得(项目)之后贯穿一切; 因为每次运行它都会添加\ n。

这是我的代码:

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输入的怪癖”。

我很感谢任何提示和答案,并会在必要时提供更多我的代码。

这是怎么回事:

  1. 程序打印菜单。
    • 用户 “B ”。
    • scanf读取B字符。 仍在输入流中等待。
    • 调用addItem
    • 调用gets() ,读取仍在等待的 ,并返回一个空行。

在使用scanf读取菜单选择字符后,您可以通过阅读并放弃所有内容(包括下一个换行符)来修复它:

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

你一次只读一个字符,而scanf()正在做一些缓冲。 如果我键入“ABC”并按Enter键,您的程序将显示为“A”,执行“A”操作,打印“按Enter键继续”,在紧随其后的scanf中读取“B”和“C”。 所以当然会早点回来; 你已经给它一些输入,即’B’和’C’。

我建议你使用另一种输入方法。 例如,您可以切换到基于行的命令(可能使用fgets() ),这需要您在每一步都按Enter键。 或者您可以使用curses或任何特定于平台的事物来进行非缓冲输入,这样您就可以对按键进行响应,而不是stdio提供的缓冲。

我注意到的一件事。 你的do while循环检查val"X"而该值实际上是在menu

除了这种可能性( val可能是"X"开头,无论输入的值如何都可能导致从循环中退出),没有任何事情跳出来,因为显然会导致函数或循环过早退出。 我认为你最好发布你的完整代码库,所以我们不会猜太多。

更新:

不要将以下内容用于家庭作业 – 你几乎肯定会因抄袭而失败(因为你的教育工作者,假设他们不是完全傻瓜,将会留意从这些网站上取得的工作)。

我只是想让您了解可以用于用户I / O的内容,以使您的程序更加强大。 正如一位有用的灵魂指出的那样,你永远不应该使用没有缓冲区溢出保护的输入例程作为选项,因为这几乎肯定会让恶意输入崩溃你的代码(这是最好的情况,最坏的情况是他们将接管你的电脑)。

这意味着没有gets ,你需要使用fgets因为它可以限制实际输入的信息量。 另外,我倾向于避免使用scanffscanf因为这些函数中的任何失败实际上都会将输入文件指针留在不确定的位置。

我发现使用fgets获得整行更好,检查你实际上是否整行,然后在该行上使用sscanf 。 这样,你就可以确定自己处于一个线边界,你已经拥有一条完整的线,然后你就可以根据自己的内容进行sscanf ,直到你将它与某些内容相匹配。

为此,您可能需要查看以下代码:

 #include  #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; }