【问题标题】:I keep getting an infinite loop when I choose a certain option in my program当我在我的程序中选择某个选项时,我不断得到一个无限循环
【发布时间】:2013-12-30 13:54:40
【问题描述】:

我有这个程序要求用户输入信息,并将其存储在文件中,并允许您通过将总工资设置为 0 来编辑条目或添加新条目或删除条目。

但是,当我尝试修改名称时,它不会修改,当我尝试修改性别时,它会导致无限循环,任何人都可以告诉我有什么问题吗?

我认为我在循环中所做的 break 语句有问题,在此先感谢

#include <stdio.h>
#include <stdlib.h>
typedef struct
{
  int employee_number;
  char employee_name[20];
  char employee_sex;
  int employee_gross_salary;

}information;
int main()
{//open main function
  information customer;
  int i;
  int choice;
  int number;
  int choice2;
  int number2;
  FILE *fptr = fopen("emp.dat", "wb+");

  //asking user to enter atleast 5 customers into datarecords
  for(i = 0; i<1;i++)
  {//open for
    printf("enter employee's number\n");
    scanf("%d",&customer.employee_number);
    getchar();
    printf("enter the employee's name\n");
    scanf("%s", customer.employee_name);
    getchar();
    printf("enter employee's gender\n");
    scanf("%d",&customer.employee_sex);
    getchar();
    printf("enter employee's salary\n");
    scanf("%d",&customer.employee_gross_salary);
    getchar();
    fwrite(&customer,sizeof(customer),1,fptr);
  }//close for 

  for(;;)
  {//open for
    printf("\n what would you like to do\n1]Add entry\n 2]Delete entry \n3]Modify     entry\n4]view entries\n5]exit\n");
    scanf("%d", &choice);
    if(choice == 5)
    {break;}
    else if(choice == 1)
    {//open else if
      fseek(fptr,0, SEEK_END);// check the parameters here
      printf("enter new employee's number\n");
      scanf("%d",&customer.employee_number);
      getchar();
      printf("enter the new employee's name\n");
      scanf("%s", customer.employee_name);
      getchar();
      printf("enter new employee's gender\n");
      scanf("%d",&customer.employee_sex);
      getchar();
      printf("enter new employee's salary\n");
      scanf("%d",&customer.employee_gross_salary);
      getchar();
      fwrite(&customer,sizeof(customer),1,fptr);
      continue;

    }//close else if
    else if( choice == 2)
    {//open else if
      printf("enter the employee number of person\n");
      scanf("%d",&number);
      fseek(fptr,0,SEEK_SET);
      while((fread(&customer,sizeof(customer), 1,fptr))!=NULL)
      {//open while

        if(customer.employee_number == number)
        {//open if
          customer.employee_gross_salary = 0;
        }//close if

      }//close while
      continue;
    }//clsoe else if
    else if(choice == 3)
    {//open else if
      printf("enter the employee number of the employee you would like to modify\n");
      scanf("%d",&number2);
      printf("what would you like to modify\n");
      scanf("%d", &choice2);
      fseek(fptr,0,SEEK_SET);
      while((fread(&customer, sizeof(customer),1,fptr))!= NULL)
      {//open while within else if
        //1 to midify name, 2 to modify gender 3 for salary
        if(customer.employee_number == number2)
        {//open if

          if(choice2 == 1)
          {

            printf("enter new name\n");
            scanf("%s",customer.employee_name );
            break;
          }
          else if(choice2 == 2)
          {
            printf("enter new gender");
            scanf("%d", &customer.employee_sex);
            break;  
          }
          else if(choice2 == 3)
          {
            printf("enter new gross salary\n");
            scanf("%d",    &customer.employee_gross_salary);
            break;
          }

        }//close if

      }//close while within else if
      continue;
    }//close else if
    else if(choice == 4)
    {
      fseek(fptr,0,SEEK_SET);
      while((fread(&customer,sizeof(customer),1,fptr))!= NULL)
        printf("\n%d\t%s\t%c\t%d\n",            customer.employee_number,customer.employee_name,customer.employee_sex,customer.employee_gro    ss_salary);
      continue;
    }
  }//close for
  return 0; 
}//close main function

