如何消除开关的情况下使用goto

问题描述 投票:3回答:6

基本上我想接受来自用户的特定的字符,然后使用它通过与该字符的情况下,以例如。对于另一功能相关的串的开关壳体。

case i:strcpy(str,"ice-cream");
    other_function(str);
    break;

如果有任何默认字符得到了用户打印的,那么它应该打印默认的语句,并再次从用户采取的性格和检查它的情况。我这样做有goto,但有可用来避免或在此代码替换goto任何其他选项。

p:  
    {
        cout<<"Choose account type:-\n"<<"Enter\ns :-saving\nc :-current\nf :-fixed\nr :-recurring"<<endl;
        char c;
        cin>>c;
        switch(c)
        {
            char t[20];
        case 's':
             strcpy(t,"saving");
             a[i].setype(t);
             break;
        case 'c':
             strcpy(t,"current");
             a[i].setype(t);
             break;
         case 'f':
             strcpy(t,"fixed");
             a[i].setype(t);
             break;
         case 'r':
             strcpy(t,"reccurring");
             a[i].setype(t);
             break;
         default:
             cout<<"Enter valid account type"<<endl;
             goto p;
         }
     }
c++
6个回答
9
投票

整个switch应不辞而别断成一个函数,并使用它的返回值,以确定发生了什么循环下一步。

while (true) {
    std::cout << "Choose account type:\n" << std::flush;
    char c;

    if (cin >> c)
    {
       const bool result = HandleUserInput(a[i], c);
       if (result)
          break;
       else
          std::cout << "Enter valid account type\n";
    }
    else
    {
       // Input error - you'll want to do something about that
    }
}

和:

// Given a character representing an account type, sets
// the type of 'account' as appropriate. Returns false
// on failure.
bool HandleUserInput(Account& account, const char c)
{
    switch (c)
    {
        case 's':
           a[i].setype("saving");
           return true;

        case 'c':
           a[i].setype("current");
           return true;

        case 'f':
           a[i].setype("fixed");
           return true;

        case 'r':
           a[i].setype("recurring");
           return true;

        default:
           return false;
    }
}

(注意我是如何摆脱了strcpy,这似乎并没有必要的?要看什么setype [这是拼写错误]我也想。此外,对于加分,可以考虑使用地图,而不是开关,如果你不“在意有点性能损失。)

拔示巴的建议是一个有效的选择,但我认为一个return会显得更加清晰一个switch内比会continue,因为后者有其他种类的控制流语句的含义之内,而前者从来不会。

还要注意的是,如果你决定不使用的功能对于一些很好的理由,实际上有什么特别问题与您goto,不要让货物信徒告诉你,否则!


7
投票

就在这里。由于continue不具有一个switch块的直接含义(参见break),前者的存在将适用于适当的外环控制结构。

因此,一些上线

do {
    // your code here, starting with "Choose account type".

    ...

    default:
        std::cout << "Enter valid account type" << std::endl;
        continue; // back to the start of the do loop
    } // close the switch
    break; // fall out of the loop
} while (true);

会做的,而且是相当地道的C ++。


3
投票

使用布尔标志:

bool isInputSuccessful = false;
while (!isInputSuccessful)
{
    cout<<"Choose account type:-\n";
    char c;
    cin>>c;
    isInputSuccessful = true;
    switch(c)
    {
        char t[20];
        case 's':strcpy(t,"saving");
                 a[i].setype(t);
                 break;
        case 'c':strcpy(t,"current");
                 a[i].setype(t);
                 break;
        case 'f':strcpy(t,"fixed");
                 a[i].setype(t);
                 break;
        case 'r':strcpy(t,"reccurring");
                 a[i].setype(t);
                 break;
        default:cout<<"Enter valid account type"<<endl;
                 isInputSuccessful = false;
    }
}

从用户输入之前,该代码将成功标志true,如果不成功,返回它false

