不使用循环或条件语句打印1到1000

322

任务: 不使用循环或条件语句打印从1到1000的数字。不要仅仅将printf()cout语句写1000次。

您如何在C或C ++中实现这一点?


137
显而易见的答案是使用500次printf,每次打印两个数字,对吗? - James McNellis
433
打印出从1到1000的数字。 - jondavidjohn
7
:?不是一条条件语句(它是一个表达式)... - Chris Lutz
127
面试是展示自己的机会。告诉面试官:“没有循环和条件语句?小菜一碟。我可以在没有电脑的情况下做到!”然后拿出笔和笔记本。他们可能会感到困惑,但只需解释如果不能依赖内置的语言结构,你就不能假设任何东西。 - JohnFx
8
我认为有几个答案的解决方案非常聪明、有趣。我也认为,虽然这可能是一个非常糟糕的面试问题,但只要面试官真正希望考察的不是完全成型的解决方案,而是看是否考虑了 TMP 的方法或以非常规的方式使用结构,那么这个问题就有很大的价值。如果这个问题被当作单纯的“对/错”问题来使用,那么就会很糟糕,但如果被用作讨论的起点,我认为它会有很多价值。 - Michael Burr
显示剩余30条评论
106个回答

1194

这个实际上编译成了没有任何条件语句的汇编代码:

#include <stdio.h>
#include <stdlib.h>

void main(int j) {
  printf("%d\n", j);
  (&main + (&exit - &main)*(j/1000))(j+1);
}


编辑:添加'&'以便考虑地址,从而回避指针错误。

以下是使用标准C版本的代码,因为它不依赖于函数指针的算术运算:

#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);
}

17
这个答案中的代码显然既不是C语言也不是C++语言,如果我们放弃这个要求,那么任何答案都可以符合要求,因为一个假想的编译器可能会从任何输入中生成所需的程序。 - eq-
321
@PP,这个解释很冗长,但基本上,“j”最初为“1”,因为它实际上是“argc”,如果程序在没有参数的情况下被调用,则为“1”。然后,“j/1000”等于“0”,直到“j”变成“1000”,之后就是“1”了。“(exit-main)”当然是“exit()”和“main()”地址之间的差异。这意味着,“(main +(exit-main)*(j/1000))”在“j”变成“1000”之前一直是“main()”,之后就变成了“exit()”。最终结果是程序启动时调用“main()”,然后递归调用自身999次并增加“j”,最后调用“exit()”。 - Frédéric Hamidi
7
这是我见过的对C语言的滥用中最神奇的之一。但它在所有平台上都能行吗? - Qwertie
13
@Mark:这是main函数的非标准签名,你不能递归调用main函数,并且指针函数相减的结果是未定义的。 - Yakov Galka
9
是的,正如@ybungalobill所说的那样,这并不是严格符合C++规范的代码,但我必须要点赞它的疯狂程度,以及它能够在一些平台上编译和工作的事实。有时候对于“但它不符合标准!”这种观点,正确的回答是“谁在乎呢!” :) - j_random_hacker
显示剩余19条评论

784

编译时递归! :P

#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);
}

8
请问有人可以解释一下这是如何运作的吗?非常令人印象深刻。 - gath
28
@Zack:让我们现实一点,我们正在打印1000行代码,这些代码是有意避免循环而编写的。性能不是问题。 - dreamlax
42
想要编译此代码的人可以在g++中使用“-ftemplate-depth-1000”来增加模板递归深度限制。默认的模板递归深度最大为500。 - Tom
6
这句话仍然使用了条件语句:模式匹配只是一个高端版的 if。 - David K.
10
@dreamlax说:这只是我多年经验中学到的一些事情:除非你真的想刷新,否则请使用'\n',除非你确实需要i的原始值,否则请使用++i,除非你有充分的理由,否则请传递const引用。当开发人员停止考虑这些事情(或从未开始),他们迟早会遇到一个问题,在这个问题中这些细节很重要,只是他们甚至不知道可能存在这样的细节。 - sbi
显示剩余27条评论

544
#include <stdio.h>
int i = 0;
p()    { printf("%d\n", ++i); }
a()    { p();p();p();p();p(); }
b()    { a();a();a();a();a(); }
c()    { b();b();b();b();b(); }
main() { c();c();c();c();c();c();c();c(); return 0; }

我很惊讶没有人发帖提到这个,我认为这是最显而易见的方法。1000 = 5*5*5*8。


