C++ 如何避免在交换机中使用goto

C++ 如何避免在交换机中使用goto,c++,C++,基本上,我想从一个用户那里接受一个特定的字符,然后使用开关大小写将与该字符大小写相关的字符串传递给另一个函数 case i:strcpy(str,"ice-cream"); other_function(str); break; 如果用户打印了任何默认字符,那么它应该打印默认语句,并再次从用户处获取字符并检查其大小写。我是通过goto实现的,但是在这段代码中是否有其他选项可以避免或替换goto p: { cout<<"Choose acc

基本上,我想从一个用户那里接受一个特定的字符,然后使用开关大小写将与该字符大小写相关的字符串传递给另一个函数

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;
         }
     }
p:
{

cout是的。由于
继续
开关
块中没有直接意义(参见
中断
),前者的存在将适用于适当的外环控制结构

所以有些事

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);
do{
//您的代码在这里,以“选择帐户类型”开头。
...
违约:
std::cout使用布尔标志:

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;
    }
}
bool isInputSuccessful=false;
而(!isInputSuccessful)
{
coutc;
isInputSuccessful=true;
开关(c)
{
chart[20];
案例:strcpy(t,“保存”);
a[i].setype(t);
打破
案例“c”:strcpy(t,“当前”);
a[i].setype(t);
打破
案例“f”:strcpy(t,“固定”);
a[i].setype(t);
打破
案例‘r’:strcpy(t,“重新计算”);
a[i].setype(t);
打破

默认值:cout整个
开关应划分为一个函数,其返回值用于确定下一个循环发生了什么

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
    }
}

(注意我是如何摆脱<代码> STRCPY < /代码>的,这似乎不是必须的。我认为什么是<代码> Styype (拼写错误)。 Bathsheba的建议是一个有效的替代方案,尽管我建议

返回
开关
中比
继续
看起来更清晰,因为后者在其他类型的控制流语句中有意义,而前者从来没有意义


还要注意的是,如果你出于某种原因决定不使用某个函数,那么你的
转到
实际上没有什么特别的问题,而且不要让货运爱好者告诉你其他的问题!

我建议将你的代码分成几个函数。这样可以更容易地理解每个函数在做什么以及它是如何做的

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.
}

如果将此代码放入函数中,可以使用
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";
    }
}

虽然所有其他示例都非常有趣,但只要有可能,我通常都会避开
true
循环内条件

在这种情况下,正确的做法是自行将案例处理移动到函数中,并使用函数的返回结果继续操作

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

enum class Action_Result
{
    Ok,
    Error,
    Invalid_account,
    Quit
    /*...*/
};
接下来,让函数返回预定义的结果。(请注意,
案例中的
break
return
用于中断函数并返回操作结果

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;
    }
}
然后在主循环中,我们可以根据处理函数的结果做出决定。注意循环条件现在是如何容易理解的,为什么循环将继续执行,以及何时停止循环。此外,所有输入和输出都在主函数中,与操作分离(更好地坚持单一责任原则)

intmain()
{
动作\结果科目\处理\结果=动作\结果::错误;
做
{

CUT<代码>(C=‘C’& &c=``&&;c’='&&c;=‘r’)< /> >搜索关于C++中的循环主题,但我好奇。您是如何使用<代码> Goto < /Cord>?您似乎还在学习C++,为什么<代码> Goto < /C> >在循环或函数之前出现?(?);{开关(V)案例a:…break;…案例z:…break;默认值:…;
continue
;}
break
;}@VictorGubin:这太不可读了。将循环体移动到一个方法可以保持它的美观和可读性。在我看来,这不是惯用的代码(我十年来第一次看到这样的代码),但它很有趣!它可能有点让人困惑,但至少在最近几年内,我确实看到了它(事实上,我写了它)。我可能会使用
goto
s从非
default
案例中打破循环,然后让
default
案例“自然”循环(虽然我知道OP更愿意避免
goto
),但我必须承认这是非常聪明的,也是非常诱人的。这是一个非常明智的选择。请投赞成票。
char t[20];
strcpy(t, enter());
a[i].set_type(t);
enum class Action_Result
{
    Ok,
    Error,
    Invalid_account,
    Quit
    /*...*/
};
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);
}