• 这c代码,会让你发疯


    9738d6b9764d4351c2d12befe3ac33be.jpeg

    之前我写过一段代码,文章如下

    c语言从1打印到100再打印到1该如何编写?

    这是一个很简单的代码,可能刚学c语言没几天的人都知道用一个for循环就可以搞定。

     
     
    1. #include "stdio.h"
    2. void fun(int n) {
    3.  if(n<100) {
    4.   printf("%d ",n); 
    5.   fun(n+1);
    6.  } 
    7.  printf("%d ",n);
    8. }
    9. int main(void) {
    10.  fun(1);
    11.  return 0;
    12. }

    但是有一个读者朋友看了我的文章,发了这样一段代码过来

     
     
    __[]={1,10,100,1000};main(_){_^400&&(_<4?1:putchar(((!((_/4)/((_%4)["3210"][__-48])%10)&&(_%4)^3)?32:((_/4)/((_%4)["3210"][__-48])%10+48))) )&&main(-~_);putchar(((!(((_+3)/4)/(((3+_)%4)["0123"][__-48])%10)&&((3+_)%4)^0)?_^398?32:48:(((3+_)/4)/(((3+_)%4)["0123"][__-48])%10+48)))&&_^1?1:putchar(10);}

    这位读者朋友的叫做,「我们国庆的时候,还针对这几个题目聊了两天,技术原来真的可以拉近大家的距离。」

    如果没解析,是很难理解这样非人类的代码的,里面运用到的几个技巧如下

    main 函数是可以递归的,这也是很多大神写代码用到的一个技巧。

    main 函数是可以没有返回值的,当然,编译的时候会出现警告,但是这并不影响运行结果。

    argc != 8 等价于 argc^8

    argc +1 等价于 -~argc

    && 和 || 等存在短路操作

    数组 a[i] 等价于 i[a]

    56,可以通过取整取余通过putchar把他们打印出来

    所以上面的代码就可以拆解成

     
     
    1. __[]={1,10,100,1000};
    2. main(_)
    3. {
    4.   if (_!=20)
    5.   {
    6.     if (_>=4)
    7.     {
    8.       putchar(((!((_/4)/((_%4)["3210"][__-48])%10)&&(_%4)^3)?32:((_/4)/((_%4)["3210"][__-48])%10+48)));
    9.     }
    10.     main(-~_);
    11.   }
    12.   putchar(((!(((_+3)/4)/(((3+_)%4)["0123"][__-48])%10)&&((3+_)%4)^0)?_^398?32:48:(((3+_)/4)/(((3+_)%4)["0123"][__-48])%10+48)))&&_^1?1:putchar(10);
    13. }
    400 是用来控制输出的数量的,我们现在是输出 1~100~1

    12d07b0eb501acc150941b6dcbcc6716.png

    看下ascii码表,32对应的是空格,48 对应的是字符 ’0

    c62612a243c0d20a1bac7de6f23d76cb.png

    然后,我们可以得出这样的解释代码
    重要的部分都写在注释里面了,大家可以认真看看。
     
     
    1. __[]={1,10,100,1000};
    2. main(_)
    3. {
    4.   if (_!=100)
    5.   {
    6.     if (_>=4)
    7.     {
    8.       char c = 32// 默认打印输出一个空格‘ ’
    9.       int number = _/4// 这个是实际输出的数字,如果_ 等于[1,2,3,4],不会进入这个循环,如果_ 等于[4,5,6,7],number就等于1,取整数部分。
    10.       int bit = (_%4)["3210"][__-48]; //这个就是数组取巧的地方,bit 等于 1,10,100,1000,其中的一个数字,记住 48对应的ascii是字符‘0’
    11.                                       //先推导 (_%4)["3210"] 这部分得出结果,之后再推导 (_%4)["3210"][__-48]
    12.                                       //(x)[y] 等价于 *(y+x)
    13.       int bitnumber = number/bit%10;  //bitnumber 可以认为是有效数字的推导,如果是 [4,5,6,7],打印出来对应的应该是[‘空格’,‘空格’,‘空格’,‘1’]
    14.                                       //所以这里的判断主要是为了让下面的if不要成立就可以了。
    15.                                       //sample input:4    5   6  7
    16.                                       //    number  :1    1   1  1
    17.                                       //    bit     :1000 100 10 1
    18.                                       //  bitnumber :0    0    0 1
    19.                                       //当然,如果输入的数字很大呢?
    20.                                       //sample input:44   45  46 47
    21.                                       //    number  :11   11  11 11
    22.                                       //    bit     :1000 100 10 1
    23.                                       //  bitnumber :0    0    1 1
    24.                                       //sample input:40   41  42 43
    25.                                       //    number  :10   10  10 10
    26.                                       //    bit     :1000 100 10 1
    27.                                       //  bitnumber :0    0    1 0
    28.                                       //上面的推导就是完成了下面的if语句,bitnumber != 0 是为了输出超过10位数的数。
    29.                                       //_%4 == 3, 是为了输出整除4个数字的最后一位。
    30.       if ((_%4 == 3) || bitnumber != 0)
    31.         c = bitnumber + 48;
    32.       putchar(c);
    33.     }
    34.     main(-~_);
    35.   }
    36.   putchar(((!(((_+3)/4)/(((3+_)%4)["0123"][__-48])%10)&&((3+_)%4)^0)?_^398?32:48:(((3+_)/4)/(((3+_)%4)["0123"][__-48])%10+48)))&&_^1?1:putchar(10);
    37. }
    至于下面的一行解释和上面的如出一撤,比较关键的地方是,这里用到了递归
    调用,所以对栈的大小是有要求的。
    可以试试

    3ed128fa3c15d6eccf78d4d2ffe19fad.png

    作者给出的详细解释如下
    两份解析一起来看的话,希望大家对代码的理解有所帮助,当然了,写这样的
    代码出来也是非常有意思。

    a4098b8fcb860fed091baa36c880e8b4.jpeg

  • 相关阅读:
    【高并发】深度解析ScheduledThreadPoolExecutor类的源代码
    0基础学习VR全景平台篇 第106篇:认识调色软件Lightroom
    µC/OS-II---两个系统任务
    1997-2020年31省进出口总额
    【Unity入门计划】Unity实例-C#如何通过封装实现对数据成员的保护
    Elasticsearch学习-- 聚合查询
    构建企业全生命周期数字化资产管理新模式
    PageHelper分页插件隐藏的坑
    应急响应-文件痕迹排查
    BEVFusion简介、环境配置与安装以及遇到的各种报错处理
  • 原文地址:https://blog.csdn.net/weiqifa0/article/details/127218828