本篇内容
- WHILE ... DO 循环
- REPEAT ... UNTIL 循环
- 典型应用:输入验证
- 核心区别对比
While...do 和 Repeat...until 是两种基于布尔条件控制的循环结构。它们弥补了 for 循环只能按固定步长迭代的不足,适用于循环次数未知的场景。
WHILE ... DO 循环
由于 for ... do 循环无法轻松满足所有迭代需求,Pascal 另外提供了两种由布尔表达式控制的循环结构。第一种便是 while ... do 循环:
while <布尔表达式> do <语句>;
只要布尔表达式的值为 True,循环体就会持续执行;若初始判断即为 False,则循环体一次也不会执行。
如果需要,你可以用 while 循环来模拟 for 循环的行为:
<变量> := <初值>;
while <变量> <= <终值> do
begin
<语句>;
<变量> := Succ(<变量>) { 等价于变量自增1 }
end;
若需要自定义步长,只需修改循环体内的递增语句即可。例如,要实现步长为 3 的循环,可将最后一句改为:
<变量> := <变量> + 3;
当然,while 循环的用途远不止模仿 for 循环。下面是一个 二分查找(Binary Search) 的经典示例。该算法在有序列表中查找目标值,直到找到或确认不存在为止。二分查找的优势在于效率极高:对于包含 $n$ 个元素的列表,最多只需 $\log_2 n$ 次比较。这意味着即使列表有 1024 个元素,循环也最多执行 10 次。
procedure BinarySearch(DKey: ListVal;
var Index: Integer;
var Found: Boolean);
{
本过程在有序数组 List[IMin..IMax] 中对 DKey 进行二分查找。
前提条件:List 已按升序排列,即 List[I] <= List[I+1]
功能:查找使得 DKey = List[Index] 的索引值
返回:若找到则 Found = True,否则 Found = False
}
var
Upper, Lower: Integer;
begin
Upper := IMax;
Lower := IMin;
Found := False;
while not Found and (Lower <= Upper) do
begin
Index := (Upper + Lower) div 2;
if DKey < List[Index] then
Upper := Pred(Index) { 目标在左半区 }
else if DKey > List[Index] then
Lower := Succ(Index) { 目标在右半区 }
else
Found := True { 找到目标 }
end;
end; { of proc BinarySearch }
每次进入循环体之前,先计算布尔表达式的值。如果初始条件即为 False,循环体一次也不会执行。
REPEAT ... UNTIL 循环
第三种循环结构是 repeat ... until,其语法格式如下:
repeat
<语句1>;
<语句2>;
...
<语句n>
until <布尔条件>;
它与 while ... do 循环存在三个关键区别:
- 至少执行一次:循环体会先执行,然后再判断布尔条件。因此无论条件是否成立,语句至少会执行一次。
- 终止逻辑相反:当布尔条件为
False 时继续循环,为 True 时终止;而 while 循环恰恰相反(为 True 时继续)。
- 天然支持多语句:
repeat ... until 本身就能包裹多条语句,无需像其他控制结构那样额外使用 begin ... end 复合语句块。
典型应用:输入验证
repeat 循环最常见的用途之一是输入校验:反复提示用户输入,直到获得合法值为止。
以下示例实现了一个“防呆”整数输入过程。它会持续要求用户输入一个位于 [Low, High] 范围内的整数,并在以下两种情况下重新提示:
- 发生 I/O 错误(如输入了非数字字符);
- 输入的数值超出允许范围。
program TestGetInteger;
type
Prompt = string[80];
procedure GetInteger(var Val: Integer;
Msg: Prompt;
Low, High: Integer);
begin
{$I-, R-} { 关闭 I/O 检查和范围检查 }
repeat
Write(Msg);
ReadLn(Val);
until (IOresult = 0) and (Low <= Val) and (Val <= High);
{$I+, R+} { 恢复所有检查 }
end; { of proc GetInteger }
这段代码实现了健壮的整数输入机制。无论用户如何误操作(输入字母、超范围数值等),程序都会持续要求重新输入,直到获得格式正确且在有效范围内的值为止。
核心区别对比
| 特性 |
While...do |
Repeat...until |
| 判断时机 |
循环前 |
循环后 |
| 最少执行次数 |
0 次 |
1 次 |
| 继续/终止逻辑 |
True → 继续 |
True → 终止 |
| 多语句包裹 |
需要 begin...end |
不需要(自带块作用域) |
| 分号 |
do 后面无分号 |
until 后面有分号 |
| 变量作用域 |
循环体内声明的变量外部不可见 |
repeat..until 内声明的变量在 until 条件中可见 |
更多 Lazarus/Pascal 实战内容,可以在 云栈社区 继续查阅。