【问题讨论】:

  • 标题灼伤我的眼睛,还有短信说话
  • 尝试用小代码重现您的问题。有了这个,你会更快得到你的答案
  • @nrathaus jst 如果 itz 不是 insd StkOvrfl0w
  • @Bartdude 无限循环——也许这就是核心问题;)
  • 为什么不自己调试代码呢?我认为这是解决这个问题的方法。你应该知道如何调试

标签: c


【解决方案1】:

这不是您调试的答案,只是对重构代码和未来写作的一些建议:

1。 避免使用 break 和 continue,它们是破坏流、错误来源、坏和邪恶,go to 也是如此,它们在这里是针对特定的没有其他方法的情况。

你可以这样做:

int end = 0,
    choice = 0;

do
{
    fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
    while(fscanf(stdin, "%d", &choice) != 1){}
    if(choice == 1)
    {
        //Do stuff
    }
    else if (choice == 2)
    {
        //Do other stuff
    }
    else if (choice == 3)
    {
        //Do another stuff
    }
    else
    {
        end = 1;
    }
}while(end == 0);
return 0;

没有继续,没有中断,更容易修改,更容易编写,更容易阅读,更短,两个词:更好

2。 总是用英文写,你有一个完整的键盘,不按字母付费,输入整个单词几乎一样快,并且帮助很多其他人理解。 此外,它还可以帮助您在编写文本或代码时减少错误。

3。 如果它们属于同一类型,您可以一次声明多个变量:

int var1;
int var2;
int var3;
...

冗长且重复,您可以改为:

int var1,
    var2,
    var3;

一个好习惯是总是初始化变量,它有助于防止一些错误:

int var1=0,
    var2=0,
    var3=0;

4。 每当你使用一个函数,测试它的返回值时,都会因为认为“它是一个 stdio 函数,它是防错的”而发生了很多错误。例如,您的 emp.dat 的 fopen。它可能会失败(实际上会在某个时候失败)。

FILE *fptr = fopen("emp.dat", "wb+");
if (fptr == NULL)
{
    fprintf(stderr, "Error while opening emp.dat\n");
    return -1;
}

5。 如果您是初学者(这并不丢人,每个人都从某个时间点开始,我们可以说每个人即使在 10 多年的编码之后仍然在开始),请先编写您的算法,然后再编写代码。示例:

//Get user's choice
//If user choice is do stuff
    //Do stuff
//If it is do other stuff
    //Do other stuff
//If it is do another stuff
    //Do another stuff
//Else if he want to quit
    //Quit

然后变成

int choice=0, //User's choice
    end=0; //End of program

do
{
    //Get user's choice
    fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
    while(fscanf(stdin, "%d", &choice) != 1){}
    //If user choice is do stuff
    if(choice == 1)
    {
        //Do stuff
    }
    //If it is do other stuff
    else if(choice == 1)
    {
        //Do other stuff
    }
    //If it is do another stuff
    else if(choice == 1)
    {
        //Do another stuff
    }
    //Else if he want to quit
    else
    {
        //Quit
        end = 1;
    }
}while (end == 0);
return 0;

它还会阻止你在几周后评论你的代码,当你不再知道你为什么这样做或那些东西时。

6。 记录,记录,记录,尤其是在调试时! 如果你愿意,你可以把它放在 stderr 上,这样你就可以把它从你的输出中分离出来。 示例:

int end = 0,
    choice = 0;

fprintf(stderr, "Start\n");

do
{
    fprintf(stderr, "\tBegin loop\n");
    fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
    while(fscanf(stdin, "%d", &choice) != 1){}
    fprintf(stderr, "\tChoice is: %d\n", choice);
    if(choice == 1)
    {
        fprintf(stderr, "\t\tStarting do stuff\n");
        //Do stuff
        fprintf(stderr, "\t\tEnding do stuff\n");
    }
    else if (choice == 2)
    {
        fprintf(stderr, "\t\tStarting do other stuff\n");
        //Do other stuff
        fprintf(stderr, "\t\tEnding do other stuff\n");
    }
    else if (choice == 3)
    {
        fprintf(stderr, "\t\tStarting do another stuff\n");
        //Do another stuff
        fprintf(stderr, "\t\tEnding do another stuff\n");
    }
    else
    {
        fprintf(stderr, "\t\tEnd order\n");
        end = 1;
    }
    fprintf(stderr, "\tEnd of loop\n");
}while(end == 0);
fprintf(stderr, "End\n");
return 0;

