5/6 线性系统的频域分析(下)
线性系统的稳定性分析
频率域稳定判据
推导
总结:
- 对于每一个s,函数F(s)都有唯一的一个值与之对应,称为映射。s平面的曲线也与F(s)平面曲线相对应。
- 若s平面的曲线不包围F(s)的零点和极点,则F(s)平面曲线不包围原点,且
Гs顺时针时,Г_F也顺时针
。 - 若s平面的曲线Гs
顺时针
包围F(s)的Z个零点,Г_F也顺时针
包围原点Z次;若s平面的曲线Гs顺时针
包围F(s)的P个极点,Г_F则逆时针
包围原点P次;重根应重复计算。 - 幅值原理。
线性系统的开环传递函数是有理分式函数,设
对应的闭环传递函数为
取F(s)为以下形式
所以,F(s)的零点
是闭环传递函数的极点
,F(s)的极点
是开环传递函数G(s)H(s)的极点
。当系统稳定时,闭环传递函数的所有极点(闭环极点)应位于复平面的虚轴左边,即s右半平面没有闭环极点,等价于F(s)在s右半平面里没有零点。
根据幅角原理,零点数Z有
Z=P−R=0
其中,P为F(s)的极点数,R为F(s)逆时针包围原点的圈数。
奈奎斯特稳定判据
因为F(s)=1+G(s)H(s),所以将F(s)左移一个单位
即开环传递函数,F(jw)逆时针包围原点
就可以等价为开环传递函数G(jw)H(jw)环绕(-1.j0)点
。故,引出奈奎斯特稳定判据:
Z=P−2N
式中,Z:右半平面闭环极点数,P:右半平面开环极点数(开环不稳定极点数),N:开环系统奈氏曲线G(jw)H(jw)在w从0到∞时,逆时针环绕(-1.j0)点次圈数。如果Z=0,则闭环系统稳定,否则系统不稳定。
补充说明:
- N=N±N_,N+为自上而下的穿越(相角增大的方向)为
正穿越
;N-为自下而上的穿越(相角减小的方向)为负穿越
。 - 若0型以上的系统,奈奎斯特曲线则需要
补线
,应自G(jw)曲线的G(jw)|_{w=0+}起,沿逆时针方向补画一个半径为无穷大,角度为v×90°的圆弧,为统一奈奎斯特曲线的方向,以顺时针方向标示箭头,作示意图时以虚线代表半径为无穷大的圆弧。 - 对于起点(或终点)位于一1之左的实轴的奈奎斯特曲线,称该曲线对负实轴进行了
半次穿越
(正负规定同补充说明1)。
注:开环传递函数在s右半平面的极点数与系统是否稳定没有直接关系!
对数频率稳定判据
频域稳定裕度
要保证实际系统能够正常地工作,分析时,不仅要求系统稳定,而且还应具有一定的稳定裕度。系统的开环幅相曲线接近(-1,j0)点的程度,就反映了系统稳定的程度。开环幅相曲线越接近(-1,j0)点,系统的稳定程度越差。
稳定边界 |
稳定裕度 |
|
---|---|---|
时域 |
虚轴 |
s左半平面闭环极点到虚轴距离 |
频域 |
(-1,j0) |
到(-1,j0)的距离 |
幅值裕度
使开环传递函数相角达到(2k+1)π的频率叫做穿越频率w_x
。幅值裕度h:
幅值裕度表示了系统在幅值方面的稳定储备量
,一般要求h>2
- h(dB)>0,L(w_x)为负值,系统稳定;
- h(dB)<0,L(w_x)为正值,系统不稳定;
- h(dB)=0,L(w_x)为0,系统临界稳定;
相角裕度
使得开环传递函数的幅值等于1的频率为截止频率w_c
。相角裕度γ是系统由稳定达到临界稳定状态所需增加的相角滞后量。
幅值裕度表示了系统在相角方面的稳定储备量
,一般要求γ>40°
- γ>0,表示奈奎斯特曲线未包围(-1,j0)点,系统稳定;
- γ<0,表示奈奎斯特曲线包围了(-1,j0)点,系统不稳定;
- γ=0,表示奈奎斯特曲线通过了(-1,j0)点,系统临界稳定;
设计控制系统时的目标:为了使系统具有足够的稳定裕度和获得良好的动态性能,一般要求相角裕度γ=30~70度,幅值裕度h=2~2.5或h(dB)=6~8。 Note 1:仅仅用相角裕度或仅仅用幅值裕度,都不足以说明系统的相对稳定性。
只有同时给出相角裕度和幅值裕度时才能表明系统的相对稳定性
,但是对于无零点的二阶系统和只要求粗略估算动态性能的高阶系统,一般只要相角裕度就足够了。 Note 2:一阶系统和二阶系统的相角裕度,幅值裕度总是大于0,而幅值裕度h=oo,因此,从理论上讲,系统不可能不稳定。
闭环系统的频域性能指标
控制系统的带宽
带宽频率:为幅频特性衰减到0.707M_0时所对应的频率,通常用w_b表示。
带宽:频率从0到w_b的频率范围,称为系统的带宽。带宽的大小,反映了系统的快速性和复现输入信号的能力。但从抑制噪声角度来说,带宽不宜过大。
二阶闭环系统频域性能指标和时域指标的转换
表示一下闭环频域指标——带宽、开环频域指标——相角裕量γ
当0<ζ<0.707时,幅频曲线有峰值出现,这时对应的峰值为谐振峰值M_r
,对应的频率为谐振频率w_r。
- 已知M_r和σ%都随ζ增加而减小,所以同一系统,M_r和σ%有一致性,M_r增大时,σ%也增大。M_r可以看作是度量系统振荡程度的频域指标。
- 相角裕度γ和阻尼比ζ也是一一对应的关系,且ζ越大,γ越大。
- 二阶系统的调节时间t_s与截止频率w_c和相角裕度γ有关,截止频率w_c越大,调节时间t_s越小。
线性系统的频域法校正
根据校正装置在系统中的连接方式,分为串联校正和反馈校正
两种。为了避免功率损耗,串联校正装置通常安置在前向通道偏差测量点之后和放大器之间,或安置在放大器之间。根据校正装置的特性,工程上常用的串联校正有串联超前校正,串联滞后校正和串联滞后-超前校正
等。反馈校正装置接在局部反馈通道上,常用的反馈校正有比例反馈校正和测速反馈校正等。
开环系统的伯德图是分析和设计控制系统的重要工具。分析时可将开环对数幅频特性以穿越频率
附近为中频段,低于中频的为低频段,高于中频的为高频段。开环系统的对数幅频特性曲线的低频段表征了系统的静态特性,中频段表征了系统的动态特性,而高频段则表征了系统的抗干扰能力。一个特性较好的系统,其各频段有以下特点:
(1)相角裕度γ为30°~60°;幅值裕度h>6dB,则系统的稳定性比较好。当中频段以一20dB/dec的斜率穿越零分贝线,而且这一斜率占有足够的频带宽度,系统会具有较好的稳定性;
(2)截止频率w_c越高,则系统的快速性越好;
(3)低频段的斜率陡,增益高,表示系统的稳态精度好;
(4)高频段衰减得越快,即高频特性负分贝值低,说明系统抗高频噪声干扰的能力越强。
串联超前校正a>1
这里稍作解释:
- 原系统为G,对数幅值为L_0;
- 超前系统为G_c,有最大超前角频率w_m,且有L_c(w_m)=10lga;
- 校正后的系统则为G*G_c,有截止频率w_c’‘,则有L_0(w_c’‘)+L_c(w_c’')=0。
为了得到最大的相角裕度,应有w_m=w_c’'。所以两个方程可以反解出两个频率值。所以求解路线基本就是:相角裕度增量(超前系统的最大相角)-a-最大超前角频率(新系统截止频率)
中知道一个然后求剩下两个,进而确定周期T,就可以完整确定超前系统。
应当指出,在有些情况下,串联超前校正无效,它受以下两个因素的限制:
(1)闭环带宽要求。若待校正系统不稳定
﹐需要超前网络提供很大的相角超前量,以致a必须很大,造成系统带宽过大,通过系统的高频噪声电平很高。
(2)在截止频率附近相角迅速减小的待校正系统
,一般不宜采用串联超前校正。因为随着频率的增大,待校正系统相角迅速减小,超前校正网络难以较多地增大系统的相角裕度。此时,可以考虑用多个超前校正网络串联,或者是采用其他校正形式,如滞后校正。
串联滞后校正b<1
超前、滞后校正的比较
- 超前校正利用其相位超前特性、获得系统所需要的相位超前量。而滞后校正则利用其高频衰减特性,使截止频率下降,借助于原系统在新的截止频率处的相位,获得系统所需要的相位裕度。
- 超前校正通常用来改善稳定裕度,滞后校正通常用来提高稳态精度。
- 超前校正比滞两个指标后校正提供更高的截止频率。高的截止频率意味着大的带宽,从而意味着小的调整时间。因此,如果希望系统具有大的带宽,或者快的响应,应采用超前校正。
- 超前校正需要由一个附加的增益增量,以抵消超前网络本身的衰减。则表明超前校正比滯后校正需要更大的增益。在多数情况下,增益越大,意味着系统的体积和重量越大, 成本越高,同时会在系统中产生比较大的信号,这种大信号容易造成元件的饱和现象。
- 滞后校正降低了系统在高频区的增益,但并没有降低系统在低频区的增益。因为降低了高频增益,系统的总增益可以增加,从而低频增益随之增加,因此改善了系统的稳态精度。
- 滞后校正减小了带宽,因此系统具有较低的响应速度,但系统中包含的任何高频噪音都可以得到衰减。
- 滞后校正将会在原点附近引进极、零点组合(偶极子) ,这将会在瞬态响应中产生小振幅的长时间拖尾。
- 如果既需要获得快速响应特性,又需要良好的稳态精度,则可以采用滞后一超前校正
推荐阅读
-
[自动驾驶仪] 线性系统的频域分析 (2) 频率特性表示法-2.惯性链路
-
实验 6 连续信号的频域分析
-
5/6 线性系统的频域分析(下)
-
windows下进程间通信的(13种方法)-摘 要 本文讨论了进程间通信与应用程序间通信的含义及相应的实现技术,并对这些技术的原理、特性等进行了深入的分析和比较。 ---- 关键词 信号 管道 消息队列 共享存储段 信号灯 远程过程调用 Socket套接字 MQSeries 1 引言 ---- 进程间通信的主要目的是实现同一计算机系统内部的相互协作的进程之间的数据共享与信息交换,由于这些进程处于同一软件和硬件环境下,利用操作系统提供的的编程接口,用户可以方便地在程序中实现这种通信;应用程序间通信的主要目的是实现不同计算机系统中的相互协作的应用程序之间的数据共享与信息交换,由于应用程序分别运行在不同计算机系统中,它们之间要通过网络之间的协议才能实现数据共享与信息交换。进程间通信和应用程序间通信及相应的实现技术有许多相同之处,也各有自己的特色。即使是同一类型的通信也有多种的实现方法,以适应不同情况的需要。 ---- 为了充分认识和掌握这两种通信及相应的实现技术,本文将就以下几个方面对这两种通信进行深入的讨论:问题的由来、解决问题的策略和方法、每种方法的工作原理和实现、每种实现方法的特点和适用的范围等。 2 进程间的通信及其实现技术 ---- 用户提交给计算机的任务最终都是通过一个个的进程来完成的。在一组并发进程中的任何两个进程之间,如果都不存在公共变量,则称该组进程为不相交的。在不相交的进程组中,每个进程都独立于其它进程,它的运行环境与顺序程序一样,而且它的运行环境也不为别的进程所改变。运行的结果是确定的,不会发生与时间相关的错误。 ---- 但是,在实际中,并发进程的各个进程之间并不是完全互相独立的,它们之间往往存在着相互制约的关系。进程之间的相互制约关系表现为两种方式: ---- (1) 间接相互制约:共享CPU ---- (2) 直接相互制约:竞争和协作 ---- 竞争——进程对共享资源的竞争。为保证进程互斥地访问共享资源,各进程必须互斥地进入各自的临界段。 ---- 协作——进程之间交换数据。为完成一个共同任务而同时运行的一组进程称为同组进程,它们之间必须交换数据,以达到协作完成任务的目的,交换数据可以通知对方可以做某事或者委托对方做某事。 ---- 共享CPU问题由操作系统的进程调度来实现,进程间的竞争和协作由进程间的通信来完成。进程间的通信一般由操作系统提供编程接口,由程序员在程序中实现。UNIX在这个方面可以说最具特色,它提供了一整套进程间的数据共享与信息交换的处理方法——进程通信机制(IPC)。因此,我们就以UNIX为例来分析进程间通信的各种实现技术。 ---- 在UNIX中,文件(File)、信号(Signal)、无名管道(Unnamed Pipes)、有名管道(FIFOs)是传统IPC功能;新的IPC功能包括消息队列(Message queues)、共享存储段(Shared memory segment)和信号灯(Semapores)。 ---- (1) 信号 ---- 信号机制是UNIX为进程中断处理而设置的。它只是一组预定义的值,因此不能用于信息交换,仅用于进程中断控制。例如在发生浮点错、非法内存访问、执行无效指令、某些按键(如ctrl-c、del等)等都会产生一个信号,操作系统就会调用有关的系统调用或用户定义的处理过程来处理。 ---- 信号处理的系统调用是signal,调用形式是: ---- signal(signalno,action) ---- 其中,signalno是规定信号编号的值,action指明当特定的信号发生时所执行的动作。 ---- (2) 无名管道和有名管道 ---- 无名管道实际上是内存中的一个临时存储区,它由系统安全控制,并且独立于创建它的进程的内存区。管道对数据采用先进先出方式管理,并严格按顺序操作,例如不能对管道进行搜索,管道中的信息只能读一次。 ---- 无名管道只能用于两个相互协作的进程之间的通信,并且访问无名管道的进程必须有共同的祖先。 ---- 系统提供了许多标准管道库函数,如: pipe——打开一个可以读写的管道; close——关闭相应的管道; read——从管道中读取字符; write——向管道中写入字符; ---- 有名管道的操作和无名管道类似,不同的地方在于使用有名管道的进程不需要具有共同的祖先,其它进程,只要知道该管道的名字,就可以访问它。管道非常适合进程之间快速交换信息。 ---- (3) 消息队列(MQ) ---- 消息队列是内存中独立于生成它的进程的一段存储区,一旦创建消息队列,任何进程,只要具有正确的的访问权限,都可以访问消息队列,消息队列非常适合于在进程间交换短信息。 ---- 消息队列的每条消息由类型编号来分类,这样接收进程可以选择读取特定的消息类型——这一点与管道不同。消息队列在创建后将一直存在,直到使用msgctl系统调用或iqcrm -q命令删除它为止。 ---- 系统提供了许多有关创建、使用和管理消息队列的系统调用,如: ---- int msgget(key,flag)——创建一个具有flag权限的MQ及其相应的结构,并返回一个唯一的正整数msqid(MQ的标识符); ---- int msgsnd(msqid,msgp,msgsz,msgtyp,flag)——向队列中发送信息; ---- int msgrcv(msqid,cmd,buf)——从队列中接收信息; ---- int msgctl(msqid,cmd,buf)——对MQ的控制操作; ---- (4) 共享存储段(SM) ---- 共享存储段是主存的一部分,它由一个或多个独立的进程共享。各进程的数据段与共享存储段相关联,对每个进程来说,共享存储段有不同的虚拟地址。系统提供的有关SM的系统调用有: ---- int shmget(key,size,flag)——创建大小为size的SM段,其相应的数据结构名为key,并返回共享内存区的标识符shmid; ---- char shmat(shmid,address,flag)——将当前进程数据段的地址赋给shmget所返回的名为shmid的SM段; ---- int shmdr(address)——从进程地址空间删除SM段; ---- int shmctl (shmid,cmd,buf)——对SM的控制操作; ---- SM的大小只受主存限制,SM段的访问及进程间的信息交换可以通过同步读写来完成。同步通常由信号灯来实现。SM非常适合进程之间大量数据的共享。 ---- (5) 信号灯 ---- 在UNIX中,信号灯是一组进程共享的数据结构,当几个进程竞争同一资源时(文件、共享内存或消息队列等),它们的操作便由信号灯来同步,以防止互相干扰。 ---- 信号灯保证了某一时刻只有一个进程访问某一临界资源,所有请求该资源的其它进程都将被挂起,一旦该资源得到释放,系统才允许其它进程访问该资源。信号灯通常配对使用,以便实现资源的加锁和解锁。 ---- 进程间通信的实现技术的特点是:操作系统提供实现机制和编程接口,由用户在程序中实现,保证进程间可以进行快速的信息交换和大量数据的共享。但是,上述方式主要适合在同一台计算机系统内部的进程之间的通信。 3 应用程序间的通信及其实现技术 ---- 同进程之间的相互制约一样,不同的应用程序之间也存在竞争和协作的关系。UNIX操作系统也提供一些可用于应用程序之间实现数据共享与信息交换的编程接口,程序员可以通过自己编程来实现。如远程过程调用和基于TCP/IP协议的套接字(Socket)编程。但是,相对普通程序员来说,它们涉及的技术比较深,编程也比较复杂,实现起来困难较大。 ---- 于是,一种新的技术应运而生——通过将有关通信的细节完全掩盖在某个独立软件内部,即底层的通讯工作和相应的维护管理工作由该软件内部来实现,用户只需要将通信任务提交给该软件去完成,而不必理会它的具体工作过程——这就是所谓的中间件技术。 ---- 我们在这里分别讨论这三种常用的应用程序间通信的实现技术——远程过程调用、会话编程技术和MQSeries消息队列技术。其中远程过程调用和会话编程属于比较低级的方式,程序员参与的程度较深,而MQSeries消息队列则属于比较高级的方式,即中间件方式,程序员参与的程度较浅。 ---- 4.1 远程过程调用(RPC)
-
原题简化版: 1. 赚6万每月的大咖秘籍:不能透漏细节的职业智慧,只有在未设防的领域不断探索、积累,到某天突然亮剑,旁人惊讶之余难以轻易赶超,这时候你就筑起了自我优势的"护城河"。 2. 成功达人秘诀揭秘:广泛交往、善言推销或直接跑业务的人总能在短时间内发现商机,关键在于抓住每一次客户互动中的机遇。 3. 编程族别再低头苦干:要学会抬头看看,发掘自身还能挖掘哪些潜力技能,尝试将其转化为创新商业模式,这才是值得我们在闲暇时光深思的问题。 4. "望洋兴叹"不如实际行动:尽管无法复制他人的整套成功路径,但我们能学习他们的思维方式和财富增长策略。看到马云早期互联网的成功,固然令人艳羡,但别沉溺于羡慕嫉妒恨,而要思考如何突破自我局限。 5. 对待心灵鸡汤和焦虑营销需理性:别被鸡汤和焦虑文章牵着鼻子走,它们只会制造紧张情绪,实际对你的成长帮助有限。与其慌乱不安,不如冷静分析,找出真正适合自己的改变之道。
-
= 0; i--) {
printf("%5d", *(p + i));
}
printf("\n");
return 0;
}
```
2. 利用指针计算奇数索引数组元素之和
```c
// 使用指针计算奇数索引数组元素之和
#include
int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int n = sizeof(arr) / sizeof(arr[0]); printf("数组元素: "); for (int i = 0; i < n; i++) { printf("%3d", arr[i]); // 宽度为3,右对齐 } printf("\n"); printf("数组下标: "); for (int i = 0; i < n; i++) { printf("%3d", i); // 宽度为3,右对齐 } printf("\n"); int sum = 0; int *p = arr; // 声明指向整数的指针 for (int i = 0; i < n; i++) { if (i % 2 != 0) { sum += *(p + i); // 若索引i为奇数,累加对应元素值 } } printf("奇数索引数组元素之和: %d\n", sum); return 0; } ``` 3. 查看不同类型指针在Linux Ubuntu gcc下的字节大小 ```c // 在Linux Ubuntu gcc环境下查看不同类型指针的字节大小 #include #include int main() { printf("int指针大小: %zu bytes\n", sizeof(int *)); printf("char指针大小: %zu bytes\n", sizeof(char *)); printf("float指针大小: %zu bytes\n", sizeof(float *)); printf("double指针大小: %zu bytes\n", sizeof(double *)); return 0; } ``` 请注意,对于现代64位系统(如Linux),`int`、`char`、`float`和`double`指针通常都是8字节。但在某些特定情况下(如32位系统或特定编译环境),可能有所不同。 4. 使用指针遍历并打印字符数组 ```c // 使用指针遍历并打印字符数组 #include #include // 引入strlen函数 int main() { char str[] = "Hello, World"; // 字符串常量 int len = strlen(str); // 获取字符串长度 char *ptr = str; // 定义指向字符的指针 printf("输出字符串: %s\n", str); // 输出原始字符串 printf("遍历并打印字符数组: "); for (int i = 0; i < len; i++) { printf("%c", *ptr); // 输出当前字符 ptr++; // 移动指针到下一个字符 } printf("\n"); return 0; } ``` 对于用户自定义输入字符串的情况,请参考以下代码: ```c #include #include int main() { char input[100]; // 用于存放用户输入的字符串,假设最大长度为100 printf("请输入字符串: "); fgets(input, sizeof(input), stdin); // 从标准输入读取字符串,fgets会保留换行符 int len = strlen(input) - 1; // 去掉fgets读取的换行符 char *ptr = input; // 定义指向字符的指针 printf("输入的字符串: %s\n", input); printf("遍历并打印字符数组: "); for (int i = 0; i < len; i++) { printf("%c", *ptr); // 输出当前字符 ptr++; // 移动指针到下一个字符 } printf("\n"); return 0; } ```"> 1. 使用指针倒序显示整数数组内容 ```c // 通过指针逆序打印整数数组 #include
#include #include int main() { int arr[10] = {0}; int n = sizeof(arr) / sizeof(arr[0]); srand(time(NULL)); printf("原始数组: "); for (int i = 0; i < n; i++) { arr[i] = rand() % 100; printf("%5d", arr[i]); } printf("\n"); int *p = arr; // 指针指向数组元素 printf("反转打印数组元素: "); for (int i = n - 1; i >= 0; i--) { printf("%5d", *(p + i)); } printf("\n"); return 0; } ``` 2. 利用指针计算奇数索引数组元素之和 ```c // 使用指针计算奇数索引数组元素之和 #include int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int n = sizeof(arr) / sizeof(arr[0]); printf("数组元素: "); for (int i = 0; i < n; i++) { printf("%3d", arr[i]); // 宽度为3,右对齐 } printf("\n"); printf("数组下标: "); for (int i = 0; i < n; i++) { printf("%3d", i); // 宽度为3,右对齐 } printf("\n"); int sum = 0; int *p = arr; // 声明指向整数的指针 for (int i = 0; i < n; i++) { if (i % 2 != 0) { sum += *(p + i); // 若索引i为奇数,累加对应元素值 } } printf("奇数索引数组元素之和: %d\n", sum); return 0; } ``` 3. 查看不同类型指针在Linux Ubuntu gcc下的字节大小 ```c // 在Linux Ubuntu gcc环境下查看不同类型指针的字节大小 #include #include int main() { printf("int指针大小: %zu bytes\n", sizeof(int *)); printf("char指针大小: %zu bytes\n", sizeof(char *)); printf("float指针大小: %zu bytes\n", sizeof(float *)); printf("double指针大小: %zu bytes\n", sizeof(double *)); return 0; } ``` 请注意,对于现代64位系统(如Linux),`int`、`char`、`float`和`double`指针通常都是8字节。但在某些特定情况下(如32位系统或特定编译环境),可能有所不同。 4. 使用指针遍历并打印字符数组 ```c // 使用指针遍历并打印字符数组 #include #include // 引入strlen函数 int main() { char str[] = "Hello, World"; // 字符串常量 int len = strlen(str); // 获取字符串长度 char *ptr = str; // 定义指向字符的指针 printf("输出字符串: %s\n", str); // 输出原始字符串 printf("遍历并打印字符数组: "); for (int i = 0; i < len; i++) { printf("%c", *ptr); // 输出当前字符 ptr++; // 移动指针到下一个字符 } printf("\n"); return 0; } ``` 对于用户自定义输入字符串的情况,请参考以下代码: ```c #include #include int main() { char input[100]; // 用于存放用户输入的字符串,假设最大长度为100 printf("请输入字符串: "); fgets(input, sizeof(input), stdin); // 从标准输入读取字符串,fgets会保留换行符 int len = strlen(input) - 1; // 去掉fgets读取的换行符 char *ptr = input; // 定义指向字符的指针 printf("输入的字符串: %s\n", input); printf("遍历并打印字符数组: "); for (int i = 0; i < len; i++) { printf("%c", *ptr); // 输出当前字符 ptr++; // 移动指针到下一个字符 } printf("\n"); return 0; } ``` -
南邮OJ Web任务大揭秘:层层挑战剖析 1. 挑战一:迷宫般的目录探索 题目作者似乎穷举了所有可能的目录组合,最终在404.php中的