当前位置: 首页 > 工具软件 > goto > 使用案例 >

goto语句

翟丰茂
2023-12-01

1. 循环的忌讳

表达循环结构

goto语句是低级语言的表征。它很灵活,灵活到没有任何拘束,在函数体内直来直往。函数体内可能含有一些嵌套的循环,这就意味着goto可以跳进跳出循环而无所顾忌。

例如,求1~100的和,由于不断的累积,使得用goto语句也可以直观表达(低级语言通过goto来表示循环结构),但是与for语句对循环结构的明确表达相比较,goto完全处于劣势:

    //goto语句模拟do-while循环
    int i=1,sum=0;
Loop://
    sum += i;
    i = i+1;
    if(i<=100)
        goto Loop;//有条件跳转
    cout<<"the sum is "<<sum<<"\n";

    //goto语句模拟while循环
    int i=1,sum=0;
Loop:
    if(i>100)
        goto END;//有条件跳转
    sum +=i;
    i = i+1;
    goto Loop;//无条件跳转
END:
    cout<<"the sum is "<<sum<<"\n";
    

极端的goto跳转

goto可以向前跳,像上面的代码所示,也可以向后跳,但跳前调后都是为了从一个语句块跳到另外一个语句块。由于入口与出口的随意性使得过程结构遭到毁灭性的破坏!

例如,下面的程序是一个使用goto的极端例子,小小一个程序,理解起来却很费神:

#include<stdio.h>
int main(){
    int a;
    goto Init;
Forward:
    a = a+1;
Print:
    printf("%d\n",a);
    goto Down;
Init:
    a = 1;
    goto Print;
Down:
    if(a<100)
        goto Forward;
}

虽然已经体现出良好的代码书写格式,但是因为可读性差,甚至连改写成不含goto的程序都很困难。在程序运行后,测试到它的功能,才知道它原来只是简单地打印1~100的整数。如果该程序在运行中出了错,可以想象要找出其中的错误肯定比for循环结构要复杂得多。

破坏声明规则

在C++中,声明和定义语句是穿插在过程体中的,如果跳过声明和定义语句,则还能造成过程体的编译错误,因为后面引用的变量没有经过声明或定义是非法的。例如:

    goto Loop;//错误,企图跳过下面的定义语句
    int a =1;
Loop:
    a =  a+1;
    //...

跳出多重循环

现代程序设计不能容忍goto在过程中容易穿梭而破坏过程提的结构。没有goto语句跳过循环语句反应的过程体结构更清晰,程序更易读。

在c++中只有一个地方还有使用goto的价值:当从多重循环深处直接跳转到某个外循环之外时。如果用break,就只能一重一重的退,而且还要边退边做记号,若用goto则显得更为直观。例如:

#include<iostream>
using namespace std;
int main(){
    const int C = 571;
    for (int X,Y; cin>>X>>Y; )
    {
        for (int i = 1;i<=1000; i++)
        for (int j = 1;j<=1000; j++)
             if((i*i*X+j*j*Y)%817==C)
            {
                cout<<i<<" "<<j<<"\n";
                goto A;
            }
        A:
    }
}

上述代码中,“A:”为标记,用于给goto语句提升标志。

这里要注意的是,代码中,if语句是二重循环中内循环的循环体语句。“A:”所标记的位置的在整体二重循环语句的外面,并不是if语句的下一条语句位置。因此,if语句中的goto语句从循环内一下可跳到二重循环的外面。

另外要指出的是,goto标记的位置需要进一步的时间才能理解。例如,上述代码等价于下列代码:

#include<iostream>
using namespace std;
int main(){
    const int C = 571;
A: for(int X,Y; cin>>X>>Y; )
    for(int i=1; i<=1000; i++)
    for(int j=1; j<=1000; j++)
        if((i*i*X+j*j*Y)%817==c){
            cout<<i<<" "<<j<<"\n";
            goto A;
        }
}

在省略了循环中不必要的花括号后,外循环开始处所设立的标号“A”,才是退出两重循环,继续最外层循环的唯一准确位置。

用了goto语句之后,退出两重循环就不需要break语句设置标记变量了,结构上变得清楚。而且,goto语句没有循环层数的障碍,可以从任意内层往某个外层跳去。

我们不提倡用goto去构筑循环,但也不要谈goto色变,需要从循环深处跳出时,可以毫不犹豫用goto去实现。

 类似资料: