6.3 Boolean变量
几乎所有学习程序设计的人很快就会发现自己要解决这样一个问题,即编写一个程序生成素数表。为了提醒你,回顾一下:如果一个正整数p不能被1和它本身之外的其他任何整数整除,就是一个素数。第一个素数规定为2。下一个素数是3,因为它不能被1和3之外的任何整数整除;而4不是素数,因为它能被2整除。
可以采用几种方法来生成素数表。例如,如果你的任务是生成50以内的所有素数,那么最直接的(也是最简单的)算法是生成这样一个表:它仅仅对每个整数p测试是否能被2到p-1间的所有整数整除。如果这样的任何整数能整除p,那么p就不是素数;否则,p就是素数。
代码清单6-10生成了2到50之间的素数列表。
代码清单6-10
//Program to generate a table of prime numbers
import<Foundation/Foundation.h>
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
int p, d,isPrime;
for(p=2;p<=50;++p){
isPrime=1;
for(d=2;d<p;++d)
if(p%d==0)
isPrime=0;
if(isPrime!=0)
NSLog(@“i”,p);
}
[pool drain];
return 0;
}
代码清单6-10输出
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
关于代码清单6-10,有几个要点值得注意。最外层的for语句建立了一个循环,周期性地遍历2到50间的整数。循环变量p表示当前正在测试以检查是否是素数的值。循环中的第一条语句将值1指派给变量isPrime。你很快就会明白这个变量的用途。
建立的第二个循环用于将p除以从2到p-1间的所有整数。在该循环中,要执行一个测试以检查p除以d的余数是否为0。如果为0,就知道p不可能是素数,因为它能被不同于1和它本身的整数整除。为了表示p不再可能是素数,可将变量isPrime的值设置为0。
执行完最内层的循环时,测试isPrime的值。如果它的值不等于0,表示没有发现能整除p的整数;否则,p肯定是素数,并显示它的值。
你可能已经注意到,变量isPrime只接受值0或值1,而不是其他值。只要p还有资格成为素数,它的值就是1。但是一旦发现它有整数约数时,它的值将设为0,以表示p不再满足成为素数的条件。以这种方式使用的变量一般称作Boolean变量。通常,一个标记只接受两个不同值中的一个。此外,标记的值通常要在程序中至少测试一次,以检查它是on(TRUE或YES)还是off(YES或TRUE),而且根据测试结果采取的特定操作。
在Objective-C中,标记为TRUE或FALSE的概念大部分被自然地转换成值1或0。因此在代码清单6-10中,在循环中将isPrime的值设置为1时,实际上将把它设置成TRUE表示p“是素数”。如果在内层for循环的执行过程中发现了一个偶数约数,isPrime的值将设置为FALSE以表示p不再“是素数”了。
以下情况并不一致:值1通常用于表示TRUE或on状态,而0用于表示FALSE或off状态。这种表示与计算机内部单个比特的概念对应。当比特位于开状态时,它的值是1;当位于关状态时,值是0。但在Objective-C中,有一种甚至更令人信服的理由来支持这些逻辑值。这与Objective-C语言处理TRUE和FALSE概念的方式有关。
在开始本章的讨论时我们注意到,如果满足if语句内部指定的条件,将执行其后的程序语句。但是满足的确切含义是什么?在Objective-C中,满足意味着非零,而不是其他的值。因此,语句
if(100)
NSLog(@“This will always be printed.”);
将导致执行NSLog语句,因为if语句中的条件(本例中仅指值100)非零,因此它是满足的。本章的每一个程序中,都会用到这个概念,即“非零意味着满足”和“零意味着不满足”。
这是因为,只要对Objective-C中的关系表达式进行求值,如果满足表达式时结果将为1,不满足时将为0。因此,语句
if(number<0)
number=-number;
的求值实际上按以下步骤进行:求关系表达式number<0的值。如果条件满足,就是,如果number小于0,表达式的值将是1;否则,它的值是0。
if语句测试了表达式求值的结果。如果结果非零,将执行其后的语句;否则,将略过这条语句。
前面的讨论还用到for、while和do语句中的条件求值。如以下语句中的复合关系表达式的求值
while(char!=‘e’&&count!=80)
也会收到前面指出的结果。如果指定的两个条件都满足,结果是1;但如果有任何一个条件不满足,求值的结果就是0。然后,检查求值的结果。如果结果为0,while循环就会终止;否则,它会继续执行。
回到代码清单6-10和标记的概念上,使用表达式测试标记的值是否为TRUE,这在Objective-C中是相当合法的,例如
if(isPrime)
等价于
if(isPrime!=0)
要方便地测试标记的值是否为FALSE,需要使用逻辑非运算符。在以下表达式中,
if(!isPrime)
使用逻辑非运算符来测试isPrime的值是否为FALSE(这条语句可读做“如果非isPrime”)。一般来说,如下表达式
!expression
用于对expression的逻辑值求反。因此,如果expression为0,逻辑非运算符将产生1。并且如果expression的求值结果非零,逻辑非运算符就会产生0。
可以使用逻辑非运算符轻易地跳过标记的值,如在以下表达式中:
my_move=!my_move;
正如你期望的,这种运算符的优先级和一元运算符相同。这意味着与所有二元算术运算符和关系运算符相比,它的优先级较高。因此,要测试变量x的值是否不小于变量y的值,如在
!(x<y)
中,圆括号是必需的,它用于确保表达式的正确求值。当然,也可将上述语句等价地表示为
x>=y
Objective-C中有一对内置的特性可以使Boolean变量的使用更容易一些。一种是特殊类型BOOL,它可以用于声明值非真即假的变量。另一种是内置值YES或NO。在程序中使用这些预定义的值可使它们更易于编写和读取。下面是使用这些特性重写的代码清单6-10。
注意类型BOOL其实是由一种称为预处理程序的机制添加的。
代码清单6-10A
//Program to generate a table of prime numbers
//second version using BOOL type and predefined values
import<Foundation/Foundation.h>
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
int p, d;
BOOL isPrime;
for(p=2;p<=50;++p){
isPrime=YES;
for(d=2;d<p;++d)
if(p%d==0)
isPrime=NO;
if(isPrime==YES)
NSLog(@“i”,p);
}
[pool drain];
return 0;
}
代码清单6-10A输出
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47