所以当我遇到这段C代码时,我正准备在印度参加入学考试
#include <stdio.h>
int main(void) {
static int i = 4;
if (--i) {
main();
printf("%d", i);
}
}
我认为printf
语句永远不会被执行,输出将是空白的。
但是我看到答案是0000
,并且这是因static
关键字int
而发生的。
任何人都可以解释为什么printf执行或者那个人错了吗?
答案 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 ......