递归和静态变量

时间:2017-08-01 19:01:29

标签: c recursion

所以当我遇到这段C代码时,我正准备在印度参加入学考试

#include <stdio.h>
int main(void) {
    static int i = 4;
    if (--i) {
        main();
        printf("%d", i);
    }
}

我认为printf语句永远不会被执行,输出将是空白的。 但是我看到答案是0000,并且这是因static关键字int而发生的。

任何人都可以解释为什么printf执行或者那个人错了吗?

5 个答案:

答案 0 :(得分:29)

在关于递归的问题的上下文中,它将打印出“000”(我不知道为什么答案显示4个零,因为' - i'减量在分配之前发生)。如果您展开电话,您将获得:

if (--i) { //i == 3
    if (--i) { //i == 2
        if (--i) { //i == 1
            if (--i) { //i == 0
                // rest does not get evaluated since the condition is false
            }
            printf("%d", i); // i is 0 now
        }
        printf("%d", i); //i is still 0
    }
    printf("%d", i); //i is still 0
}

但是大多数人都提到这个代码很糟糕,我建议你永远不要考虑你写的任何软件的这种程度的邋。。

答案 1 :(得分:22)

在C * main递归是合法的(虽然你为什么?)

此外,C11(5.1.2.2.1)规定:

  

应定义返回类型为int ... [或]如果返回类型与int不兼容,则   返回到主机环境的终止状态未指定。

(C ++声明返回类型必须为int

所以代码的这部分实际上是符合标准的,但实际的返回是实现定义的(感谢@chux)

  

任何人都可以解释为什么printf执行或者那个人错了吗?

如果你用C ++编译器编译C,那就错了。否则代码将编译。

现在这已经不在了,printf确实会执行,因为static变量只被初始化一次,根据6.2.4 / 3

  

一个对象,其标识符与...一起声明   存储类说明符static具有静态存储持续时间。它的一生就是整个   程序执行程序及其存储的值仅在程序之前初始化一次   启动

*在C ++中绝对不合法。来自[basic.start.main]:  &#34;函数main不得在程序中使用&#34;。在这个答案中有很多C ++,因为这个问题最初被标记为C ++并且信息很有用

答案 2 :(得分:13)

  

任何人都可以解释为什么printf执行或者那个人错了吗?

因为main返回。

This answer写出了逻辑,但我发现你仍然在评论中提出这个问题。所以我将以不同的方式说同样的事情,并希望你更清楚。

因为变量是static,所以在第一次调用之前,声明变量并将其设置为4.因为它是static,所以每次都会使用相同的变量。如果再次调用它,它只是跳过声明和初始化(或者甚至可能是第一次,因为static变量可以在运行之前分配)。

在第一次调用中,变量递减为3. 3是真值,因此我们执行if的块。这会递归调用main

在第二次调用中,变量递减为2. 2在C中仍然是真实的。我们再次递归地调用main

在第三次调用中,变量递减为1. 1仍然是真的。我们再次递归到main

在第四次调用中,变量递减到0. 0在C中为假。我们不输入if的块。我们不会递归。我们不打印。在对main的此次调用中,没有什么可做的。它最后返回。

现在我们又回到了第三次通话中。我们刚从电话main回来了。我们仍然在if区块内。下一个语句是printf。变量的值现在为0.所以我们打印一个0.没什么可做的,我们最后返回。

现在我们又回到了第二次通话中。仍为0,所以我们再打印0并返回。

现在我们回到了第一个电话。仍为0,所以我们再打印0并返回。

我们打印了3次,所以000

正如您所说,在下来的路上,我们不打印。我们在回来的路上打印。到那时,变量为0.然后我们输入if的then块三次。所以我们递归然后再打印三次。

当您递归调用函数时,不会消除之前的调用。你把它放在堆栈上。完成后,您将返回到您离开的地方并继续下一个声明。

您可能想要考虑以下三段代码的反应方式:

void recurse() {
    static int i = 4;
    if (--i) {
        recurse();
        printf("%d", i);
    }
}

第一次打电话时打印000。之后什么都不做。

void recurse(int i) {
    if (--i) {
        recurse(i);
        printf("%d", i);
    }
}

如果调用recurse(4),将打印123。作为参数,我们每次调用函数时都会处理不同的i

void recurse(int i) {
    if (--i) {
        printf("%d", i);
        recurse(i);
    }
}

如果调用recurse(4),则打印321。在下来的路上打印而不是在返回时打印。

void recurse(int i) {
    printf("%d", i);
    if (--i) {
        recurse(i);
    }
}

如果被称为recurse(4)则打印4321。它打印下来,而不是向上。

void recurse() {
    static int i = 4;
    printf("%d", i);
    if (--i) {
        recurse();
    }
}

将打印4321.我们正在打印,而不是向上打印。请注意参数和static变量如何以这种方式给出相同的结果。但是,如果这是第二次调用,它将不执行任何操作。该参数将再次打印相同的内容。

void recurse() {
    int i = 4;
    if (--i) {
        recurse();
        printf("%d", i);
    }
}

永远循环。如果没有static,我们每次都会制作一个新的i。这将一直运行,直到它重载堆栈并崩溃。没有输出,因为它永远不会进入printf

检查这个问题的最简单方法是去ideone.com,然后运行代码。询问为什么它打印的东西对于这个网站来说是合理的。但是询问它打印的内容是你应该自己回答的问题。

答案 3 :(得分:7)

此代码中存在多个问题:

  • <stdio.h>未包含在内,调用printf("%d", i);的行为未定义。

  • main没有参数的原型是int main(void)。将main定义为void main()在某些平台上不可移植且不正确。始终使用main的标准原型并返回有效退出状态以获得良好的风格。

  • 在C中递归调用main函数是不好的,它在C ++中有未定义的行为。

忽略未定义行为意味着任何事情都可能发生的事实,包括印度公司使用可怕的编程测试,程序打印0000的原因是您可能错误地输入了if (i--)测试或错误地将内存中的大括号,或者这个家伙是完全错的。 main函数每次递归调用自身3次递减相同的i变量,直到它变为0并且每个实例打印i的值,即0在它返回其调用者之前,包括main()的初始调用。

函数内的

static int i = 4;定义了一个全局变量i,其初始值为4,只能在定义它的块内访问。 main的所有递归实例都访问同一个变量。

答案 4 :(得分:6)

从该功能的质量和名称中抽象出来。

所有static变量在程序启动期间仅初始化一次,并保持其值。

当启动例程第一次调用main时,变量i的值为4.然后将其值减小为3并再次调用main。这次i的值为3然后将其值减小为2 ......