第6章 选择结构
对于任何程序设计语言来说,其构造选择的能力都是一项基本特性。选择在执行循环语句时做出,以便确定何时终止循环。Objective-C程序设计语言也提供了其他几种用于构造选择的结构,本章将介绍它们:
·if语句
·switch语句
·conditional运算符
6.1 if语句
Objective-C程序设计语言提供了通用的构造选择能力,其语言结构就是所谓的if语句。这种语句的一般格式为
if(expression)
program statement
假设,要将“如果不下雨,我就去游泳”这样的句子转换成Objective-C语言。使用上述的if语句格式,可用Objective-C将这个句子“编写”成以下形式:
if(不下雨)
我就去游泳
if语句根据指定的条件规定程序语句(或括在花括号中的多条语句)的执行。如果不下雨,我就去游泳。类似地,在程序语句
if(count>MAXIMUM_SONGS)
[playlist maxExceeded];
中,只要count的值大于MAXIMUM_SONGS的值,就会将消息maxExceeded发送给playlist;否则,这条消息将被忽略。
一个实际的程序例子将帮助你理解这一点。假设想要编写一个程序,用于接受从键盘键入的整数,并随后显示这个整数的绝对值。计算整数绝对值的简明方法就是简单地在这个整数小于0时对它求反。在上述语句中使用的短语“如果它小于0”,表示程序必须做出选择。if语句可以影响这个选择,如以下程序所示。
代码清单6-1
//Calculate the absolute value of an integer
import<Foundation/Foundation.h>
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
int number;
NSLog(@“Type in your number:);
scanf(“i”,&number);
if(number<0)
number=-number;
NSLog(@“The absolute value is%i”,number);
[pool drain];
return 0;
}
代码清单6-1输出
Type in your number:
-100
The absolute value is 100
代码清单6-1输出(重新运行)
Type in your number:
2000
The absolute value is 2000
程序执行了两次,以验证它能正确地运行。当然,你可能希望该程序执行更多次,以获得更高水准的可信度,这样就知道该程序确实能正确地工作,但是你至少应该知道,已经检查了该程序所做选择的两种可能结果。
向用户显示一条消息之后,用户将输入整数值,程序将该值存储到number中,然后程序测试number的值以确定该值是否小于0。如果这个值小于0,将执行以下程序语句,对number的值求反。如果number的值不小于0,将自动略过这条程序语句(如果这个值已经是正的,则无需对它求反)。随后,程序将显示number的绝对值,并终止运行。
看一看另一个使用if语句的程序。再向Fraction类添加一个名为convertToNum的方法。这个方法将提供一个用实数表示的分数值。换言之,该方法将用分子除以分母并用双精度的值返回结果。因此,对于分数1/2,该方法将返回值0.5。
这样的方法声明可能如下所示:
-(double)convertToNum;
而且,以下就是它的定义:
-(double)convertToNum
{
return numerator/denominator;
}
当然,并非完全如此。实际上,定义这个方法时有两个重要问题。能发现它们吗?第一个和算术转换有关。你会想起,numerator和denominator都是整型的实例变量。因此,对这两个整数执行除法时,将出现什么情况?正确的情况,它们会作为整数除法来完成!因此,要将分数1/2转换成实数,上述代码将得出结果0!通过在执行除法之前,使用类型强制运算符将一个或两个运算数转换成浮点值,可轻松地解决这个错误。
(double)numerator/denominator
回忆一下,这种运算符的优先级相对较高,因此,在执行除法之前先将numerator转换成double类型。此外,无需转换denominator,因为算术运算的规则将替你完成这项工作。
使用这种方法要注意的第二个问题是应该检查被除数是否为0(总应该检查这种情况)。这个方法的调用者可能由于疏忽而忘记了设置此分数的分母或将分母设置为0,而且你并不希望程序异常终止。
修改后的convertToNum方法显示如下:
-(double)convertToNum
{
if(denominator!=0)
return(double)numerator/denominator;
else
return 0.0;
}
如果分数的denominator为0,此处规定它返回0.0。另外,还可以使用其他选择(如,打印一条错误消息、抛出一个异常,等等),但不在这里做进一步讨论了。
使用这个新方法。下面是用于测试它的测试程序。
代码清单6-2
import<Foundation/Foundation.h>
@interface Fraction:NSObject
{
int numerator;
int denominator;
}
-(void)print;
-(void)setNumerator:(int)n;
-(void)setDenominator:(int)d;
-(int)numerator;
-(int)denominator;
-(double)convertToNum;
@end
@implementation Fraction
-(void)print
{
NSLog(@“i/%i”,numerator, denominator);
}
-(void)setNumerator:(int)n
{
numerator=n;
}
-(void)setDenominator:(int)d
{
denominator=d;
}
-(int)numerator
{
return numerator;
}
-(int)denominator
{
return denominator;
}
-(double)convertToNum
{
if(denominator!=0)
return(double)numerator/denominator;
else
return 0.0;
}
@end
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
Fraction*aFraction=[[Fraction alloc]init];
Fraction*bFraction=[[Fraction alloc]init];
[aFraction setNumerator:1];//1st fraction is 1/4
[aFraction setDenominator:4];
[aFraction print];
NSLog(@);
NSLog(@“g”,[aFraction convertToNum]);
[bFraction print];//never assigned a value
NSLog(@);
NSLog(@“g”,[bFraction convertToNum]);
[aFraction release];
[bFraction release];
[pool drain];
return 0;
}
代码清单6-2输出
1/4
=
0.25
0/0
=
0
将aFraction设置成1/4后,程序会使用convertToNum方法将此分数转换成一个十进制的值。这个值随后就会显示出来,即0.25。
在第二种情况下,没有明确地设置bFraction的值,因此,这个分数的分子和分母会初始化为0,这是实例变量默认的初始值。这就解释了print方法显示的结果。同时,它还导致convertToNum方法中的if语句返回值0,从输出可以验证。
6.1.1 if-else结构
如果有人问你特定的数是偶数还是奇数,最有可能的情况是,通过检查这个数的最后一位数字做出决定。如果最后一位数字是0、2、4、6或8中的任何一个,就能说这个数是偶数。否则,它是奇数。
确定特定的数是偶数还是奇数时,计算机使用一种更方便的方法,它并不检查这个数的最后一位数字来观察此数字是否是0、2、4、6或8,而是简单地通过检验这个数能否整除2来确定。如果能整除2,这个数是偶数;否则,就是奇数。
你已经知道,如何使用模运算符%来计算两个整数相除所得的余数。这种能力使它成为在确定整数能否整除2时使用的理想运算符。如果某个数除以2所得的余数为0,它就是偶数;否则,就是奇数。
现在,编写一个程序用于确定用户键入的整型值是偶数还是奇数,并随后在终端显示一条正确的消息,参见代码清单6-3。
代码清单6-3
//Program to determine if a number is even or odd
import<Foundation/Foundation.h>
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
int number_to_test, remainder;
NSLog(@“Enter your number to be tested:);
scanf(“i”,&number_to_test);
remainder=number_to_test%2;
if(remainder==0)
NSLog(@“The number is even.”);
if(remainder!=0)
NSLog(@“The number is odd.”);
[pool drain];
return 0;
}
代码清单6-3输出
Enter your number to be tested:
2455
The number is odd.
代码清单6-3输出(重新运行)
Enter your number to be tested:
1210
The number is even.
键入一个数后,计算此数除以2所得的余数。第一条if语句测试了这个余数的值,检验它是否等于0。如果等于0,将显示消息“The number is even”。
第二条if语句测试余数,检验它是否不等于0,如果不等于0,就会显示一条消息声明这个数是奇数。
实际的情况是:只要第一条if语句成功,第二条if语句肯定失败;反之亦然。如果回顾本节开始处有关偶数/奇数的讨论,就会知道:如果一个数能被2整除,它就是偶数;否则就是奇数。
编写程序时,这个“否则”的概念使用得相当频繁,以至几乎所有的现代程序设计语言都提供了一个特殊结构来处理这一情况。在Objective-C中,它通常称为if-else结构,一般格式如下:
if(expression)
program statement 1
else
program statement 2
实际上,if-else仅仅是if语句一般格式的一种扩展形式。如果表达式的计算结果是TRUE,将执行之后的program statement 1;否则,将执行program statement 2。在任何情况下,都会执行program statement 1或program statement 2两者中的一个,而不是两个都执行。
可将if-else语句结合到前面的程序中,用单个if-else语句替换程序中的两个if语句。你将看到,使用这种新的程序语句如何实际地帮助程序在一定程度上减少复杂性,同时又提高可读性。
代码清单6-4
//Determine if a number is even or odd(Ver.2)
import<Foundation/Foundation.h>
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
int number_to_test, remainder;
NSLog(@“Enter your number to be tested:);
scanf(“i”,&number_to_test);
remainder=number_to_test%2;
if(remainder==0)
NSLog(@“The number is even.”);
else
NSLog(@“The number is odd.”);
[pool drain];
return 0;
}
代码清单6-4输出
Enter your number to be tested:
1234
The number is even.
代码清单6-4输出(重新运行)
Enter your number to be tested:
6551
The number is odd.
不要忘记,双等号(==)用于相等测试,而单个等号是赋值运算符。如果忘记了这一点,并因疏忽而在if语句中使用了赋值运算符,将会导致许多令人头痛的事。