【问题标题】:Why does this invalid input still works? (switch case) char error为什么这个无效的输入仍然有效? (开关盒)字符错误
【发布时间】:2014-10-24 15:23:25
【问题描述】:

更新代码

为什么输入 12 有效?它将 12 解释为选项 1 并为 case'1' 的第一个 scanf 取 2?我不想像输入一个字母一样使用 int opcao,它会无限期地运行。

我希望用户只能在选择退出选项(其中一种情况)时退出程序,因此执行... while。如果用户输入无效字符或字母或菜单再次显示的任何内容并显示默认消息。我还希望在执行所选案例后,它会再次显示菜单以供新选择,因此我同时使用 1=1 的始终有效条件。我不能使用整数,就好像你输入一个字母程序会变得疯狂,又名永远不会停止运行。试试看吧。

char opcao;



do {
    menu();
    scanf(" %c",&opcao);

    switch(opcao) {
      case '1':
    printf("Massa do módulo (sem combustível):\n");
    scanf("%f",&m_modulo);
    printf("Massa de combustível:\n");
    scanf("%f",&m_combustivel);
    printf("Altitude no início da alunagem em relação a um ponto de referência:\n");
    break;
      case '2':

    break;
      case '3':
    printf("Funcionalidade nao disponivel.\n");
    break;
      case '4':
    printf("Funcionalidade nao disponivel.\n");
    break;
      case '5':
    printf("Funcionalidade nao disponivel.\n");
    break;
      case '6':
    exit(0);
    break;
      default:
    printf("Opcao invalida, as seguintes opcoes estao disponiveis:\n");
    break;
    }
  }
while(1==1);

【问题讨论】:

  • 使用opcao = getch() 而不是scanf(" %c",&opcao)
  • while(opcao!=1 || opcao!=2 || opcao!=3 || opcao!=4 || opcao!=5 || opcao!=6 && opcao>=1 && opcao<=6); 条件始终为真。
  • 无论如何,你必须决定是使用int opcao还是char opcao
  • 在演示问题时,请始终确保您的示例遵循 "Minimal, Complete, Verifiable Example" 中的“最小”。这意味着 最短代码 来演示混淆。显然,不需要案例 2 到 6(并且没有代码),因此可以删除这些案例。但是,在案例 1 中,您还需要更多的 scanf 调用来证明该问题。请记住,您还可以使用“编辑”按钮编辑您的帖子,使其更加简洁和信息丰富。
  • while 中你真的是指while((opcao != '1')||(opcao != '1') ... 吗?您在开关中测试的值是 ASCII '1',即 = 0x31 或 49(十进制)。

标签: c switch-statement


【解决方案1】:

那是因为您正在使用单个 %c 读取您的输入。

这样,12(1)的第一个字符被switch使用,第二个被case '1':的scanf使用。

为避免这种行为,您可以将选项读取为整数,并在您的第一个 scanf 中使用占位符 %d


编辑:

为了避免你的无限循环问题,你可以这样做:

#include <stdio.h>

void clean_stdin();

int main() {
  int opcao;
  float m_modulo, m_combustivel;
  int flag = 0;

  do {
      printf("Make a choice: ");
      if (scanf("%d", &opcao) == 0) {
        clean_stdin();
      }
      else {
          switch(opcao) {
            case 1:
                    printf("Massa do módulo (sem combustível): ");
                    scanf("%f", &m_modulo);
                    printf("Massa de combustível: ");
                    scanf("%f", &m_combustivel);
                    printf("Altitude no início da alunagem em relação a um ponto de referência.\n");
                    break;
            case 2:

                    break;
            case 3:
                    printf("Funcionalidade nao disponivel.\n");
                     break;
            case 4:
                    printf("Funcionalidade nao disponivel.\n");
                     break;
            case 5:
                    printf("Funcionalidade nao disponivel.\n");
                    break;
            case 6:
                    flag = 1;
                    break;
            default:
                    printf("Opcao invalida, as seguintes opcoes estao disponiveis:\n");
          }
      }

  } while(flag == 0);
}

void clean_stdin()
{
    int c;
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);
}

我所做的如下:

  • 检查 scanf 输出是否正确读取输入(在这种特定情况下,如果输入是一个数字,则它返回一个不同于 0 的数字)。
  • 使用函数clean_stdin (Credits) 来清理scanf 读取但没有消耗的字符(它需要一个数字,你给它一个字符,所以字符留在标准输入并创建无限循环)
  • 我使用标志来控制循环条件,选择退出选项时,将标志值更改为使条件失败
  • 的值
  • 我添加了main(),因为我需要它来运行程序;您可以将里面的内容合并到您的main 中。记得复制clean_stdin()函数。

我建议你阅读一些scanf documentation 来了解它的返回值。

我还建议阅读 scanf 替代品,因为它是一个无聊的功能:link 1link2

请记住使用正确的缩进来格式化您的代码,这是一种最佳做法。

【讨论】:

  • 是的,但是如果我输入一个字母,那么程序会无限期地运行
  • @Leonardo Nunes:“无限运行”是什么意思?你到底观察到了什么?
  • 您需要处理输入char 而scanf 输入int 的情况。
  • @AndreyT 它一直在重新显示菜单直到无穷大,我必须关闭终端才能停止
  • 切换到数字。条件超过一个整数范围。
【解决方案2】:

scanf 就是这样工作的。

您要求scanf 从输入流中读取单个字符。输入流最初包含12 序列(更有可能是12&lt;newline&gt; 序列)。因此,就像您要求的那样,scanf 消耗了第一个 1,将其余部分留在输入流中。

下一个scanf 继续消耗前一个停止的输入流。

【讨论】:

  • 我怎样才能避免这种情况?
【解决方案3】:

scanf%c 可以一次读取一个字符。 “12”包含两个字符“1”和“2”。所以“1”将首先被scanf 消耗,因此case '1': 被执行。 '2' 留在输入缓冲区中(stdin),它将被下一个带有%cscanf 使用。

为避免这种情况,您可以将opcao 声明为整数并使用以下代码:

    while(1)
     {
              if(scanf("%d",&opcao)==0)
              {
              printf("Invalid input. Try again:");
              scanf("%*s"); //remove the invalid input
              continue;
              }
              if(opcao>0 && opcao<7)
              break;
              else
              printf("invalid integer. Try again:");
     }
    switch(opcao) {
      case 1://your code
    break;
      case 2://your code
    break;
      case 3://your code
    break;
       // etc...
       case 6:exit(0);
             }
  //no need of do...while or a default case

【讨论】:

  • 那我该如何避免呢?
  • @LeonardoNunes,将opcao 声明为int 并在我编辑的答案中使用代码
猜你喜欢
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-09
  • 1970-01-01
相关资源
最近更新 更多