人们已经发布了这个。其他版本将数字传递给打印而不是使用全局变量,但本质上是相同的解决方案。 - Chris Lutz
1
@Chris,他们使用宏或模板表达的相同逻辑,会增加代码大小,对吧?你不如直接生成输出字符串,而不是一千个printf。 - Darius Bacon
哦,我看到Keith的答案确实生成了整个字符串,太棒了。 :) 我没注意到。 - Darius Bacon
43
很好,努力不错,但是有点奇怪你没有将8分解成222,从而使用唯一质因数分解。 - David Heffernan

298

看起来不需要使用循环

printf("1 10 11 100 101 110 111 1000\n");

1
有人可能会认为使用 copy 是作弊。 - John Dibling
13
@Johannes 其实我很确定 printf 有一个循环 :p - icecrime
1
@litb:注意,我并没有说“使用copy是作弊”。 - John Dibling
2
@John:复制就是作弊。你怀疑吗? :P - Nawaz
1
在一个从1到10的等级中,我使用二进制的几率有多大? - Jordan
显示剩余3条评论

270

这里有我知道的三种解决方案,第二个可能会被质疑。

// 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) 可以用于运行时表达式 — 修改结束. ]


5
此外,我认为短路不是一种条件语句......虽然不是一个语句,但我会说它是一种条件表达式。只要我们将条件表达式定义为“在汇编中产生条件跳转的东西”。 - Kos
5
读构造函数时我遇到了一个问题:标准要求数组中的每个项按顺序构造吗?如果构造函数具有副作用,这将很重要。我确信每个正常的编译器都会按0->1000的顺序进行循环,但我想知道是否可以反向循环并仍然符合标准...... - Joseph Garvin
6
@Joseph - 构造函数不应受个别对象初始化顺序的影响,但这是一个好问题。 - Chris Lutz
12
@Joseph 这是由 C++03 中的 12.6/3 定义的。初始化按照下标顺序进行。 - Johannes Schaub - litb
2
@Joseph:它们也按相反的顺序被销毁,因此您同样可以轻松使用析构函数 :) - j_random_hacker
显示剩余3条评论

263

我不想写1000遍printf语句!

