没有goto跳转进出循环的更好方法?

xiv*_*r77 2 c c++ goto

do {
    int j, k;
    if (num_copy_array[0][0] == num_copy_array[0][1]) {
        goto next_num;
    } else {
        goto first_time;
    }
    for (j = 0; j < ARRAY_LEN; j++) {
        for (k = 0; k < NUM_LEN; k++) {
            goto skip;
        first_time:
            j = 0, k = 2;
        skip:
            for (int j_2 = 0; j_2 <= j; j_2++) {
                for (int k_2 = 0; k_2 <= NUM_LEN; k_2++) {
                    if (j_2 == j && k_2 == k) {
                        goto next_digit;
                    }
                    if (num_copy_array[j][k] == num_copy_array[j_2][k_2]) {
                        goto next_num;
                    }
                }
            }
        next_digit:;
        }
    }
} while (false);
/*
 * some
 * code
*/
:next_num // starts the bigger loop outside
Run Code Online (Sandbox Code Playgroud)

这就是我在编写c ++程序时创建一个特殊的循环入口并打破多个循环的结果.我必须将循环变量'j,k'声明为外部,以便在使用goto跳入循环之前声明它们,并使用伪do循环来本地化这些变量.

这么多人都说"从不使用goto",我同意使用不必要的getos会产生一个不好的程序.但是在这种情况下,我很难想到一个替代方法,而不是使用临时切换变量并在每个循环入口处检查它们,这种方式我认为效率非常低且难以阅读.

你能想出一个很好的方法让我的程序更好,或者你有一个一般性的建议吗?

Joh*_*ica 9

短的anwer

将代码分解为函数.您可以goto明智地使用辅助方法和快速返回来替换这些.Helper方法是管理四重嵌套循环和snaking gotos 的复杂性的好方法.他们还将通过为各种运动部件命名来揭示算法的基本逻辑.

答案很长:

由于@MooingDuck在他的评论中破译,此代码的唯一外部效果是正常退出循环或通过跳转到next_num标签退出.

考虑到这一点,第一步是将循环移动到一个函数,该函数返回truefalse控制是否执行"某些代码".

if (should_execute_some_code()) {
    /*
     * some
     * code
     */
}

// starts the bigger loop outside
Run Code Online (Sandbox Code Playgroud)

在函数内部,我们将任何goto next_num行转换为return true,否则return false如果控制从函数的底部掉落.

bool should_execute_some_code()
{
    int j, k;
    if (num_copy_array[0][0] == num_copy_array[0][1]) {
        return true;
    }

    goto first_time;

    for (j = 0; j < ARRAY_LEN; j++) {
        for (k = 0; k < NUM_LEN; k++) {
            goto skip;
        first_time:
            j = 0, k = 2;
        skip:
            for (int j_2 = 0; j_2 <= j; j_2++) {
                for (int k_2 = 0; k_2 <= NUM_LEN; k_2++) {
                    if (j_2 == j && k_2 == k) {
                        goto next_digit;
                    }
                    if (num_copy_array[j][k] == num_copy_array[j_2][k_2]) {
                        return true;
                    }
                }
            }
        next_digit:;
        }
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

那是一个开始.现在我们怎样摆脱其余的东西呢?让我们来解决这个问题first_time.无需无条件地跳入循环内部.它不漂亮,但我们可以用条件初始化替换跳转k.2在第一次迭代时将其设置为其0后.这让我们摆脱了first_timeskip标签.

bool should_execute_some_code()
{
    int j = 0, k = 2;

    if (num_copy_array[0][0] == num_copy_array[0][1]) {
        return true;
    }

    for (int j = 0; j < ARRAY_LEN; j++) {
        for (int k = (j == 0 ? 2 : 0); k < NUM_LEN; k++) {
            for (int j_2 = 0; j_2 <= j; j_2++) {
                for (int k_2 = 0; k_2 <= NUM_LEN; k_2++) {
                    if (j_2 == j && k_2 == k) {
                        goto next_digit;
                    }
                    if (num_copy_array[j][k] == num_copy_array[j_2][k_2]) {
                        return true;
                    }
                }
            }
        next_digit:;
        }
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

接下来是next_digit标签.如果j == j_2k == k_2你想要停止内部两个循环.这可以通过更具选择性的循环条件而不是a来控制goto.

bool should_execute_some_code()
{
    if (num_copy_array[0][0] == num_copy_array[0][1]) {
        return true;
    }

    for (int j = 0; j < ARRAY_LEN; j++) {
        for (int k = (j == 0 ? 2 : 0); k < NUM_LEN; k++) {
            for (int j_2 = 0; j_2 <= j; j_2++) {
                for (int k_2 = 0; k_2 <= NUM_LEN && !(j_2 == j && k_2 == k); k_2++) {
                    if (num_copy_array[j][k] == num_copy_array[j_2][k_2]) {
                        return true;
                    }
                }
            }
        }
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)

在这一点上,它看起来像你在检查二维数组中的任何条目是否等于二维数组中的任何其他条目.而且你要小心忽略检查同一个单元格.好吧.现在让我们知道它的功能,重命名这个功能.让我们通过引入第二个辅助函数来拆分四个嵌套循环.

bool has_duplicate_entry()
{
    if (num_copy_array[0][0] == num_copy_array[0][1]) {
        return true;
    }

    for (int j = 0; j < ARRAY_LEN; j++) {
        for (int k = (j == 0 ? 2 : 0); k < NUM_LEN; k++) {
            if (contains_entry(num_copy_array[j][k], j, k)) {
                return true;
            }
        }
    }

    return false;
}

bool contains_entry(int entry, int not_j, int not_k)
{
    for (int j = 0; j <= not_j; j++) {
        for (int k = 0; k <= NUM_LEN && !(j == not_j && k == not_k); k++) {
            if (num_copy_array[j][k] == entry) {
                return true;
            }
        }
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)