所以你现在知道你的程序何时何地,这对调试有很大帮助!

目前就想到这么多,希望对你有帮助。

另外,欢迎使用 Stack Overflow。

编辑:

感谢chunk,还有一点很重要:

7.始终检查 scanf 是否有有效的用户输入。用户的输入可以并且将几乎是一切,并且在某些时候不会是你的想法,测试它,总是。 (它不仅对 (f)scanf 有效,而且对于您从其他来源获取数据但您自己的源代码的各种方式)

int check = 0;
fprintf(stderr, "\tBegin loop\n");
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
check = fscanf(stdin, "%d", &choice);
if(check != 1)
{
    fprintf(stderr, "Bad input\n");
    return -1;
}
fprintf(stderr, "\tValid choice is: %d\n", choice);

这样,除了十进制数之外的任何其他输入都将被丢弃并关闭程序,当然你可以做得更好。

int check = 0;
fprintf(stderr, "\tBegin loop\n");
fprintf(stdout, "1:Do stuff\n2:Do other stuff\n3: Do another stuff\nX: end\n");
while(fscanf(stdin, "%d", &choice) != 1)
{
    fprintf(stderr, "Bad input!\n");
}
fprintf(stderr, "\tValid choice is: %d\n", choice);

在这个版本中,当用户输入无效的内容时,他只需要再试一次。

【讨论】:

  • 所有这些想法,但scanf() 的结果未被检查 - 恕我直言,最重要的想法。如果用户输入一个好的数字“1”到“3”,然后输入“X”,此代码将永远循环。
【解决方案2】:

除了 DrakaSAN 的回答之外,我还要补充一点,当您在输入 integer 后输入 character/string 时,您应该始终刷新输入缓冲区输入。

刷新输入缓冲区的一种方法是使用getchar()

while ((ch = getchar()) != '\n');

但是,如果用户将输入作为“123 abc\n”(如评论中 chux 所述)假设 123 进入整数变量,“abc”进入字符数组,那么有办法解决这个问题:

//can be modified according to programmer's requirements
int a;
char arr[10],ch;

scanf("%d",&a);

while((ch=getchar())==' ' || ch=='\t' || ch=='\n') //loop until non-whitespace character
{
    if (ch=='\n')
    {
        ch=getchar();
        break;
    }
}

if (ch!='\n') //ch contains the first character of the character array
{
    arr[0]=ch;
    gets(arr+1);
}
else //if two consecutive new lines after integer, string contains nothing
    arr[0]='\0';

【讨论】:

  • stdin 之类的输入流执行fflush() 会导致UB。可能在特定平台上工作,但对于可移植代码来说是不好的做法。 C11 7.21.5.2 2 fflush 函数“如果 stream 指向未输入最新操作的输出流或更新流,fflush 函数会导致该流的任何未写入数据被传递到要写入文件的主机环境;否则,行为未定义。"
  • 我从未说过要使用fflush()。有一些方法可以刷新输入缓冲区。您可以在整数输入后使用getchar() 来刷新缓冲区。
  • 我理解刷新stdin 的想法是丢弃stdin 中当前的所有数据。也许您有一些可以引用的定义。你将如何处理重定向的stdin?您将如何处理输入“123 abc\n”。由于这个答案是针对 flush 和您的评论“我从未说过要使用 fflush()”,也许您应该发布它是如何完成的?
  • 请详细说明“您将如何处理输入“123 abc\n””部分。 "123 abc\n" 是整数变量还是字符数组的输入?
  • 两者都不是。使用代码fscanf(stdin, "%d", &amp;choice),输入"123 abc\n" 应该扫描“123”并留下" abc\n" 用于下一个IO 操作。采用 integer 输入并不总是意味着应该丢弃(刷新)直到 \n 的数字之后的所有内容。
【解决方案3】:

choice == 2choice == 3需要在continue前面写结果,like

fseek(fptr, -sizeof(customer), SEEK_CUR);
fwrite(&customer,sizeof(customer), 1, fptr);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-19
    • 2015-10-24
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多