我们如何在不使用循环和条件的情况下从1到100打印数字

时间:2018-05-26 20:48:03

标签: c

基本上我在互联网上发现的问题是:“我们如何在不使用循环和条件的情况下将数字从1打印到100?”在答案中,我被卡在下面标有粗体的一些线上。任何人都可以解释我是什么? 我认为下面的总代码是用我的知识用C语言编写的。

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

void foo(int);

void f1(int x)
{
  printf ("%d\n", x + 1);
  foo (x + 1);
}

void f2(int x)  //why we have used this fumction
{}

void (*tab[])(int) = { f1, f2 }; // what is this

void foo(int x)
{
  tab[!(x < 100)](x); // what is this
}

int main()
{
  foo(0);
  return 0;
}

5 个答案:

答案 0 :(得分:4)

tab是一个包含两个函数指针的数组。

由于您不允许使用if,而是使用函数数组,并使用!(x < 100)比较结果对其进行索引。如果这是真的,则评估为1,因此您在tab[1]中调用该函数,即f2()。如果它为false,则评估为0,因此您调用tab[0],即f1。所以它实际上与:

相同
if (x < 100) {
    f1(x);
} else {
    f2(x);
}

f1(x)打印x+1,然后递归调用foo(x+1)f2(x)没有做任何事情,所以当你到达时,递归就会结束。

答案 1 :(得分:2)

void (*tab[])(int) = { f1, f2 }; // what is this将是一个带有int参数的函数指针数组。

tab[!(x < 100)](x); // what is this

这意味着您正在访问函数0或1,具体取决于条件的评估(false - 0或true - 1)

代码似乎是一个递归调用,它将停止在100

答案 2 :(得分:2)

这个怎么样:

#include <stdio.h>

int p(int n) {
    return printf("%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n",
                  n+1, n+2, n+3, n+4, n+5, n+6, n+7, n+8, n+9, n+10);
}

int main() {
    return p(0), p(10), p(20), p(30), p(40), p(50), p(60), p(70), p(80), p(90), 0;
}

或者这个更紧凑的版本,使用非明显的终止测试一次打印一个数字:

#include <stdio.h>

int p(int n) {
    return printf("%d\n", n++) - 4 && p(n);
}
int main() {
    return p(1);
}

顺便说一下,人们可以用这种方式使它更加神秘:

#include <stdio.h>

int main(int argc, char *argv[]) {
    return printf("%d\n", argc++) - 4 && main(argc, argv);
}

上面的两个版本仍然使用测试,而不是if语句。

这是一个将OP代码的想法与上述方法相结合的变体:

#include <stdio.h>
#include <stlib.h>

static void p(int n);
static void (*f[5])(int) = { p, p, p, p, exit };
static void p(int n) {
    f[printf("%d\n", n + 101)](n + 1);
}
int main(int argc, char *argv[]) {
    p(-100);
}

function p取整数n并打印n + 101的值,然后调用其指针位于数组f中的偏移量的函数由printf输出的字节数,将n + 1传递给此函数。

第一个调用获取-100作为参数,因此打印1和换行符。 printf返回2,因此p以值-99递归调用自身。

第二个调用打印2,并以-98递归调用自身。

此过程一直重复,直到printf返回4:f[4]调用的函数为exit,并且printf首次打印数字100时返回4 ,exit获取值0并以退出状态0终止该程序,这意味着成功。

没有循环,没有条件,根本没有测试。

答案 3 :(得分:1)

这依赖于递归(在函数f1中)和动态数组查找(在函数foo中),而不是使用循环或条件。

void f2(int x)  //why we have used this fumction
{}

f2函数不执行任何操作,并在x >= 100时调用,从而在达到最大值时终止序列。

void (*tab[])(int) = { f1, f2 }; // what is this

这是一个数组初始化。 tab是一个指向int参数的函数的指针数组。数组的两个元素是指向函数f1f2的指针。

tab[!(x < 100)](x); // what is this

在这种情况下,这与条件相同。这会调用tab中的第一个或第二个函数,具体取决于x < 100是否为x < 100

!(x < 100)时,数组下标!true等于0,或int转换为tab[0]时。 f1是数组的第一个元素,即函数f1foo函数打印并递增数字,然后再次调用x >= 100进行递归,从而继续执行序列。

tab[1]f2被调用时,它是数组的第二个元素f2。由于x >= 100不执行任何操作,因此序列在Client时结束。

答案 4 :(得分:0)

f1负责打印并实际递增计数,并依赖于foo的来回弹跳。

tab是由两个函数f1f2组成的数组。请注意,在foo中,此数组由布尔表达式索引,该表达式最终转换为执行f1(count),直到count大于或等于100 。 / p> 因此,

footabf1f2只是支持和终止递归的一种方式。

执行程序时,调用堆栈看起来像这样:

main()
    foo(0)
        f1(0) -> print 1
            foo(1)
                f1(1) -> print 2
                    foo(2)
                        f1(2) -> print 3
                            ....
                            foo(99)
                                f1(99) -> print 100
                                    foo(100)
                                        f2(100) -> do nothing
  <---------------------------------------