任务:打印从1到1000的数字,不使用任何循环或条件语句。不要只写printf()或cout语句1000次。
用C或c++怎么做呢?
任务:打印从1到1000的数字,不使用任何循环或条件语句。不要只写printf()或cout语句1000次。
用C或c++怎么做呢?
当前回答
以下是我知道的三个解决方案。不过,第二种说法可能存在争议。
// compile time recursion
template<int N> void f1()
{
f1<N-1>();
cout << N << '\n';
}
template<> void f1<1>()
{
cout << 1 << '\n';
}
// short circuiting (not a conditional statement)
void f2(int N)
{
N && (f2(N-1), cout << N << '\n');
}
// constructors!
struct A {
A() {
static int N = 1;
cout << N++ << '\n';
}
};
int main()
{
f1<1000>();
f2(1000);
delete[] new A[1000]; // (3)
A data[1000]; // (4) added by Martin York
}
[编辑:(1)和(4)只能用于编译时常数,(2)和(3)也可以用于运行时表达式-结束编辑。]]
其他回答
显然需要Windows/Visual Studio…但它确实有效。
#include <stdio.h>
#include <Windows.h>
void print(int x)
{
int y;
printf("%d\n", x);
__try
{
y = 1 / (x - 1000);
print(x + 1);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return;
}
}
void main()
{
print(1);
}
我不想破坏它,但递归和循环在机器级别本质上是相同的事情。
区别在于JMP/JCC与CALL指令的使用。两者都有大致相同的周期时间,并刷新指令管道。
我最喜欢的递归技巧是手工编写返回地址的PUSH,并对函数使用JMP。然后函数正常工作,并在结束时返回,但返回到其他地方。这对于更快地解析非常有用,因为它减少了指令管道刷新。
最初的海报可能是一个完整的展开,这是模板的人想出的;或者将页内存放入终端,如果您确切地知道终端文本存储在哪里。后者需要大量的洞察力和风险,但几乎不需要计算能力,并且代码没有像连续1000个打印文件那样的麻烦。
Manglesky的解决方案很棒,但还不够模糊。: -):
#include <stdio.h>
#define TEN(S) S S S S S S S S S S
int main() { int i = 1; TEN(TEN(TEN(printf("%d\n", i++);))) return 0; }
尽管在这里看到了所有出色的代码,但我认为唯一真正的答案是它不能实现。
为什么?简单。事实上,每一个答案都是循环的。隐藏为递归的循环仍然是循环。看一下汇编代码就会发现这一事实。即使读取和打印带有数字的文本文件也涉及循环。再看一下机器代码。输入1000个printf语句也意味着循环,因为printf本身也有循环。
不可能做到。
我重新制定了比尔提出的伟大惯例,使其更加普遍:
void printMe ()
{
int i = 1;
startPrintMe:
printf ("%d\n", i);
void *labelPtr = &&startPrintMe + (&&exitPrintMe - &&startPrintMe) * (i++ / 1000);
goto *labelPtr;
exitPrintMe:
}
更新:第二种方法需要2个功能:
void exitMe(){}
void printMe ()
{
static int i = 1; // or 1001
i = i * !!(1001 - i) + !(1001 - i); // makes function reusable
printf ("%d\n", i);
(typeof(void (*)())[]){printMe, exitMe} [!(1000-i++)](); // :)
}
对于这两种情况,都可以通过简单地调用来启动打印
printMe();
已为GCC 4.2测试。