7.2 if else 语句
简单形式的if语句让程序选择执行一条语句,或者跳过这条语句。C还提供了if else形式,可以在两条语句之间做选择。我们用if else形式修正程序7.1中的程序段。
if (all_days != 0)
printf("%d days total: %.1f%% were below freezing.\n",
all_days, 100.0 * (float) cold_days / all_days);
if (all_days == 0)
printf("No data entered!\n");
all_days就两个选择,要么等于0,要么不等于0,因此修改为:
if (all_days != 0)
printf("%d days total: %.1f%% were below freezing.\n",
all_days, 100.0 * (float) cold_days / all_days);
else
printf("No data entered!\n");
注意,if else语句的通用形式是:
if( expression )
statement1
else
statement2
如果expression为真(非0),则执行statement1;如果expression为假或0,则执行else后面的statement2。statement1和statement2可以是一条简单语句或符合语句。C并不要求一定要缩进,但这是标准风格。缩进让根据测试条件的求值结果来判断执行哪部分语句
一目了然。
如果要在if和else之间执行多条语句,必须用花括号把这些语句括起来成为一个块。
7.2.1 另一个示例:介绍getchar()和putchar()
scanf()和printf()根据%c转换说明读写字符。
字符输入/输出函数:getchar()和putchar()。
getchar()函数不带任何参数,它从输入队列中返回下一个字符。
ch = getchar() 与 scanf( "%c", &ch )效果相同。
putchar()函数打印它的参数。
putchar( ch ) 与 printf( "%c", ch )效果相同。
由于这些函数只处理字符,所以它们比更通用的scanf()和printf()函数更快、更简单。而且,注意getchar()和putchar()不需要转换说明,因为它们只处理字符。这两个函数通常定义在stdio.h头文件中(而且,它们通常是预处理宏,不是真正的函数)。
下面给程序可描述为“如果打印时空白,原样打印;否则,打印原字符在ASCII序列中的下一个字符”。
// cypher1.c -- alters input, preserving spaces
#include
#define SPACE ' ' // that's quote-space-quote
int main(void)
{
char ch;
ch = getchar(); // read a character
while (ch != '\n') // while not end of line
{
if (ch == SPACE) // leave the space
putchar(ch); // character unchanged
else
putchar(ch + 1); // change other characters
ch = getchar(); // get next character
}
putchar(ch); // print the newline
return 0;
}
/* 输出:

*/
把读取和测试合并成一个表达式。也就是说,可以把这种形式的循环:
ch = getchar(); // read a character
while (ch != '\n') // while not end of line
{
if (ch == SPACE) // leave the space
putchar(ch); // character unchanged
else
putchar(ch + 1); // change other characters
ch = getchar(); // get next character
}
替换成下面形式的循环:
while( (ch = getchar()) != '\n' ){
... /*处理字符*/
}
while( (ch = getchar()) != '\n' )
这体现了C特有的编程风格---把两个行为合并成一个表达式。
还要记住合理使用圆括号组合子表达式。上例中的圆括号必不可少,因为赋值运算符的优先级低于关系运算符。
putchar( ch + 1 ); /*改变其他字符*/
再次演示了字符实际上是作为整数存储的。为计算方便,表达式ch + 1中的ch被转换成int类型,然后int类型的计算结果被传递给接受一个int类型参数的putchar(),该函数只根据最后一个字节确定显示哪个字符。
7.2.2 ctype.h系列的字符函数
斜杠(/)比点号(.)的ASCII码的值多1。
ctype.h头文件包含了专门处理字符的函数的原型。这些函数接受一个字符作为参数,如果该字符属于某特殊的类别,就返回一个非零值(真);否则,返回0(假)。
// cypher2.c -- alters input, preserving non-letters
#include
#include
int main(void)
{
char ch;
while ((ch = getchar()) != '\n')
{
if (isalpha(ch)) // if a letter,
putchar(ch + 1); // display next letter
else // otherwise,
putchar(ch); // display as is
}
putchar(ch); // display the newline
return 0;
}
/* 输出:

*/
ctype.h有些函数涉及本地化,指的是为适应特定区域的使用习惯或扩展C基本用法的工具。
注意,字符映射函数不会修改原始的参数,这些函数只会返回已修改的值。也就是说,下面的语句不改变ch的值:
tolower( ch ); //不影响ch的值
这样做才会改变ch的值:
ch = tolower( ch ); //把chi转换成小写字母
表7.1 ctype.h头文件中的字符测试函数
函数名 如果是下列参数时,返回值为真
isalnum() 字母数字(字母或数字)
isalpha() 字母
isblank() 标准的空白字符(空格、水平制表符或换行符)或任何其他本地化指定为空白的字 符
iscntrl() 控制字符 如Ctrl + B
isdigit() 数字
isgraph() 除空格之外的任意可打印字符
islower() 小写字母
isprint() 可打印字符
ispunct() 标点符号(除空格或字母数字字符意外的任何可打印字符)
isspace() 空白字符(空格、换行符、换页符、回车符、垂直制表符、水平制表符或其他本地 化定义的字符)
isupper() 大写字母
isxdigit() 十六进制字符
表7.2 ctype.h头文件中的字符映射函数
函数名 行为
tolower() 如果参数是大写字符,该函数返回小写字母;否则,返回原始参数
toupper() 如果参数是小写字符,该函数返回大写字符;否则,返回原始参数
7.2.3 多重选择else if
在程序中可以用else if扩展if else结构模拟多种选择的情况。
电费的程序。
// electric.c -- calculates electric bill
#include
#define RATE1 0.13230 // rate for first 360 kwh
#define RATE2 0.15040 // rate for next 108 kwh
#define RATE3 0.30025 // rate for next 252 kwh
#define RATE4 0.34025 // rate for over 720 kwh
#define BREAK1 360.0 // first breakpoint for rates
#define BREAK2 468.0 // second breakpoint for rates
#define BREAK3 720.0 // third breakpoint for rates
#define BASE1 (RATE1 * BREAK1)
// cost for 360 kwh
#define BASE2 (BASE1 + (RATE2 * (BREAK2 - BREAK1)))
// cost for 468 kwh
#define BASE3 (BASE1 + BASE2 + (RATE3 *(BREAK3 - BREAK2)))
//cost for 720 kwh
int main(void)
{
double kwh; // kilowatt-hours used
double bill; // charges
printf("Please enter the kwh used.\n");
scanf("%lf", &kwh); // %lf for type double
if (kwh <= BREAK1)
bill = RATE1 * kwh;
else if (kwh <= BREAK2) // kwh between 360 and 468
bill = BASE1 + (RATE2 * (kwh - BREAK1));
else if (kwh <= BREAK3) // kwh betweent 468 and 720
bill = BASE2 + (RATE3 * (kwh - BREAK2));
else // kwh above 680
bill = BASE3 + (RATE4 * (kwh - BREAK3));
printf("The charge for %.1f kwh is $%1.2f.\n", kwh, bill);
return 0;
}
/* 输出:

*/
实际上,else if是已学过的if else语句的变式。例如。该程序对的核心部分只不过是下面代码的另一种写法:
if (kwh <= BREAK1)
bill = RATE1 * kwh;
else
if (kwh <= BREAK2) // kwh between 360 and 468
bill = BASE1 + (RATE2 * (kwh - BREAK1));
else
if (kwh <= BREAK3) // kwh betweent 468 and 720
bill = BASE2 + (RATE3 * (kwh - BREAK2));
else // kwh above 680
bill = BASE3 + (RATE4 * (kwh - BREAK3));
整个if else语句被视为一条语句,因此不必把嵌套的if else语句用花括号括起来。当然,花括号可以更清楚地表明这种特殊格式的含义。
这两种形式完全等价。唯一不同的是使用空格和换行的位置不同,不过编译器会忽略这些。尽管如此,第1种形式还是好些,因为这种形式更清楚地显示了有4种选择。在浏览程序时,这种形式让读者更容易看清楚各项选择。在需要时要缩进嵌套的部分。
对于编译器的限制范围,C99标准要求编译器至少支持127层套嵌。
7.2.4 else与if配对
规则是,如果没有花括号,else与离它最近的if匹配,除非最近的if被花括号括起来。
记住,编译器是忽略缩进的。
7.2.5 多层嵌套的if语句
前面介绍的if...else if...else序列是嵌套if的一种形式,从一系列选项中选择一个执行。有时,选择一个特定选项后又引出其他选择,这种情况可以使用另一种嵌套if。
验证素数
在编写代码之前要先规划好。
不使用平方根而用div * div <= num这样的测试条件,有两个原因。其一,整数乘法比求平方根块。其二,我们还没有正是介绍平方根函数。
注意
从技术角度看,if else语句作为一条单独的语句,不必使用花括号。外层if也是一条单独的语句,也不必使用花括号。但是,当语句太长时,使用花括号能提高代码的可读性,而且还可以防止今后在if循环中添加其他语句时忘记加花括号。
可以在外层循环把一个变量设置为某个值(如,1),然后在if语句中把该变量重新设置为0。循环完成后,检查该变量是否为1,如果是,说明没有进入if语句,那么该数就是素数。这样的变量通常称为标记(flag)。
一直以来,C都习惯用int作为标记的类型,其实新增的_Bool类型更合适。另外,如果在程序中包含了stdbool.h头文件,便可用bool代替_Bool类型,用true和false分别代替1和0。
为扩大该程序的应用范围,程序用long类型而不是int类型(如果系统不支持stdbool.h头文件,可以把isPrime的类型改为int,并用1和0分别代替程序中的true和false)。
// divisors.c -- nested ifs display divisors of a number
#include
#include
int main(void)
{
unsigned long num; // number to be checked
unsigned long div; // potential divisors
bool isPrime; // prime flag
printf("Please enter an integer for analysis; ");
printf("Enter q to quit.\n");
while (scanf("%lu", &num) == 1)
{
for (div = 2, isPrime = true; (div * div) <= num; div++)
{
if (num % div == 0)
{
if ((div * div) != num)
printf("%lu is divisible by %lu and %lu.\n",
num, div, num / div);
else
printf("%lu is divisible by %lu.\n",
num, div);
isPrime= false; // number is not prime
}
}
if (isPrime)
printf("%lu is prime.\n", num);
printf("Please enter another integer for analysis; ");
printf("Enter q to quit.\n");
}
printf("Bye.\n");
return 0;
}
/* 输出:

*/
该程序会把1认为是素数,其实它不是。
小结:用if语句进行选择
形式3:
if( expression1 )
statement1
else if( expression2 )
statement2
else
statement3
如果expression1为真,执行statement1部分;如果expression2为真,执行statement2部分;否则,执行statement3部分。