选择结构程序设计

在顺序结构中,各语句都是按自上而下的顺序执行的,执行完上一个语句就自动执行下一个语句,是无条件的,不必做任何判断。这是最简单的程序结构。实际上,在很多情况下,需要根据某个条件是否满足来决定是否执行指定的操作任务,或者从给定的两种或多种操作选择其一。这就是选择结构要解决的问题。

选择结构和条件判断

由于程序处理问题的需要,在大多数程序中都会包含选择结构,需要在进行下一操作之前先进行条件判断。

C语言有两种选择语句:

  1. if语句:用来实现两个分支的选择结构
  2. switch语句:用来实现多分支的选择结构

例:题目要求解得 ax2+bc+c=0 方程的根。由键盘输入 a, b, c 假设 a, b, c的值任意,并不保证 b2-4ac>=0。需要在程序中进行判别,如果 b2-4ac>=0,就计算并输出方程的两个实根,如果 b2-4ac<0,就输入“方程无实根”的信息。


//题目要求解得 ax^2 + bc + c = 0 方程的根。
//由键盘输入 a, b, c 假设 a, b, c的值任意,并不保证 b^2 - 4ac >= 0。
//需要在程序中进行判别,如果 b2 - 4ac >= 0,就计算并输出方程的两个实根,
//如果 b2 - 4ac<0,就输入“方程无实根”的信息。

#include <stdio.h>
#include <math.h>

int main(void)
{
	double a, b, c;
	scanf("%lf %lf %lf", &a, &b, &c);

	double dis = b * b - 4 * a * c;
	if (dis < 0)
	{
		printf("方程无实根\n");
		return -1;
	}

	double p = 0 - b / (2 * a);
	double q = sqrt(dis) / (2 * a);

	double x1 = p + q;
	double x2 = p - q;
	
	printf("x1 = %lf\nx2 = %lf\n", x1, x2);

	return 0;
}

在VS编译器内会报C4996错误,解决见下文:(下同)

C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. - EricsT - 博客园 (cnblogs.com)

运行结果:

结果一:走无实根分支

  结果二:走有根分支

用 if 语句实现选择结构

用 if 语句处理选择结构举例

例:输入两个实数,按代数值由小到大的顺序输出这两个数


//例:输入两个实数,按代数值由小到大的顺序输出这两个数

#include <stdio.h>

int main()
{
	double a, b;
	scanf("%lf %lf", &a, &b);

	if (a > b)
		printf("%lf %lf\n", b, a);
	else
		printf("%lf %lf\n", a, b);

	return 0;
}

运行结果:

分支1:

  分支2:

例:输入3个数 a,b,c 要求由小到大顺序输出


//例:输入3个数 a,b,c 要求由小到大顺序输出

#include <stdio.h>

int main()
{
	double a, b, c;
	scanf("%lf %lf %lf", &a, &b, &c);

	if (a > b)
	{
		double temp = a;
		a = b;
		b = temp;
	}//a < b

	if (a > c)
	{
		double temp = a;
		a = c;
		c = temp;
	}//a < c

	if (b > c)
	{
		double temp = b;
		b = c;
		c = temp;
	}//b < c

	printf("%lf %lf %lf\n", a, b, c);

	return 0;
}

运行结果:

if 语句的一般形式

if 语句的一般形式:

if (表达式) 语句1
[else 语句2]

表达式可以是关系表达式、逻辑表达式,甚至是数值表达式。

所谓的关系表达式就是两个数值进行比较的式子。

在 if 语句的一般形式中,方括号内的部分(即 else 子句)为可选的,即可以有,也可以没有

语句1和语句2可以是一个简单的语句,也可以是一个复合语句,还可以是另一个 if 语句(即在一个 if 语句中又包括另一个或多个内嵌的 if 语句)

if 语句常用的3种形式:

if (表达式)    语句1
if (表达式)
    语句1
else
    语句2
if (表达式)    语句1
else if (表达式2)    语句2
else if (表达式3)    语句3
            .         .
            .         .
            .         .
else if (表达式m)    语句m
else                 语句n

整个 if 语句可以写在一行上也可以写在多行上

if 语句无论是写在一行上还是写在多行上,都是属于一个整体,属于同一个语句。

else 子句是不能作为语句单独使用的,必须是 if 语句的一部分,与 if 语句配对使用

内嵌语句也可以是一个 if 语句

在 if 语句中要对给定的条件进行检查,判定所给定的条件是否成立。判断的结果是一个逻辑值“是”或“否”

关系运算符和关系表达式

