雨中飞燕

编程江湖里的一段传奇

2025.05.18

最近闲来无事,刷了一下 Github Star 排行榜,除了发掘出了一些之前不知道的开源项目,也看到了几个多年以前关注过的项目,思绪便一下子被拉回到那些遥远记忆之中。

突然想起了最开始学习编程的社区 —— 如鹏网(rupeng.com),如今网站已经关闭,杨中科老师也已移民新西兰(但依旧活跃于互联网上)。他的《C语言也能干大事》系列视频算是我编程的启蒙课程,那时候条件还很“艰苦”,我是晚上躲在被窝里用 MP4 偷看学习的。

在如鹏网上有一位代号为“rtgirl”和“雨中飞燕”的版主,比较活跃,发布了很多作品。当时我对她也不太了解,不知道她建立了一个 算法社区 ,也不知道她写了一个 EGE 图形库 。我还记得她发布过一个叫做“碧波荡漾”的程序,对于那时候还是个毛头小子的我来说,感觉非常有趣,也挺震撼的。

她还写过一个晦涩难懂的计算 1000 阶乘的程序。后来我都上大学了也没看懂这段代码,可能是编程经验欠缺,也可能是被浮夸的说法给唬住了,还以为用了什么很高级的数学技巧。时过境迁,随着技术的发展,如今连 AI 都能看懂这段代码,并给出程序的输出。

#include<stdio.h>
#define N 1000    //要计算的N
long s[N]={1,1},n=N,t=2,a=1,b=0;
int main()//雨中飞燕之作
{
    for(;a<=*s||(++t<=n?(b=0,a=1):0);(*s==a++&&b)?(*s)++:0)
        s[a]=(b+=s[a]*t)%10000,b/=10000;
    for(printf("%d",s[*s]);--*s>0;)printf("%04d",s[*s]);
    return 0;
}

现在,工作多年后的我,已经有足够的信心能看懂它了。我这才发现,刨去代码压缩的技巧外,程序的核心逻辑其实很朴素,就是实现了一个大整数乘以小整数而已。这里我贴出一个冗长,但是可读性良好的等价版本。

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

typedef struct {
    uint32_t *parts;
    int capacity;
    int used;
} big_num_t;

void big_num_ensure_capacity(big_num_t *big, int capacity)
{
    if (capacity <= big->capacity)
        return;

    big->parts = realloc(big->parts, sizeof(big->parts) * capacity);
    big->capacity = capacity;
}

void big_num_init(big_num_t *big, uint32_t value)
{
    big->parts = NULL;
    big->capacity = 0;
    big_num_ensure_capacity(big, 1);
    big->parts[0] = value;
    big->used = 1;
}

void big_num_free(big_num_t *big)
{
    if (big->parts) {
        free(big->parts);
        big->parts = NULL;
        big->capacity = 0;
    }
}

void big_num_multiply(big_num_t *big, uint16_t multiplier)
{
    uint64_t carry = 0;

    for (int i = 0; i < big->used; ++i) {
        uint64_t multiplicand = big->parts[i];
        uint64_t result = multiplicand * multiplier + carry;
        big->parts[i] = result % 10000;
        carry = (result / 10000);
    }

    if (!carry)
        return;

    big_num_ensure_capacity(big, ++big->used);
    big->parts[big->used - 1] = (uint32_t)carry;
}

char* big_num_to_string(big_num_t *big)
{
    if (!big->used) {
        big_num_ensure_capacity(big, 1);
        big->parts[0] = 0;
        big->used = 1;
    }

    char *result = malloc(big->used * 4 + 1);
    snprintf(result, 5, "%d", big->parts[big->used - 1]);

    char *head = result + strlen(result);

    for (int i = big->used - 2; i >= 0; --i) {
        snprintf(head, 5, "%04d", big->parts[i]);
        head += 4;
    }

    *head = '\0';
    return result;
}

int main()
{
    big_num_t result;
    big_num_init(&result, 1);

    for (uint16_t i = 2; i <= 1000; ++i)
        big_num_multiply(&result, i);

    char *result_str = big_num_to_string(&result);
    printf("%s\n", result_str);

    free(result_str);
    big_num_free(&result);
}

接着,我尝试搜索更多关于雨中飞燕的信息,但这个 ID 似乎已经从网络上消失了,包括以前贴吧里讨论她性别的帖子。一段传奇本应该就此落幕,然而现实世界总是荒诞离奇的。通过搜索,我惊讶的发现她的身份居然早已被 公开 ,而她的另一个代号便是知名的“破娃酱”,即 SSR 的作者“breakwa11”。在翻墙工具刚刚开始发展的蛮荒时期,SSR 非常流行,相信很多人都见过这个头像。

江湖险恶,在 breakwa11 被开盒后,这个代号从此也不再活跃了,不知道她是否还会再换个马甲续写下一段传奇,或是心灰意冷,退隐江湖。

从 breakwa11 被开盒的事件中,我认识到,在网络上保持绝对的匿名其实相当困难。不同账号之间一定要完全排除关联性,比如 breakwa11 就是在 Telegram 上关联了特征性极强的 “misakamm”。她在“雨中飞燕”时期公开的 QQ 号至少就有 59765994、78803110、609754650 和 1007665007,马甲倒是层出不穷,但没有做到彻底的身份隔离,不同平台,不同账号之间有很多关联性。即便是“编程随想”的邮箱,也曾关联过特征极强的 “rxh-temp”,或许除了人格分裂外,一个人不可能在网上长期维持两个完全独立的身份而不留下任何蛛丝马迹。

好了,雨中飞燕的故事或许真的迎来了终章,她的传奇,也将随着岁月的烟霭渐渐隐去。

(全文结束)