1

在我当前的项目中,我偶然发现了一个奇怪的现象,即嵌套的 for 循环只会执行一次内部循环,然后就停止。即使仔细检查了所有涉及的变量,外部 for 循环仍然无故终止。使这种构造与我的程序中包含的其他 for 循环不同的唯一一点是,计数器变量作为参数传递给包含循环的函数,并且从未复制到任何地方。

所以我决定测试一下问题是否可以重现:

#include <stdio.h>

void someFunction(int x, int y, int width, int length)
{
    int endX = x+width;
    int endY = y+length;

    printf("x will not exceed: %i\n", endX);
    printf("y will not exceed: %i\n", endY);

    for(; x < endX; x++)
    {
        for(; y < endY; y++)
        {
            printf("(%i, %i)\n", x, y);
        }
    }
}

int main(int argc, const char *argv[])
{
    someFunction(1, 1, 5, 5);
    return 0;
}

然而,在执行时,应用程序的输出与直观的预期不同:

x will not exceed: 6
y will not exceed: 6
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)

切换 x 和 y 时的行为类似,但 y 变量从不递增。这个问题通过简单地声明一个新变量作为每个循环的计数器来解决。

但是为什么会这样呢?是否因特定原因而被禁止?编译器是否禁用对某些参数的修改,如果是,为什么它对一个变量起作用,而对另一个变量不起作用?

提供的源代码是用 GCC/G++ 4.5.3 编译的,没有任何特殊的优化标志。

4

2 回答 2

13

y永远不会在x循环中被重置,所以一旦它在第一次通过时越界,它就会永远保持在界外。

于 2012-08-08T18:24:17.813 回答
2

由于xandy也存在于循环之外,并且由于循环没有设置它们的初始值,因此即使重用它们也会保留最后一个值。这尤其是关于您的y, 在 y 循环退出后不会回退到初始值。

为避免此类问题,请避免使用循环外部的变量作为索引。

void someFunction(const int x, const int y, const int width, const int length)
{
    int endX = x+width;
    int endY = y+length;

    printf("x will not exceed: %i\n", endX);
    printf("y will not exceed: %i\n", endY);

    for(int ix=x; ix < endX; ++ix)
    {
        for(int iy=0; iy < endY; ++iy)
        {
            printf("(%i, %i)\n", ix, iy);
        }
    }
}

在这里,通过使参数 const 我们确保我们不能触摸它们,即使是错误的。然后我们使用循环本地的 ix 和 iy 来处理迭代。

此外,除非出于其他原因必须避免使用后缀增量,并使用前缀。在您使用整数之前,这并不是一个很大的变化,但是使用更复杂的变量可以有所作为。

如果您避免像 C 程序员那样编写代码,这也是一个好主意(因为您将问题标记为C++而不是)。C

惯用的 C++ 等价物是这样的:

#include <iostream>

void someFunction(const int& x, const int& y, const int& width, const int& length)
{
    const int endX = x+width;
    const int endY = y+length;

    std::cout << "x will not exceed: " << endX << std::endl;
    std::cout << "y will not exceed: " << endY << std::endl;

    for(int ix=x; ix < endX; ++ix)
    {
        for(int iy=y; iy < endY; ++iy)
        {
            std::cout << '('<<ix<<", "<<iy<<')'<< std::endl;    
        }
    }
}

int main()
{
    someFunction(1, 1, 5, 5);
    return 0;
}
于 2012-08-08T18:45:32.110 回答