A for statement, unlike a repeat
or while statement, requires you to specify explicitly the number of
iterations you want the loop to go through. The syntax of a for
statement is
for counter := initialValue
to finalValue do statement
or
for counter := initialValue
downto finalValue do statement
where
· counter is a local variable (declared in the block containing the for
statement) of ordinal type, without any qualifiers.
· initialValue and finalValue are expressions that are
assignment-compatible with counter.
· statement is a simple or structured statement that does not change the value
of counter.
The for statement assigns
the value of initialValue to counter, then executes statement
repeatedly, incrementing or decrementing counter after each iteration.
(The for...to syntax increments counter, while the for...downto
syntax decrements it.) When counter returns the same value as finalValue,
statement is executed once more and the for statement terminates.
In other words, statement is executed once for every value in the range
from initialValue to finalValue. If initialValue is equal
to finalValue, statement is executed exactly once. If initialValue
is greater than finalValue in a for...to statement, or less than finalValue
in a for...downto statement, then statement is never executed.
After the for statement terminates, the value of counter is
undefined.
For purposes of controlling execution of the loop, the expressions initialValue and finalValue are evaluated only once, before the loop begins. Hence the for...to statement is almost, but not quite, equivalent to this while construction:
begin
counter := initialValue;
while counter <= finalValue do
begin
statement;
counter := Succ(counter);
end;
end
The difference between this
construction and the for...to statement is that the while loop
re-evaluates finalValue before each iteration. This can result in
noticeably slower performance if finalValue is a complex expression, and
it also means that changes to the value of finalValue within statement
can affect execution of the loop.
Examples of for statements:
for I :=
2 to 63 do
if Data[I] > Max then
Max := Data[I];
for I :=
ListBox1.Items.Count - 1 downto 0 do
ListBox1.Items[I] := UpperCase(ListBox1.Items[I]);
for I :=
1 to 10 do
for J := 1 to 10 do
begin
X := 0;
for K := 1 to 10 do
X := X + Mat1[I, K] * Mat2[K, J];
Mat[I, J] := X;
end;
for C :=
Red to Blue do Check(C);
Structured Statements: Overview
与repeat、while语句不同,for语句需要明确指定循环次数。for语句的语法是:
for counter := initialValue
to finalValue do statement
或者
for counter := initialValue
downto finalValue do statement
这里,
· 计数器counter是一个局部序数型变量(声明在包含当前for语句的块中),并且不能含有任何限定词。
· 初始值initialValue和结束值finalValue是与计数器counter赋值兼容的表达式。
· 语句statement是简单语句或结构语句,但在语句中不能改变计数器counter的值。
for语句将初始值initialValue的值赋给计数器counter,然后重复执行语句statement,在每次循环之后递增或递减计数器counter的值。(在for...to语句中递增计数器counter的值,在for...downto语句中递减计数器counter的值。)当计数器counter返回的值与结束值finalValue的值相等时,语句statement再被执行一次,for语句终止。换句话说,语句statement将为初始值initialValue到结束值finalValue之间的每个值执行一次。如果initialValue等于finalValue,那么语句statement正好被执行一次。如果在for...to语句中的初始值initialValue大于结束值finalValue,或者在for...downto语句中的初始值initialValue小于结束值finalValue,那么语句statement不会被执行(相当于for语句什么也不做)。for语句终止后,计数器counter的值是不明确的。(因此,不能在for语句之后的语句中立即将计数器counter的值视为finalValue来使用。)
为控制循环的执行,表达式initialValue和finalValue在循环开始之前只被求值一次。因此,for...to语句几乎(但不完全)等价于下面的while语句:
begin
counter := initialValue;
while counter <= finalValue do
begin
statement;
counter := Succ(counter);
end;
end
上面的while语句与相应for...to语句之间的差别在于,while循环在每次重复之前都对finalValue进行了重新求值。这对于finalValue是一个混合表达式的情况来说,显然降低了执行效率;另外,在语句statement中改变finalValue的值也会影响循环的执行。
下面是for语句的一些例子:
for I :=
2 to 63 do
if Data[I] > Max then
Max := Data[I];
for I :=
ListBox1.Items.Count - 1 downto 0 do
ListBox1.Items[I] := UpperCase(ListBox1.Items[I]);
for I :=
1 to 10 do
for J := 1 to 10 do
begin
X := 0;
for K := 1 to 10 do
X := X + Mat1[I, K] * Mat2[K, J];
Mat[I, J] := X;
end;
for C :=
Red to Blue do Check(C);
编者注
什么时候需要使用for...downto语句
在for...to语句中,当一次反复可能会影响到下一次反复时,需要使用for...downto来替换。例如
for I :=
0 to StringList.Count – 1 do begin
if StringList.Strings[I] = 'To Delete' then
StringList.Delete(I);
end;
这里的for...to语句希望执行这样一个程序逻辑:遍历StringList,删除所有串值为 'To
Delete' 的项。这里的语法是完全正确的,编译器也不会报告任何提示和警告。但在执行中就有可能发生异常。这是因为,在每次检查到串值 'To Delete' 并对其删除之后,StringList中的项数就会相应递减,那么,对于每次删除,下一次循环实质上是跳过了一项(被跳过的项代替了被删除项的位置索引),这已经有违初衷了。此外,假定已经删除N(显然N应当小于或等于StringList.Count)项,那么在检查第(StringList.Count – N)项时,将会发生运行时错误,因为这时已经索引不到该项了。
为了详细说明,可以假设StringList中只有四项('Hello', 'To Delete', 'World', 'OK')。
第一次循环(I
= 0)执行后,StringList没有变化;
第二次循环(I
= 1)执行后,串 'To
Delete' 被删除,StirngList变成('Hello', 'World', 'OK');
第三次循环(I
= 2)中,if语句判定的是串 'OK' 而跳过了串 'World' (串 'World' 此时的索引是
1 而不是最初的 2);
第四次循环(I
= 3)中,if语句将试图对表达式 StringList.String[3]
= 'To Delete' 进行求值,这时将会引发异常,导致运行时错误,因为此时StringList有效索引范围是 [0..2] (只有3项)。
因此,对于此类程序逻辑,需要使用for...downto语句。上面的程序逻辑可以写成:
for I := StringList.Count
– 1 downto 0 do begin
if StringList.Strings[I] = 'To Delete' then
StringList.Delete(I);
end;
这样,既不会跳过或漏掉任何一项,也不会引发异常。