stackoverflow | C/C++ | 如何不使用循环和判断语句实现“打印从1到100之间的数字”
原文链接:http://www.keepsimply.org/2012/08/11/printing-1-to-1000-without-loop-or-conditionals/
作者:独酌逸醉
时间:2012.08.11
声明:翻译仅以技术学习和交流为目的,如需转载请务必标明原帖链接。
来源:http://stackoverflow.com/questions/4568645/printing-1-to-1000-without-loop-or-conditionals
水平有限,如有翻译不当,欢迎探讨、批评与指正。
任务:
不使用循环和条件判断语句“打印从1到100之间的数字”。不要使用 1000 个printf 或者 cout 哦,O(∩_∩)O~。
如果是你,你将怎么用 C 或者 C++ 语言实现呢?
方法一:
#include <iostream> template<int N> struct NumberGeneration { static void out(std::ostream& os) { NumberGeneration<N-1>::out(os); os << N << std::endl; } }; template<> struct NumberGeneration<1> { static void out(std::ostream& os) { os << 1 << std::endl; } }; int main() { NumberGeneration<1000>::out(std::cout); }
译者注:这是利用模板编译时的递归来实现的,会消耗编译时间。存在一个问题就是,不同的编译器对模板递归编译的层数有限制。这个问题,有人跟帖也说了。默认情况下 g++ 的递归深度是 500. 我用 Code::blocks 10.05 和 visual studio 2010 分别进行测试,CB 编译失败,VS2010可成功编译和运行。把参数改成 501 之后(也就是说递归编译层数是500),CB也可以成功编译和运行。
方法二:
#include<stdio.h> int b = 1; int printS() { printf("%d\n", b); b++; return (1001-b) && printS(); } int main() { printS(); }
方法三:
OpenMP 版(非命令行方式):
#include <iostream> #include <omp.h> int main(int argc, char** argv) { #pragma omp parallel num_threads(1000) { #pragma omp critical { std::cout << omp_get_thread_num() << std::endl; } } return 0; }
(在VS2010 OpenMP 运行时库下无法执行(64个线程的限制),在linux下可以运行,比如 Inter 编译器)。
下面是一个命令行方式的版本:
#include <stdio.h> #include <omp.h> int main(int argc, char *argv[]) { int i = 1; #pragma omp parallel num_threads(1000) #pragma omp critical printf("%d ", i++); return 0; }
译者注:我没有接触过 OpenMP ,不敢妄加揣测。如果有熟悉的朋友可以帮忙测试一下,测试完把结果告诉我一下,不胜感激。
方法四:
#include <stdio.h> #include <stdlib.h> int numbers[501] = {0}; int comp(const void * a, const void * b){ numbers[0]++; printf("%i\n", numbers[0]); return 0; } int main() { qsort(numbers+1,500,sizeof(int),comp); comp(NULL, NULL); return 0; }
译者注:原帖参数是 51,我想应该是 501。
想搞懂原因,就要去分析这里面的 qsort 是怎么执行的,
假设我们要打印1~5,numbers初始序列应该是:0,0,0,0,0,0,程序中实现的是第一个元素的递增,每次比较的时候,打印第一个元素。也就是说其实打印到那个值,取决于调用 comp 的次数。假设qsort选取第一个元素为轴,那么比较次数应该是 4+3+2=9,加上 main 函数中,qsort执行后的一次 comp 调用,4+3+2+1=10。假如轴的选取不是第一个元素,那么比较次数应该是多少呢?读者自己分析吧。
方法五:
printf("打印从1到100之间的数字");
译者注:这个答案亮,但是谁能说它是错的呢?!
方法六:
#include <iostream> #include <stdexcept> #include <cstdio> using namespace std; int main(int arg) { try { printf("%d\n",arg); int j=1/(arg-1000); main(arg+1); } catch(...) { exit(1); } }
译者注:code::blocks 10.05 不能通过编译(VS2010可以),很显然是因为 exit 的缘故,去掉就可以了。这种方法靠除 0 错引起异常,结束递归,以程序的崩溃而告终,^_^。
方法七:
#include <iostream> static int n = 1; class number { public: number () { std::cout << n++ << std::endl; } }; int main(int argc, char* argv[]) { number X[1000]; return 0; }
方法八:
#include <stdio.h> #include <stdlib.h> static int x(/*@unused@*/ const char * format, ...) { exit(0); } static void p(int v, int e) { static int (*a[])(const char *, ...) = { printf, x }; (void)a[v/(e+1)]("%d\n", v); p(v+1, e); } int main(void) { p(1, 1000); return 0; }
译者注:看似复杂,其实非常简单。a[] 是一个函数指针数组,a[0] = printf ; a[1] = x 。当 v/(e+1) = 0 时,调用 printf 打印数字。当 v/(e+1) = 1 时,调用 x ,跳出递归。
方法九:
#include <iostream> using namespace std; template<int N> void func() { func<N-1>(); cout << N << "\t"; } template<> void func<1>() { cout << 1 << "\t"; } int main() { func<1000>(); cout << endl; return 0; }
译者注:和方法一有点像是吧?嗯,原理一样,只不过方法一是类模板,方法九是函数模板。
方法十:
#include <stdio.h> #define sign(x) (( x >> 31 ) | ( (unsigned int)( -x ) >> 31 )) void (*actions[3])(int); void Action0(int n) { printf("%d", n); } void Action1(int n) { int index; printf("%d\n", n); index = sign(998-n)+1; actions[index](++n); } int main() { actions[0] = &Action0; actions[1] = 0; //Not used actions[2] = &Action1; actions[2](0); return 0; }
方法十一:
#include <stdio.h> #include <stdlib.h> void f(int j) { static void (*const ft[2])(int) = { f, exit }; printf("%d\n", j); ft[j/1000](j + 1); } int main(int argc, char *argv[]) { f(1); }
译者注:此方法和方法八有异曲同工一秒。
方法十二:
C++:
#include <iostream> using namespace std; static int i = 1; struct a { a(){cout<<i++<<endl;} ~a(){cout<<i++<<endl;} }obj[500]; int main() { return 0; }
C:
#include <stdio.h> #define c1000(x) c5(c5(c5(c4(c2(x))))) #define c5(x) c4(x) c1(x) //or x x x x x #define c4(x) c2(c2(x)) //or x x x x #define c2(x) c1(x) c1(x) //or x x #define c1(x) x int main(int i) { c1000(printf("%d\n",i++);) return 0; }
一个更简单的版本:
#include <stdio.h> #define p10(x) x x x x x x x x x x int main(int i) { p10(p10(p10(printf("%d\n",i++);))) return 0; }
方法十三:
#include <process.h> int main() { system("cmd.exe /c for /l %x in (1, 1, 1000) do echo %x" ); }
译者注:依赖于 Windows 平台,CB不能通过编译,VS2010可正常编译和运行。
方法十四:
#include <stdio.h> int i=1; void x10( void (*f)() ) { f(); f(); f(); f(); f(); f(); f(); f(); f(); f(); } void I(){printf("%i ", i++);} void D(){ x10( I ); } void C(){ x10( D ); } void M(){ x10( C ); } int main(){ M(); }
方法十五:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef void(*word)(int); word words[1024]; void print(int i) { printf("%d\n", i); words[i+1](i+1); } void bye(int i) { exit(0); } int main(int argc, char *argv[]) { words[0] = print; words[1] = print; memcpy(&words[2], &words[0], sizeof(word) * 2); // 0-3 memcpy(&words[4], &words[0], sizeof(word) * 4); // 0-7 memcpy(&words[8], &words[0], sizeof(word) * 8); // 0-15 memcpy(&words[16], &words[0], sizeof(word) * 16); // 0-31 memcpy(&words[32], &words[0], sizeof(word) * 32); // 0-63 memcpy(&words[64], &words[0], sizeof(word) * 64); // 0-127 memcpy(&words[128], &words[0], sizeof(word) * 128); // 0-255 memcpy(&words[256], &words[0], sizeof(word) * 256); // 0-511 memcpy(&words[512], &words[0], sizeof(word) * 512); // 0-1023 words[1001] = bye; words[1](1); }
方法十六:
#include <stdio.h> int printN(int n) { printf("%d\n", n); return 1; } int print_range(int low, int high) { return ((low+1==high) && (printN(low)) || (print_range(low,(low+high)/2) && print_range((low+high)/2, high))); } int main() { print_range(1,1001); }
方法十七:
#include<stdio.h> /* prints number i */ void print1(int i) { printf("%d\n",i); } /* prints 10 numbers starting from i */ void print10(int i) { print1(i); print1(i+1); print1(i+2); print1(i+3); print1(i+4); print1(i+5); print1(i+6); print1(i+7); print1(i+8); print1(i+9); } /* prints 100 numbers starting from i */ void print100(int i) { print10(i); print10(i+10); print10(i+20); print10(i+30); print10(i+40); print10(i+50); print10(i+60); print10(i+70); print10(i+80); print10(i+90); } /* prints 1000 numbers starting from i */ void print1000(int i) { print100(i); print100(i+100); print100(i+200); print100(i+300); print100(i+400); print100(i+500); print100(i+600); print100(i+700); print100(i+800); print100(i+900); } int main() { print1000(1); return 0; }
方法十八:
printf("1 10 11 100 101 110 111 1000\n");
译者注:亮,你们都懂的!
方法十九:
#include <stdio.h> #define Out(i) printf("%d\n", i++); #define REP(N) N N N N N N N N N N #define Out1000(i) REP(REP(REP(Out(i)))); int main() { int i = 1; Out1000(i); return 0; }
译者注:
1.上文上所有代码测试环境为 Windows 7 下 Code::blocks 10.05 和 Visual Studio 2010 ,如果没有备注说明的话,代表两个环境都可通过编译,正常运行。
2.想一探具体的朋友可以去看原帖。有一些得分较低的答案我没有发上来;讨论部分我也没有发过来。毕竟帖子整理成文章是要有所取舍的,否则文章太过杂乱。这一点希望读者见谅。
3.这篇帖子我翻译的帖子中最满意的,因为我觉得很有意思。涵盖的C/C++知识面很广。有些答案很BT,但是回望那些BT的答案,又是否会思索这其中巧的地方呢?也许有人会说,开发过程中,几乎没人会这么用,研究没有多大意义。我个人认为,这些奇淫技巧的确在开发过程中,是很少用,但是这玩技术的过程,是一件很快乐的事情,而且我相信每个回帖人都会认为自己的答案是最好的,这是属于我们自己这个行业的快乐。也正因为这样,也许有人的工资不高,待遇不好,依然可以快乐的工作着。(哎,废话又多了,^_^)
好了,本文结束,感谢阅读!