【问题标题】:Stuck in a type of loop陷入一种循环
【发布时间】:2016-06-21 19:14:49
【问题描述】:

我刚开始用 C 语言编程,我正在使用代码块来学习。我正在开发一个简单的 ATM 程序,并决定在输入无效条目时使用 goto 函数。当我第一次使用它时,它按预期运行。但现在它不会超过其中一个陈述。代码如下。

当任何选项 1-3 被按下时,它会按预期运行,但也会继续运行在它之后的选择错误部分。如果我只是尝试运行选择错误部分,它会通过它,并一遍又一遍地重复它。我该如何阻止这种情况发生?我只需要在满足条件时才运行无效的选择部分。谢谢!

int iSelection = 0;

float fTransAmount = 0.0;

float fBalance = 100.25;

    printf("\n\n\tATM\n");

menu_options:

    printf("\n1\t To Make a Deposit Press One");
    printf("\n2\t To Make a Withdrawal Press Two");
    printf("\n3\t To End Transaction, Press Three\n");
    scanf("%d", &iSelection);

    if (iSelection == 1) {
        printf("\n Enter Amount to Deposit: ");
        scanf("%f", &fTransAmount);
        printf("\n Your new balance is: $%.2f", fBalance + fTransAmount);

    }  //End if for 1

    if (iSelection == 2) {
        printf("\n Enter Amount to Withdraw: ");
        scanf("%f", &fTransAmount);

        if (fTransAmount > fBalance)
            printf("\n Insufficient funds, ending transaction.....\n");
        else
            printf("\n Your new balance is $%.2f\n", fBalance - fTransAmount);

    } //End if for 2

    if (iSelection == 3) {
        printf("\n ending transaction");

    } //End if for 3

       if (iSelection != 1 || iSelection != 2 || iSelection != 3  ) {
        printf("\nInvalid selection, please try again");

        goto menu_options;
    } //End if for Selection Error

【问题讨论】:

  • 不要使用goto。您可以将其重写为while 循环,这将使其更易于使用和调试。请参阅:stackoverflow.com/questions/46586/goto-still-considered-harmful
  • if (iSelection != 1 || iSelection != 2 || iSelection != 3 )的逻辑不对,应该是&&。但甚至不要这样做,将else if 用于条件 2 和 3,然后使用 else
  • 尽管 CS 教授说什么,goto 在 C 语言中的应用非常好。但它们应该保留在可以提高可读性的地方。您的代码不是一个好的用例。实际上它甚至不是一个可以接受的。使用其他迭代语句。
  • sn-p 不是程序。请参阅How to Ask 并提供minimal reproducible example

标签: c goto


【解决方案1】:

对于像在失败时循环回到开头这样简单的事情,您应该使用while(1)for(;;) 循环无限重复,直到语句break 被执行。它更具可读性,并且效果更好。 goto 在 C 中主要用于资源清理,因为没有对象或异常,处理错误条件和释放内存可能很困难。

话虽如此,你的问题是if (iSelection != 1 || iSelection != 2 || iSelection != 3 )。您正在测试您的选择不是1,或者不是2,或者不是3。这始终是true,因为它永远不会同时三个。

你想要:if (iSelection != 1 && iSelection != 2 && iSelection != 3 )

【讨论】:

  • 你甚至不需要最后一个 if 语句:
  • ^ 同意,您可以在所有其他 ifs 中使用 break 继续循环,如果不输入任何内容,您可以打印一条消息,然后在循环结束,你会跳到顶部。关于这一点,您可以只使用 if-else 树,因为您的所有条件都是互斥的。最后一个条件是最终的else 块。
【解决方案2】:

您的if 条件错误:

(iSelection != 1 || iSelection != 2 || iSelection != 3  )

iSelection 不是 1 或不是 2 或不是 3 时,这将是真的。这将永远是真的。相反,您想使用逻辑 AND (&&):

(iSelection != 1 && iSelection != 2 && iSelection != 3  )

另外,这不是goto 的适当用法。你最好使用while 循环:

while(1) {
    printf("\n1\t To Make a Deposit Press One");

    ...

   if (iSelection != 1 && iSelection != 2 && iSelection != 3  ) {
      printf("\nInvalid selection, please try again");
   } else {
       break;
   }
}

更好的是,使用 switch 语句而不是多个 if 块:

do {

    printf("\n1\t To Make a Deposit Press One");
    printf("\n2\t To Make a Withdrawal Press Two");
    printf("\n3\t To End Transaction, Press Three\n");
    scanf("%d", &iSelection);

    int invalidSelection = 0;
    switch (iSelection) {
    case 1:
        printf("\n Enter Amount to Deposit: ");
        scanf("%f", &fTransAmount);
        printf("\n Your new balance is: $%.2f", fBalance + fTransAmount);
        break;
    case 2:
        printf("\n Enter Amount to Withdraw: ");
        scanf("%f", &fTransAmount);

        if (fTransAmount > fBalance)
            printf("\n Insufficient funds, ending transaction.....\n");
        else
            printf("\n Your new balance is $%.2f\n", fBalance - fTransAmount);
        break;
    case 3:
        printf("\n ending transaction");
        break;
    default:
        printf("\nInvalid selection, please try again");
        invalidSelection = 1;
        break;
    }
} while (invalidSelection);

【讨论】:

    【解决方案3】:

    你甚至不需要最后的 if 语句:

    int repeat = 1;
    while ( repeat) {
       repeat = 0;
       if (iSelection == 1) {
          ...
       } else if ( iSelection == 2 ) {
          ...
       } else if ( iSelection == 3 ) {
          ...
       } else {
          // print error here
          repeat = 1;
       }
    }
    

    或者您也可以使用 switch-case 构造。 这样做的好处是,如果您曾经为 iSelection 添加其他有效值,您只需添加一个额外的“else if”块,而无需编辑最终的 if 语句。

    【讨论】:

      猜你喜欢
      • 2010-11-09
      • 1970-01-01
      • 2019-11-12
      • 2017-03-05
      • 1970-01-01
      • 2020-05-13
      • 2011-06-21
      • 2017-05-22
      • 2022-01-16
      相关资源
      最近更新 更多