printf("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49\n50\n51\n52\n53\n54\n55\n56\n57\n58\n59\n60\n61\n62\n63\n64\n65\n66\n67\n68\n69\n70\n71\n72\n73\n74\n75\n76\n77\n78\n79\n80\n81\n82\n83\n84\n85\n86\n87\n88\n89\n90\n91\n92\n93\n94\n95\n96\n97\n98\n99\n100\n101\n102\n103\n104\n105\n106\n107\n108\n109\n110\n111\n112\n113\n114\n115\n116\n117\n118\n119\n120\n121\n122\n123\n124\n125\n126\n127\n128\n129\n130\n131\n132\n133\n134\n135\n136\n137\n138\n139\n140\n141\n142\n143\n144\n145\n146\n147\n148\n149\n150\n151\n152\n153\n154\n155\n156\n157\n158\n159\n160\n161\n162\n163\n164\n165\n166\n167\n168\n169\n170\n171\n172\n173\n174\n175\n176\n177\n178\n179\n180\n181\n182\n183\n184\n185\n186\n187\n188\n189\n190\n191\n192\n193\n194\n195\n196\n197\n198\n199\n200\n201\n202\n203\n204\n205\n206\n207\n208\n209\n210\n211\n212\n213\n214\n215\n216\n217\n218\n219\n220\n221\n222\n223\n224\n225\n226\n227\n228\n229\n230\n231\n232\n233\n234\n235\n236\n237\n238\n239\n240\n241\n242\n243\n244\n245\n246\n247\n248\n249\n250\n251\n252\n253\n254\n255\n256\n257\n258\n259\n260\n261\n262\n263\n264\n265\n266\n267\n268\n269\n270\n271\n272\n273\n274\n275\n276\n277\n278\n279\n280\n281\n282\n283\n284\n285\n286\n287\n288\n289\n290\n291\n292\n293\n294\n295\n296\n297\n298\n299\n300\n301\n302\n303\n304\n305\n306\n307\n308\n309\n310\n311\n312\n313\n314\n315\n316\n317\n318\n319\n320\n321\n322\n323\n324\n325\n326\n327\n328\n329\n330\n331\n332\n333\n334\n335\n336\n337\n338\n339\n340\n341\n342\n343\n344\n345\n346\n347\n348\n349\n350\n351\n352\n353\n354\n355\n356\n357\n358\n359\n360\n361\n362\n363\n364\n365\n366\n367\n368\n369\n370\n371\n372\n373\n374\n375\n376\n377\n378\n379\n380\n381\n382\n383\n384\n385\n386\n387\n388\n389\n390\n391\n392\n393\n394\n395\n396\n397\n398\n399\n400\n401\n402\n403\n404\n405\n406\n407\n408\n409\n410\n411\n412\n413\n414\n415\n416\n417\n418\n419\n420\n421\n422\n423\n424\n425\n426\n427\n428\n429\n430\n431\n432\n433\n434\n435\n436\n437\n438\n439\n440\n441\n442\n443\n444\n445\n446\n447\n448\n449\n450\n451\n452\n453\n454\n455\n456\n457\n458\n459\n460\n461\n462\n463\n464\n465\n466\n467\n468\n469\n470\n471\n472\n473\n474\n475\n476\n477\n478\n479\n480\n481\n482\n483\n484\n485\n486\n487\n488\n489\n490\n491\n492\n493\n494\n495\n496\n497\n498\n499\n500\n501\n502\n503\n504\n505\n506\n507\n508\n509\n510\n511\n512\n513\n514\n515\n516\n517\n518\n519\n520\n521\n522\n523\n524\n525\n526\n527\n528\n529\n530\n531\n532\n533\n534\n535\n536\n537\n538\n539\n540\n541\n542\n543\n544\n545\n546\n547\n548\n549\n550\n551\n552\n553\n554\n555\n556\n557\n558\n559\n560\n561\n562\n563\n564\n565\n566\n567\n568\n569\n570\n571\n572\n573\n574\n575\n576\n577\n578\n579\n580\n581\n582\n583\n584\n585\n586\n587\n588\n589\n590\n591\n592\n593\n594\n595\n596\n597\n598\n599\n600\n601\n602\n603\n604\n605\n606\n607\n608\n609\n610\n611\n612\n613\n614\n615\n616\n617\n618\n619\n620\n621\n622\n623\n624\n625\n626\n627\n628\n629\n630\n631\n632\n633\n634\n635\n636\n637\n638\n639\n640\n641\n642\n643\n644\n645\n646\n647\n648\n649\n650\n651\n652\n653\n654\n655\n656\n657\n658\n659\n660\n661\n662\n663\n664\n665\n666\n667\n668\n669\n670\n671\n672\n673\n674\n675\n676\n677\n678\n679\n680\n681\n682\n683\n684\n685\n686\n687\n688\n689\n690\n691\n692\n693\n694\n695\n696\n697\n698\n699\n700\n701\n702\n703\n704\n705\n706\n707\n708\n709\n710\n711\n712\n713\n714\n715\n716\n717\n718\n719\n720\n721\n722\n723\n724\n725\n726\n727\n728\n729\n730\n731\n732\n733\n734\n735\n736\n737\n738\n739\n740\n741\n742\n743\n744\n745\n746\n747\n748\n749\n750\n751\n752\n753\n754\n755\n756\n757\n758\n759\n760\n761\n762\n763\n764\n765\n766\n767\n768\n769\n770\n771\n772\n773\n774\n775\n776\n777\n778\n779\n780\n781\n782\n783\n784\n785\n786\n787\n788\n789\n790\n791\n792\n793\n794\n795\n796\n797\n798\n799\n800\n801\n802\n803\n804\n805\n806\n807\n808\n809\n810\n811\n812\n813\n814\n815\n816\n817\n818\n819\n820\n821\n822\n823\n824\n825\n826\n827\n828\n829\n830\n831\n832\n833\n834\n835\n836\n837\n838\n839\n840\n841\n842\n843\n844\n845\n846\n847\n848\n849\n850\n851\n852\n853\n854\n855\n856\n857\n858\n859\n860\n861\n862\n863\n864\n865\n866\n867\n868\n869\n870\n871\n872\n873\n874\n875\n876\n877\n878\n879\n880\n881\n882\n883\n884\n885\n886\n887\n888\n889\n890\n891\n892\n893\n894\n895\n896\n897\n898\n899\n900\n901\n902\n903\n904\n905\n906\n907\n908\n909\n910\n911\n912\n913\n914\n915\n916\n917\n918\n919\n920\n921\n922\n923\n924\n925\n926\n927\n928\n929\n930\n931\n932\n933\n934\n935\n936\n937\n938\n939\n940\n941\n942\n943\n944\n945\n946\n947\n948\n949\n950\n951\n952\n953\n954\n955\n956\n957\n958\n959\n960\n961\n962\n963\n964\n965\n966\n967\n968\n969\n970\n971\n972\n973\n974\n975\n976\n977\n978\n979\n980\n981\n982\n983\n984\n985\n986\n987\n988\n989\n990\n991\n992\n993\n994\n995\n996\n997\n998\n999\n1000\n");

