【UOJ#8】Quine

前言

不想写作业!怕 FuB** 被发现!那就写写这道经典的传统题吧。

题目

题目链接:http://uoj.ac/problem/8
写一个程序,使其能输出自己的源代码。
代码中必须至少包含 10 个可见字符。

思路

如果这个 OJ 支持 PHP 就好了。
如果按照普通的方法输出自己这个程序,那么需要把自己的程序放在 printf 里面,但是放进去后现在的程序就不是原来的程序了,所以你输出的依然不是源代码。容易发现,这样下去会无限循环。
但是我们可以利用 %s 来输出字符串。这是解决 Quine 问题的瓶颈。
直接放代码吧。再稍微解释解释。

#include <cstdio>
using namespace std;
int main()
{
    char ch[]="#include <cstdio>%cusing namespace std;%cint main()%c{%c    char ch[]=%c%s%c;%c    printf(ch,10,10,10,10,34,ch,34,10,10);%c}";
    printf(ch,10,10,10,10,34,ch,34,10,10);
}

首先我们知道 printf 的一般用法是

printf("%dWYC%cAK%sIOI",1,1,"abc");

之类的。
那么我的代码中最开始 printf(ch,···); 中的 ch 就是相当于上例的 "%dWYC%cAK%sIOI" ,后面的一堆数字就会填进 %c 里面。
首先,回车字符的 ASCII 是 10,双引号字符的 ASCII 是 34。
那么在 #include <cstdio>%cusing namespace std;%cint main()%c{%c 部分的 %c 都会被填入回车字符,其余会被正常输出。
接下来 char ch[]=%c%s%c; ,其中前后两个 %c 都是双引号,中间的 %s 则是 ch 本身。这样就有效避免了无限循环。那么这一段就对应着输出了 char ch[]="#include <cstdio>%cusing namespace std;%cint main()%c{%c char ch[]=%c%s%c;%c printf(ch,10,10,10,10,34,ch,34,10,10);%c}";
接下来 %c printf(ch,10,10,10,10,34,ch,34,10,10);%c} 则是把这个程序的输出部分输出掉。 %c 全部是回车字符。
这样就解决了经典的 Quine 问题。

代码

上面不是有吗

posted @ 2020-03-17 23:09  stoorz  阅读(...)  评论(...编辑  收藏