或者,它可能只是将其设置在每个成功的情况下true


2
投票

我建议将你的代码的一些功能。这将使它更容易了解每个功能在做什么,它是如何做的。

bool isValidAccountType(char c)
{
   return ( c == 's' || c == 'c' || c == 'f' || c == 'r');
}

char getAccountType()
{
   char c;
   cout<<"Choose account type:-\n"<<"Enter\ns :-saving\nc :-current\nf :-fixed\nr :-recurring"<<endl;
   while ( cin >> c )
   {
      if ( isValidAccountType(c) )
      {
         return c;
      }
      cout<<"Enter valid account type"<<endl;
   }

   // Wasn't able to get input.
   // Exit out of the program.
   exit(0);
}

void processAccount(char c)
{
   char t[20];
   switch(c)
   {
      case 's':strcpy(t,"saving");
               a[i].setype(t);
               break;
      case 'c':strcpy(t,"current");
               a[i].setype(t);
               break;
      case 'f':strcpy(t,"fixed");
               a[i].setype(t);
               break;
      case 'r':strcpy(t,"reccurring");
               a[i].setype(t);
               break;
      default:cout<<"Invalid account type"<<endl;
              return;
   }

   // Rest of the function.
}

使用在main以下。

char c = getAccountType();
processAccount(c);

1
投票

如果你把这个代码放到一个功能,您可以使用return声明退出循环:

const char* enter() {
    for (;;) {
        std::cout << "Choose account type: ";
        char ch;
        std::cin >> ch;
        switch(ch) {
            case 's': return "saving";
            case 'c': return "current";
            case 'f': return "fixed";
            case 'r': return "recurring";
        }
        std::cout << "Invalid input.\n";
    }
}

现在,你可以调用这个函数,并使用它的结果:

char t[20];
strcpy(t, enter());
a[i].set_type(t);

-1
投票

而所有其他的例子是非常有趣的,我通常远离true客场循环条件只要有可能。

在这种情况下,这将是正确的本身的情况下,处理移动到一个功能,并使用该函数的返回结果,继续操作。

首先声明一些预定义的返回结果。

enum class Action_Result
{
    Ok,
    Error,
    Invalid_account,
    Quit
    /*...*/
};

接下来使函数返回预定义的结果。 (请注意,而不是在break casereturn用来打出来的功能,并且也返回作用的结果。

Action_Result handle_account_type(char c /*...*/)
{
    switch (c)
    {
        char t[20];
        case 's':
            strcpy(t, "saving");
            a[i].setype(t);
            return Action_Result::Ok;
        case 'c':
            strcpy(t, "current");
            a[i].setype(t);
            return Action_Result::Ok;
        case 'f':
            strcpy(t, "fixed");
            a[i].setype(t);
            return Action_Result::Ok;
        case 'r':
            strcpy(t, "reccurring");
            a[i].setype(t);
            return Action_Result::Ok;
        default:
            return Action_Result::Invalid_account;
    }
}

然后在主循环中,我们可以根据处理函数的结果决定。注意循环条件如何,现在很容易理解,为什么循环将继续执行,并且什么时候会停止循环。也所有的输入和输出是在主函数,从所述动作(粘附更好地对单一职责原则)分开。

int main()
{
    Action_Result account_handled_result = Action_Result::Error;

    do
    {
        cout << "Choose account type:-\n"
             << "Enter\ns :-saving\nc :-current\nf :-fixed\nr :-recurring"
             << endl;
        char c;

        if (cin >> c)
        {
            if (c == 'q')
                account_handled_result = Action_Result::Quit;
            else
                account_handled_result = handle_account_type(c);
        }
        else
        {
            account_handled_result = Action_Result::Error;
        }

        if (account_handled_result == Action_Result::Invalid_account)
             cout << "Enter valid account type" << endl;

    } while (account_handled_result != Action_Result::Quit);
}
© www.soinside.com 2019 - 2024. All rights reserved.