不客气 ;)


223
希望你编写了一个程序来生成那行代码。 - Martin York
32
打开一个名为“1000.c”的文件,并以写入模式进行操作。将格式化字符串“printf("%s")”的参数替换为从1到999的数字组成的字符串列表,每个数字都转换为字符串类型并用换行符分隔。最后将该字符串写入到文件中。 - Tyler Eaves
53
希望你编写生成那行文字的程序没有使用循环! - Jeeyoung Kim
20
一个Vim宏可以快速完成这项工作。 - StackedCrooked
2
一点 Perl 可以用炫酷的方式生成它:$r='printf("'; for (1..1000) { $r.="$_\\n" } $r.='");'; print $r; - sidyll
显示剩余3条评论

212
printf("%d\n", 2);
printf("%d\n", 3);

它并没有打印出所有的数字,但是它确实“打印从1到1000的数字。”模棱两可的问题获胜! :)


77
我最喜欢的是在“printf(“数字从1到1000”)”之后 - 愚蠢的问题需要愚蠢的回答。 - SEngstrom
这太棒了。+1 因为利用了问题中的歧义。哈哈 - Nawaz
2
编辑过;这段代码print "打印从1到1000的数字。"绝对没有任何歧义的问题,不准确的描述真糟糕 :) - sehe
哇,最近这个问题的答案遭到了一些破坏。有些迹象表明我们应该将其锁定为历史性锁定。 - BoltClock

172

触发一个致命错误!这是文件countup.c:

#include <stdio.h>
#define MAX 1000
int boom;
int foo(n) {
    boom = 1 / (MAX-n+1);
    printf("%d\n", n);
    foo(n+1);
}
int main() {
    foo(1);
}

编译后,在shell提示符下执行:

$ ./countup
1
2
3
...
996
997
998
999
1000
Floating point exception
$

这确实打印出从1到1000的数字,没有任何循环或条件语句!


43
每次使用printf()之后,您应该调用fflush(stdout)以刷新输出缓冲区。程序崩溃时,无法保证输出缓冲区的内容会被打印到屏幕上。 - zakk
10
这并不是必需的 - 默认情况下,标准输出是行缓冲的,因此\n就足以清空输出。 - psmears
24
如果可以确定stdout是交互设备,则其是行缓冲的;否则它是完全缓冲的。如果教授将stdout重定向到文件以进行自动化检查,你将会失败 :-) - paxdiablo
堆栈溢出的危险(例如在嵌入式环境中) - Hernán Eche

166

使用系统命令:

system("/usr/bin/seq 1000");

15
高概率/usr/bin/seq在内部使用了一个循环。 :) - user142019
@jokester: 你的意思是,因为Solaris/BSD默认没有seq工具吗?<grin/> - sehe
我很不想说这个(好吧,其实我不介意),但是你的解决方案中有一个错误。它没有打印出正确的数字集合。 :)这是修复方法:system("/bin/echo {1..1000}");如果你先写了单元测试就好了... - Don Branson
1
有些聪明的家伙决定更改了我的答案,所以那不是我的错误。 - moinudin

100

未经测试,但应该是标准的 C 代码:

void yesprint(int i);
void noprint(int i);

typedef void(*fnPtr)(int);
fnPtr dispatch[] = { noprint, yesprint };

void yesprint(int i) {
    printf("%d\n", i);
    dispatch[i < 1000](i + 1);
}

void noprint(int i) { /* do nothing. */ }

int main() {
    yesprint(1);
}

29
@Prasoon:它是一种关系。 - Yakov Galka
28
请将英语翻译成中文。仅返回已翻译的文本:要求“不使用条件句”(if、switch等)。而非“没有条件”。 - jon_darkstar
32
< 不是条件语句,它是一个关系运算符。if / else 是一种条件语句,而 ?: 则是一个条件运算符。< 只是一种返回布尔值的运算符。它可能只是一条机器指令,没有跳转或其他任何内容。 - Chris Lutz
12
在x86上,需要执行3条指令:cmplsetlemovzbl。在x86-64上,需要执行这些指令以及cltq指令。在PowerPC上,需要执行2条指令:cmpwicrnot - Adam Rosenfield
4
1 - i / 1000。 - Thai
显示剩余15条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接