当前位置: 首页 > 知识库问答 >
问题:

for循环在切换情况之间分裂的行为

晏富
2023-03-14

在玩代码时,我注意到一个奇怪的行为,我不知道如何解释背后的逻辑

void foo(int n)
{
    int m = n;
    while (--n > 0)
    {
        switch (n)
        {
            case -1:
            case 0:
                for (int j = 0; j < m; ++j)
            default:
                    printf(":-)");
                break;
        }
    }
}

int main()
{
    foo(10);
    return 0;
}

我希望printf执行10次。然后我看到它继续运行(想象是100000而不是10),并且假设开发人员(VS)将中的printf解释为(这是意料之中的),因此每次进入switch时输出都是n次。

但后来证明j从未初始化。

所以我的问题是为什么?这是一种未定义的行为吗?这不是一个标准的代码吗?

共有2个答案

花博厚
2023-03-14

switch块实际上是一组美化的goto语句。不同的案例没有给代码引入作用域或任何逻辑结构。它们实际上只是switch语句要跳转到的目标。

在此程序中,default:标签位于嵌套的for循环内。当default大小写被命中时,程序在循环内跳转,就好像那里有goto语句一样。开关块等效于:

if (n == -1 || n == 0) {
    goto before_loop;
}
else {
    goto inside_loop;
}

before_loop:
for (int j = 0; j < m; ++j) {
    inside_loop:
    printf(":-)");
}

这是危险的,因为跳转到inside_loop:会跳过j=0。正如您所观察到的,j仍然声明了,但没有初始化,访问它会导致未定义的行为。

刘胜泫
2023-03-14

default只是一个标签(如果n不是-1或0,则代码跳转到的地址)。因此,当n不是-1或0时,流进入for循环的主体,跳过j的初始化。您也可以编写与此相同的代码,因此这里发生的事情会更清楚:

int m = n;
while (--n > 0)
{
    switch (n)
    {
        case -1:
        case 0:
            for (int j = 0; j < m; ++j)
            {
        default: printf(":-)");
            }
            break;
    }
}

(注意,正如@Alagner在评论中提到的,它不会用C++编译器编译,但可以用C语言完美地编译,所以这足以说明我的观点并解释代码的外观)。

所以是的,因为j是未初始化的,所以它是未定义的行为。如果启用编译器警告,它将对您发出警告(https://godbolt.org/z/rzgrap):

warning: 'j' may be used uninitialized in this function [-Wmaybe-uninitialized]
   12 |                 for (int j = 0; j < m; ++j)
      |                          ^                  
 类似资料:
  • 我在运行Windows XP sp3的计算机上安装了Java 6和Java 7。我已在计算机中的环境变量(path、JAVA_HOME)中输入path- java-版本 我还是收到下面的短信 Java版本"1.7.0_09"Java(TM)SE运行时环境(构建1.7.0_09-b05)JavaHotSpot(TM)客户端VM(构建23.5-b02,混合模式,共享) 然而,当我尝试 javac-版本

  • 我有 我想要 在JS我可以做 像这样简单的方法之一 围棋里有这样的东西吗?

  • 问题内容: 目前,我正在此站点上抓取图表图表信息。要抓取信息,我需要为有很多镜头的情况做一个for循环。我可以通过单击“ Team Stats”并找到射门次数来找到射门次数。 我想做出适当的选择而不必找出拍摄数量。 我目前正在做什么: 任何帮助将不胜感激。请让我知道是否需要进一步的信息。 问题答案: 我不确定您的变量k是什么意思。 我从所有评论中获得了建议。

  • 问题内容: 以下两个循环之间的性能差异(如果有)是什么? 和 问题答案: 版本1.5中引入的for-each循环通过完全隐藏迭代器或index变量,消除了混乱和出错的机会。结果成语同样适用于集合和数组: 当你看到冒号(:)时,将其读为“ in”。因此,上面的循环读为“对于元素中的每个元素e”。请注意,即使对于数组,使用for-each循环也不会降低性能。实际上,在某些情况下,它可能只比普通的for

  • 我想有开关情况循环我的九个菜单,在那里我可以在任何给定的一个和菜单跳转到下一个随机选择,现在它目前旋转的顺序,无论我在哪里点击。

  • 我有一个非常基本的函数,它搜索的数组列表,并返回与传递给它的参数匹配的帐户。但是,一旦抛出CustomerAccountNotFoundException,我的for循环就会中断。 我通过在异常后打印的值来测试这一点,该值一直被重置为0。如何在抛出异常后继续循环?我希望每次帐户不匹配时都抛出它,当它匹配时返回帐户。我还尝试过但不起作用。