在C语言中,比较符(或称比较运算符)称为关系运算符。

所谓“关系运算”就是“比较运算”,将两个数值进行比较,判断其比较的结果是否符合给定的条件。

关系运算符及其优先次序

C语言提供6种关系运算符

  1. <    小于
  2. <=    小于或等于
  3. >    大于
  4. >=    大于或等于
  5. ==    等于
  6. !=    不等于

前四种关系运算符的优先级相同,后两种也相同,前四种优先级高于后两种

关系运算符的优先级低于算术运算符

关系运算符的优先级高于赋值运算符

关系表达式

用关系运算符将两个数值或数值表达式连接起来的式子,称为关系表达式

逻辑运算符和逻辑表达式

用逻辑运算符将关系表达式或其他逻辑量连接起来的式子就是逻辑表达式

逻辑运算符及其优先次序

有3种逻辑运算符,与(AND)或(OR)非(NOT)

在 BASIC 和 Pascal 等语言中可以在程序中直接用 AND,OR,NOT作为逻辑运算符,在 C 语言中不能再程序中直接使用 AND,OR,NOT 作为逻辑运算符,而是用其他符号代替

C 逻辑运算符及其含义
运算符 含义 举例 说明
&& 逻辑与  a && b 如果 a 和 b 都是真,则结果为真,否则为假
|| 逻辑或 a || b 如果a 和 b 有一个以上为真,则结果为真,二者都为假,则结果为假
! 逻辑非 !a 如果 a 为真,则 !a 为假,如果 a 为真,则 !a 为假

“&&”和“||”是双目运算符,要求有两个运算对象(操作数)“!”是一目(元)运算符,只要求有一个运算对象

逻辑运算的真值表
a b !a !b a && b a || b

非(!)的优先级高于与(&&),与(&&)的优先级高于或(||)

逻辑运算符中的“&&”和“||”的优先级低于关系运算符,而“!”的优先级高于算术运算符

逻辑表达式

逻辑表达式应该是一个逻辑量“真”或“假”

C语言编译系统在表示逻辑运算结果时,以数值“1”代表“真”,以数值“0”代表“假”,但在判断一个量是否为“真”时,以0代表“假”,以非0代表“真”。即将一个非零的数值认作为“真”

由系统给出的逻辑运算结果不是0技术1,不可能是其他数值。

在逻辑表达式中作为参加逻辑运算的运算对象可以是 0(“假”)或任何非0的数值(按“真”对待)

逻辑运算符两侧的运算对象不但可以是0和1,或者是0和非0整数,也可以是字符型、浮点型、枚举型或指针型的纯量型数据。系统最终以0和非0来判定它们属于“真”或“假”

逻辑运算的真值表
a b !a !b a && b a || b
非0 非0 0 0 1 1
非0 0 0 1 0 1
0 非0 1 0 0 1
0 0 1 1 0 0

在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符

逻辑型变量

是C99所增加的一种数据类型。

可以将关系运算和逻辑运算的结果存到一个逻辑型变量里面,以便分析和运算。

定义逻辑变量用类型符_Bool

在头文件 stdbool.h 中,将 bool 定义为 _Bool 的同义词,同时定义了两个符号常量 true 和 false ,true 代表 1,false 代表 0,用它们分表代表真和假

逻辑变量 bool 和 true 和 false 原本是C++中使用的,现在 C 把它们吸收进 C 新标准,以增加程序的可读性。但是目前使用的有些 C 编译系统并未实现此功能。

条件运算符和条件表达式

条件运算符是由两个符号(“?”和“:”)组成,必须一起使用。要求有3个操作对象,称为三目(元)运算符,它是C语言中唯一的一个三目运算符

条件表达式的一般形式:表达式1 ? 表达式2 : 表达式3 

条件运算符的执行顺序:

  • 先求解“表达式1”
    • 若为真则执行“表达式2”此时“表达式2”的值作为整个条件表达式的值
    • 若为假则执行“表达式3”此时“表达式3”的值作为整个条件表达式的值

条件运算符的优先级高于赋值运算符

条件运算符的优先级比关系运算符和算术运算符都低

例:输入一个字符,判别它是否是大写字母,如果是,将它转换为小写字母;如果不是,不转换,然后输出最后得到的字符。


//例:输入一个字符,判别它是否是大写字母,如果是,将它转换为小写字母;如果不是,不转换,然后输出最后得到的字符。

#include <stdio.h>

