使用goto是一种合法的方式来打破两个循环?

Luc*_*cas 19 c++ goto

我正在解决Project Euler上的问题9 .在我的解决方案中,我使用"goto"语句来打破两个for循环.问题如下:

毕达哥拉斯三元组是一组三个自然数,abc,为此,

a ^ 2 + b ^ 2 = c ^ 2

例如,3 ^ 2 + 4 ^ 2 = 9 + 16 = 25 = 52.

恰好存在一个毕达哥拉斯三元组,其中a + b + c = 1000.找到产品abc.

我的解决方案是在c ++中:

int a,b,c;
const int sum = 1000;
int result = -1;
for (a = 1; a<sum; a++){
    for (b = 1; b < sum; b++){
            c = sum-a-b;
            if (a*a+b*b == c*c){
                result = a*b*c;
                goto found;
            }
    }   
}
found:
std::cout << "a:" << a << std::endl;
std::cout << "b:" << b << std::endl;
std::cout << "c:" << c << std::endl;
std::cout <<"Result:" << result << std::endl;
Run Code Online (Sandbox Code Playgroud)

由于"goto"语句在c ++程序员中不是很受欢迎,我想知道,如果这可以被认为是合理使用"goto".或者如果对于不需要"goto"的问题有更好的解决方案.我并不是指一种只避免"转到"的解决方案,而是以改进算法的方式避免"转向".

Ale*_*lli 46

return是一个"结构化" goto,许多程序员发现更容易接受!所以:

static int findit(int sum, int* pa, int* pb, int* pc)
{
    for (int a = 1; a<sum; a++) {
        for (int b = 1; b < sum; b++) {
            int c = sum-a-b;
            if (a*a+b*b == c*c) {
                *pa = a; *pb = b; *pc = c;
                return a*b*c;
        }
    }
    return -1;    
}

int main() {
    int a, b, c;
    const int sum = 1000;
    int result = findit(sum, &a, &b, &c);
    if (result == -1) {
        std::cout << "No result!" << std::endl;
        return 1;
    }
    std::cout << "a:" << a << std::endl;
    std::cout << "b:" << b << std::endl;
    std::cout << "c:" << c << std::endl;
    std::cout <<"Result:" << result << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • +1:如果它足够复杂以考虑goto,它足够复杂,可以封装在一个函数中并避免使用goto. (21认同)
  • @onebyone,当然,还有各种各样的原教旨主义者;-),但是"单身回归"在任何我愿意为之努力的地方都非常薄弱:与恐惧症(一种良好的良性疾病)不同程序员,由于过去遭遇意大利面条代码而感到伤痕累累),单一性肠炎是一种恶性(尽管很少见)综合症,需要大刀阔斧的治疗... ;-) (6认同)
  • 这种方法的唯一缺点是,与"从不使用GOTO !!!"的战斗.人群,你直接与"功能必须只有一次回归!!!"战斗 人群.所以采用这种方法因为你喜欢它,觉得"findit"是一个很好的抽象,并愿意为它辩护,很好.仅仅为了避免转到这种方法是徒劳的. (5认同)
  • 是的.不要让循环复杂化.只是出去了.完美解决方案 但你可以通过引用传递a,b,c.然后你不需要乱用指针. (2认同)
  • @Martin,我更喜欢这样的想法,无论我是用C语言还是C++编程,调用f(a)都不会改变a - 如果我们"有时"让它发生,那么心灵的平静就会消失.并且检查(例如)pa是否为空是像检查(例如)a*a + b*b没有溢出那样超级 - 只是调用者必须遵守的合同的一部分.最后,引用也可能错误地为null(接收int&a,传递*p,其中int*p为0,只是在接收函数中打印&a,你会看到0)......! - ). (2认同)
  • 优秀.因此,剩下的就是对死亡和血腥到第七代的战斗,关于应该如何处理多个返回值.我说你需要"课堂PythagoreanTriple:private boost :: tuple <int,int,int>";-) (2认同)

Sta*_*ked 18

在我看来,goto在这样的情况下使用是很好的.

顺便说一下,对goto的居高临下的讲道通常来自那些只是鹦鹉学舌的人,他们听到别人说或在某处读到的东西.

  • @Casebash:好的.但这与答案或问题有何关系? (3认同)

Mat*_*nes 6

看到关于突破2个循环的这个问题.提供的答案比使用goto要好得多.

提供的最佳答案是将第二个循环放入函数中,并从第一个循环中调用该函数.

从mquander的回复复制的代码

public bool CheckWhatever(int whateverIndex)
{
    for(int j = 0; j < height; j++)
    {
        if(whatever[whateverIndex][j]) return false;
    }

    return true;
}

public void DoubleLoop()
{
    for(int i = 0; i < width; i++)
    {
        if(!CheckWhatever(i)) break;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我觉得在这种情况下使用goto并不像杀小猫那么糟糕.但它很接近.

  • 我们怎么都洗脑了?:)这个代码的结果结构比使用goto更复杂(由于DoubleLoop中额外的'if-statement').拆分代码也可能会减少编译器可以进行的优化集 - 例如,"CheckWhatever"本地的变量可能已被优化为在封闭循环之外. (10认同)