C/C++/Java goto语句的使用

来源:互联网 发布:空气炮升级数据 编辑:程序博客网 时间:2024/06/08 17:13

goto语句:http://baike.baidu.com/link?url=2SPNcNbC4S-CP08jQV5ei2b9zqpXdfHrFRqstF5TCsVTnZeUcrpQ3THe0uvWkF95eyej52gBijSAwwXR_6ZeIq#6

《C Primer Plus》(第6版)中文版 7.8章 goto语句

《JAVA核心技术 卷I:基础知识》3.8.6章 中断控制流程语句


##############################################################


最近一段时间,经常需要在同一个函数中编写多个重复代码,出现问题后就需要一个个找出来进行修改,没有效率。在一个例子里发现一段goto语句的使用,发现能够高效的处理重复代码,之前对于goto语句并没有在意,觉得应该不用任何goto语句,但是现在看来,goto语句还是很有效的


知乎上有一个关于goto语句使用的讨论:
既然建议尽量避免使用goto语句为何C++还要支持goto呢?:https://www.zhihu.com/question/21981058


################################################################


首先介绍C/C++版本的goto语句


goto语句也称为无条件转移语句,最早应该出现在BASIC和FORTRAN中,C/C++也能够使用goto语句,但C/C++与前面两种语言不同的是,goto语句并不是必需的,没有goto语句程序也能运行良好。


goto语句的一般格式:

goto 标签名;

其中标签名遵循变量命名规则


介绍一下变量命名规则

1).变量名只能是字母(A-Z,a-z)和数字(0-9)或者下划线(_)组成;

2).第一个字母必须是字母或者下划线开头;

3).不能使用C/C++关键字来命名变量,以免冲突;

4).变量名区分大小写。

参考:C/C++变量命名规则,个人习惯总结 - http://blog.sina.com.cn/s/blog_8a7012cf01017h9p.html


同时程序必须包含另一条语句,格式为:

标签名:
即标签名后紧跟一个冒号


一个简单的C程序:

#include <stdio.h>int main(int argc, char* argv[]) {    if (getchar() == 'a') {        goto Hi;    } else {        goto Hello;    }Hi: printf("Hi World\n");    return 0;Hello: printf("Hello World\n");    return 0;}

当你输入字符a时,输出Hi World;否则,输出Hello World






原则上,根本不用在C/C++程序中使用goto语句。但在以下场景中,使用goto语句可以高效的处理代码


1.从多重循环中直接跳出

当需要结束嵌套循环时,break语句只能跳出当前循环,使用goto语句可以直接跳出所有循环,这样就不需要在嵌套循环中再进行if判断了

例子:从一个二重循环中退出

使用break

#include <stdio.h>int main(int argc, char* argv[]) {    bool flag  = false; //设置标志位,用于判断是否退出    int sum = 0;    // 累加i*j的值,大于10就结束    for (int i=0; i<10; i++) {        for (int j=0; j<10; j++) {            sum += i*j;            if (sum > 10) {                flag = true;                break;            }        }        if (flag) {            break;        }    }    printf("sum = %d\n", sum);    return 0;}

使用goto

#include <stdio.h>int main(int argc, char* argv[]) {    int sum = 0;    // 累加i*j的值,大于10就结束    for (int i=0; i<10; i++) {        for (int j=0; j<10; j++) {            sum += i*j;            if (sum > 10) {                goto exit;            }        }    }    exit:    printf("sum = %d\n", sum);    return 0;}

很明显,goto语句能够方便的完成退出


2.为函数统一设置出口

这个就是我遇到的问题,不论退出函数时是好的结果还是坏的结果,都有可能会有一些必须执行的操作,比如释放资源,重设置标识符等。可能一个函数中会有多个出口,这样对于程序的可读性以及后续维护很不方便,使用goto可以很好的解决这个问题

不用goto

#include <iostream>#include <string.h>using namespace std;string func(const char* arg1, const char* arg2);int main(int argc, char* argv[]) {    string res;    res = func("arg1", "arg2");    cout <<"res = " <<res <<endl;    return 0;}string func(const char* arg1, const char* arg2) {    char* p1 = NULL;    p1 = (char*)malloc(sizeof(char) * strlen(arg1));    memset(p1, 0, strlen(arg1));    memcpy(p1, arg1, strlen(arg1));    char* p2 = NULL;    p2 =(char*)malloc(sizeof(char) * strlen(arg2));    memset(p2, 0, strlen(arg2));    memcpy(p2, arg2, strlen(arg2));    if (strcmp("arg1", p1) == 0) {        cout <<"arg1 ok" <<endl;        delete[] p1;        delete[] p2;        return arg1;    }    if (strcmp("arg2", p2) == 0) {        cout <<"arg2 ok" <<endl;        delete[] p1;        delete[] p2;        return arg2;    }    delete[] p1;    delete[] p2;    return "error";}


使用goto

#include <iostream>#include <string.h>using namespace std;string func(const char* arg1, const char* arg2);int main(int argc, char* argv[]) {    string res;    res = func("arg1", "arg2");    cout <<"res = " <<res <<endl;    return 0;}string func(const char* arg1, const char* arg2) {    char* p1 = NULL;    p1 = (char*)malloc(sizeof(char) * strlen(arg1));    memset(p1, 0, strlen(arg1));    memcpy(p1, arg1, strlen(arg1));    char* p2 = NULL;    p2 =(char*)malloc(sizeof(char) * strlen(arg2));    memset(p2, 0, strlen(arg2));    memcpy(p2, arg2, strlen(arg2));    string res = "error";    if (strcmp("arg1", p1) == 0) {        cout <<"arg1 ok" <<endl;        res = arg1;        goto exit;    }    if (strcmp("arg2", p2) == 0) {        cout <<"arg2 ok" <<endl;        res = arg2;        goto exit;    }    exit:    delete[] p1;    delete[] p2;    return res;}

将同一个函数中的所有出口统一到一起,可读性提高,同时方便今后修改


#############################################################


Java中将goto作为关键字,但并没有给它赋予任何功能,但在Java中也有可替代goto功能的语句,就是带标签的break和带标签的continue语句

参考:Alternative to a goto statement in Java - http://stackoverflow.com/questions/2430782/alternative-to-a-goto-statement-in-java/2430829#2430829


带标签的break语句

语法:

break 标签名;


同时程序中还有另外一条语句

标签名:


注意:第二条语句必须放在希望跳出的语句块之前,并且必须紧跟一个分号,同时语句块中必须包含带标签的break语句,所以该语句仅能作为跳出语句块的操作。语句块可以使多重循环,也可以是if语句,for语句或者{}块语句。


一个简单的例子:输入数字,小于等于0则退出

package com.zj;import java.util.Scanner;public class Main {    public static void main(String[] args) {// write your code here        Scanner in = new Scanner(System.in);        int n = 0;        read_data:        while (true) {            while (true) {                System.out.print("Enter a number >= 0:");                n = in.nextInt();                if (n <= 0)                    break read_data;            }        }        if (n < 0) {            System.out.println("n < 0");        } else if (n == 0) {            System.out.println("n == 0");        }    }}


还有一个continue加标签的用法,用于退出当前循环,继续上层循环,想要了解的可以查找相关资料

0 0
原创粉丝点击