【问题标题】:scanf,fgets, fgetc get skipped inside loopscanf,fgets,fgetc 在循环内被跳过
【发布时间】:2015-05-28 16:06:48
【问题描述】:

我正在尝试制作递归菜单。

这个程序稍后将使用树(hojanodo),这就是我跟踪根的原因。

问题:由于某种原因,fgets/fgetc 在第二次运行时在递归内部被跳过,为什么会发生这种情况? 我希望用户输入 1,2 或 3.(int) 有什么办法解决这个问题?这是实现菜单的最佳方式吗?

这就是我现在所拥有的:(它可以编译并运行,因此您可以对其进行测试,但它并没有像我想要的那样真正工作......)

    #include<stdio.h>
#include<stdlib.h>

typedef struct node{
  char ch;
  int i;
  struct node *left;
  struct node *right;
}hojaNodo;


int  handle_menu(int eventHandler, hojaNodo **root);
int opcion_menu();
char get_symbol();
int get_userMenuInput();
int intro();

int main(){

  hojaNodo *treeRoot = NULL;
  intro();
  // system("clear");
  handle_menu(opcion_menu(), &treeRoot);

  return 0;
}

int opcion_menu(){
  int userOption;   

  printf("1.Agrega un Simbolo.\n");
  printf("2.Listar Codigo\n");
  printf("3.Exit");

    userOption = get_userMenuInput();
    printf("User: %d",userOption);

  if(userOption < 4 && userOption > 0){
    return userOption;
  }
  else
    return -1;

}//eof opcion_menu

int handle_menu(int userOption,hojaNodo **root){
  hojaNodo *tempRoot = NULL;
  tempRoot = *root;
   int valor;
   char simbol;

  switch(userOption){
  case 1:

    simbol = get_symbol();
    printf("Simbol: %c", simbol);

    break;
  case 2:
     printf("List Nodes\n");
    break;
  case 3:
    printf("Exit");
    userOption = -1;
    // destroy_tree(root);
    break;
    default:
    printf("userOption Error, Bye!");
    break;
  }//eof switch
  if(userOption != -1)
  handle_menu(opcion_menu(),&tempRoot);
  // return userOption;
  return -1;
}//eof menu()



char get_symbol(){

    /*char userKey[3]
    fgets(userKey,len,stdin);*/
    char simbolo;
    printf("Give me a symbol.");
    simbolo = fgetc(stdin);
    return simbolo;
}

int get_userMenuInput(){

     char userKey[3];
     int userOption;
    size_t len;
     len = sizeof(userKey);
     fgets(userKey,len,stdin);
     userOption = atoi(userKey);
  //printf("User Option: %d\n", userOption);
  return userOption;
}

【问题讨论】:

  • 这一行:'switch(userOption){' 正在使用 userOption,但是,该变量未设置为任何特定值(该变量在 main() 中声明但未设置为任何特定值,所以它包含堆栈中的垃圾,位于 main() 中的位置。看起来变量应该初始化为 1。
  • 始终检查 fgets() 和 family 的返回值,以确保操作成功
  • 如果用户输入的所有内容都是换行符,则对 fgets() 的调用将仅返回两个字节。 (甚至在 windows/dos 系统上它会返回 3 个字符。)建议将变量 userkey 设置为更长的数组,在对 fgets() 的调用中,第二个参数应该是 'sizeof userKey'' 所以对 userkey 的修改只需要在代码中的一处制作。强烈建议删除主变量 eventhandler 并将对 handle_menu 的调用更改为:handle_menu( opcion_menu(), &tempRoot );
  • main() 总是被声明为返回 int,所以它需要一个“返回值”;就在最后一个右大括号之前的语句。建议在启用所有警告的情况下进行编译,以便编译器可以告诉您它在代码中看到的问题。始终修复警告。他们在那里让你知道编译器认为代码有一些可疑的语法/逻辑
  • switch() 代码块应该在一个循环中,提示输入用户输入,直到输入有效值(1、2、3、-1)。如果递归非常深,则消息“userOption Error,Bye!”将为每个级别的递归输出。注意:用户不能通过调用 fgets() 将“-1”输入到只有 2 个字节长的字符数组中。 fgets 将读取一个字节,附加一个 '\0' 并返回。所以数组中的所有内容都是 '-','\0'

标签: char stdin scanf fgets fgetc


【解决方案1】:

我不知道这是否可以帮助任何人。 就我而言,我必须使用这个函数从 char 中“释放”缓冲区:

void clean(){
char cTemp;
while((cTemp = getchar()) !=  '\n')
;
}

我不太确定为什么会这样,但确实如此(如果有人这样做,请将其添加到我的答案中)。 我在调用 get_userOption() 之前调用它;

【讨论】:

    【解决方案2】:

    除了所有与递归相关的 cmets 和其他建议的更改,请检查一下。 fgets() 函数需要刷新输入流。可以使用 fflush() 或 fgetc() 来完成。

    一个简单的解决方案是:

    在函数中:

    int opcion_menu(){

    ...
    fgets(userKey,2,stdin);
    fgetc(stdin); // Add this statement
    

    也在功能上:

    int handle_menu(int userOption,hojaNodo **root)

                case 1:
                        printf("Give me a choice : ");
                        fgets(userKey,2,stdin);
                        fgetc(stdin); // add this statement
    

    fgets 从流中最多读入一个小于 size 的字符,并将它们存储到字符串指向的缓冲区中。这将导致在需要刷新的输入流中仍然可用的换行符。如果这个换行符不是从输入流中读取的,那么这将成为下一个 fgets 函数的输入,最终它将跳过 fgets(因为它已经得到了一个换行符的输入)

    fgetc(stdin) 将清除这些额外的换行符。

    【讨论】:

    • 这个想法是用户输入 1,2 或 3。我认为它必须是 userKey= fgetc(stdin) /// 如果它是我需要的数字,我该如何更改char 到 int?感谢您的帮助
    • 您可以使用 scanf 代替。 scanf("%d", &choice);这将自动将输入转换为整数。
    • 我最初是从 scanf 开始的,但你看到的我的问题是,对菜单使用递归性会使终端跳过 2+ scanf 的......(其中一个问题......)
    • 检查我的修改,这将证明需要刷新数据 fgetc(stdin) 是清除多余的字符而不是用于选择输入
    • 对我的代码进行了一些更改,我运行了它,但是当我第二次进入菜单时,我 getuserOption = '0'......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 2014-10-27
    • 1970-01-01
    相关资源
    最近更新 更多