int main(void)
{
	char ch;

	scanf("%c", &ch);

	((ch <= 'Z') && (ch >= 'A')) ? (ch = ch + 32) : (ch = ch);

	printf("ch = %c\n", ch);

	return 0;
}

运行结果:

结果1:

,结果2:

条件表达式相当于一个不带关键字 if 的 if 语句,用它处理简单的选择结构可使程序简洁。

选择结构的嵌套

在 if 语句中又包含一个或多个 if 语句称为 if 语句的嵌套

其一般形式:

else 总是与它上面的最近的未配对的 if 配对

例:有一个函数:x < 0 时,y = -1;x = 0 时,y = 0;x > 0 时,y = 1;编一程序,输入一个 x 值,要求输出相应的 y 值


//例:有一个函数:x < 0 时,y = -1;x = 0 时,y = 0;x > 0 时,y = 1;编一程序,输入一个 x 值,要求输出相应的 y 值

#include <stdio.h>

int main(void)
{
	double x;
	int y;

	scanf("%lf", &x);

	if (x < 0)
		y = -1;
	else
	{
		if (0 == x)
			y = 0;
		else
			y = 1;
	}

	printf("y = %d\n", y);

	return 0;
}

运行结果:

结果一:

结果二:

结果三:

用 switch 语句实现多分支选择结构

C语言提供 switch 语句直接处理多分支选择

switch 句是多分支选择语句

例:要求按照考试成绩的等级输出百分制分数段,A等85分以上,B等[70, 84],C等[60, 69],D等为60分以下。成绩由键盘输入


//例:要求按照考试成绩的等级输出百分制分数段,A等85分以上,B等[70, 84],C等[60, 69],D等为60分以下。成绩由键盘输入

#include <stdio.h>

int main(void)
{
	char ch;

	scanf("%c", &ch);

	switch (ch)
	{
	case 'A':
		printf("85以上\n");
		break;
	case 'B':
		printf("70到84\n");
		break;
	case 'C':
		printf("60到69\n");
		break;
	case 'D':
		printf("60以下\n");
		break;
	}

	return 0;
}

运行结果:

结果一:

  结果二:
  结果三:
  结果四:

switch 语句的作用是根据表达式的值,使流程跳转到不同的语句。

switch 语句的一般形式:

switch (表达式)
{
    case 常量1:    语句1
    case 常量2:    语句2
      .    .        .  
      .    .        .  
      .    .        .  
    case 常量n:    语句n
    default:       语句n+1
}

switch 后面括号内的“表达式”其值类型应该为整数类型(包括字符型)

switch 下面的花括号内是一个复合语句。这个复合语句包括若干语句,它是 switch 语句的语句体。语句体内包含多个以关键字 case 开头的语句行和最多一个以 default 开头的行。case 后面跟一个常量(或常量表达式)case 和 default 都是起标号( label 或称标签、标记)的作用,用来标志一个位置。

执行 switch 语句时,先计算 switch 后面的“表达式”的值,然后将它与各 case 标号比较,如果没有与 switch 表达式相匹配的 case 常量,流程转去执行 default 标号后面的语句

可以没有 default 语句,此时如果没有与 switch 表达式相匹配的 case 常量,则不执行任何语句,流程转到 switch 语句的下一个语句。

各个 switch 标号出现的次序不影响执行结果

每一个 case 常量必须互不相同;否则就会出现互相矛盾的现象(对 switch 表达式的同一个值,有两种或多种执行方案)

case 标号只起标记的作用。在执行 switch 语句时,根据 switch 表达式的值找到匹配的入口标号,并不在此进行条件检查,在执行完一个 case 标号后面的语句后,就从此标号开始执行下去,不再进行判断。

一般情况下,在执行一个 case 子句后,应当用 break 语句使流程跳出 switch 结构,即终止 switch 语句的执行。最后一个 case 子句(今为 default 子句)中可不必加 break 语句,因为流程已经到了 switch 结构的结束处。

在 case 子句中虽然包含了一个以上执行语句,但可以不必用花括号括起来,会自动顺序执行本 case 标号后面所有的语句。当然加上花括号也可以。

多个 case 标号可以共用一组执行语句

选择结构程序综合举例

例:写一程序,判断某一年是否为闰年


//例:写一程序,判断某一年是否为闰年

#include <stdio.h>

int main(void)
{
	int year;

	scanf("%d", &year);

	if (((0 == (year % 4)) && (0 != (year % 100))) || (0 == (year % 400)))
		printf("%d是闰年\n", year);
	else
		printf("%d不是闰年\n", year);

	return 0;
}

运行结果:

结果一:

  结果二: