选择结构
对应教学日历:讲次 5-7(3月26日-4月2日)
一、条件的表示
关系表达式
用关系运算符连接:> < >= <= == !=
结果:真 → 1,假 → 0(C 语言没有布尔类型,用 int 表示真假)
逻辑表达式
用逻辑运算符连接:&&(与)、||(或)、!(非)
if (a > 0 && a < 100) // 0 < a < 100 是错误的写法!
if (ch >= 'A' && ch <= 'Z') // 判断是否大写字母
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) // 闰年判断易错:
0 < a < 100在C语言中不等于数学中的 “a 在 0 到 100 之间”。 实际运算:先算0 < a得 0 或 1,再与 100 比较,结果总是真。 正确写法:a > 0 && a < 100
C语言中的”真假”概念
- 假:
0、'\0'、NULL - 真:一切非 0 值(包括负数)
if (3) // 永远为真
if (-1) // 永远为真
if (0) // 永远为假
if ('A') // 永远为真('A' 的 ASCII 码 65 ≠ 0)浮点数的等于判断
// 错误:if (f == 0.0) 浮点数不能用 == 精确比较
// 正确:if (fabs(f) < 1E-6)二、if 语句
单分支
if (表达式)
语句; // 表达式为真时执行双分支
if (表达式)
语句1; // 表达式为真时执行
else
语句2; // 表达式为假时执行多分支
if (表达式1)
语句1;
else if (表达式2)
语句2;
else if (表达式3)
语句3;
else
语句n; // 以上条件都不满足时执行if 语句的嵌套
if (表达式1)
if (表达式2) // 内嵌 if
语句1;
else
语句2; // else 与最近的未配对的 if 匹配
else
语句3;悬空 else 问题:
else总是与它前面最近的、未配对的if匹配。不确定时用{}明确作用域。
复合语句(语句块)
if (a > b)
{
t = a; // 多条语句必须用 {} 括起来
a = b;
b = t;
}三、switch 语句
switch (表达式) // 表达式必须是整数或字符型
{
case 常量1: 语句1; break;
case 常量2: 语句2; break;
...
default: 语句n; // 可选的默认分支
}执行机制
- 计算
switch后表达式的值 - 与各
case后的常量比较 - 匹配成功后从该
case开始执行,直到遇到break或switch结束 - 如果所有
case都不匹配,执行default(如果有)
重点(贯穿现象):如果
case后没有break,会贯穿到下一个case继续执行!这是考试常考点。
switch(score)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5: grade='E'; break; // 0-5 都对应 E
case 6: grade='D'; break;
case 7: grade='C'; break;
case 8: grade='B'; break;
case 9: grade='A'; break;
}四、指针变量初步(讲次 5 引入)
在讲次5引入选择结构的同时,课程也引入了指针的基本概念,为后续章节铺垫。
指针定义与使用
int *p; // 定义一个指向整型的指针变量 p
int x = 100;
p = &x; // p 指向 x(p 存储 x 的地址)
printf("%d", *p); // *p 表示取 p 所指向变量的值(即 x 的值 100)| 符号 | 含义 | 示例 |
|---|---|---|
& | 取地址运算符 | p = &x; |
* | (定义时)声明指针类型 | int *p; |
* | (使用时)指针解引用(取值) | *p = 10; |
核心理解:
p存地址,*p访问该地址的数据。
作业示例
ex6-1:if-else 猜数
#include<stdio.h>
#include<time.h>
#include <stdlib.h>
int main()
{
int a,b;
srand((unsigned)time(NULL));
a=rand()%101; // 随机生成 0-100 的数
printf("输入猜测整数:");
scanf("%d",&b);
if(a==b)
printf("恭喜你猜对了!");
else if(a>b)
printf("小了");
else
printf("大了");
return 0;
}要点:
srand(time(NULL))+rand()%101生成 0-100 随机数if-else if-else三路分支结构
ex6-2:switch 实现成绩评级
#include<stdio.h>
#include <stdlib.h>
int main()
{
int score,temp;
char grade;
printf("enter score:");
scanf("%d",&score);
if((score>100)||(score<0))
{
printf("\n error,try again!\n");
exit(0);
}
if(score==100) temp=9;
else temp=(score%10); // 只取个位数判断
switch(temp)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:grade='E';break;
case 6:grade='D';break;
case 7:grade='C';break;
case 8:grade='B';break;
case 9:grade='A';
}
printf("score=%d,grade=%c\n",score,grade);
return 0;
}要点:
- 先排除非法输入(
score>100 || score<0) - 通过
temp=score%10取个位数简化 switch 分支 - 利用贯穿现象:case 0-5 共享一个执行体
switch的表达式必须是整型(int、char),不能是float- 每个分支末尾的
break不能忘
ex6-3:个税计算(多分支 else-if)
#include<stdio.h>
int main()
{
float yingnashui,nashui;
printf("请输入你的月应纳税所得额:");
scanf("%f",&yingnashui);
if((yingnashui-3000)<1E-6)
nashui=yingnashui*0.03;
else if((yingnashui-12000)<1E-6&&(yingnashui-3000)>1E-6)
nashui=yingnashui*0.1-210;
else if((yingnashui-25000)<1E-6&&(yingnashui-12000)>1E-6)
nashui=yingnashui*0.2-1410;
printf("您应交纳个人所得税为:%8.2f\n",nashui);
printf("--纳税光荣--!\n");
return 0;
}要点:
if-else if-else if多分支结构- 使用
1E-6替代0做浮点比较((yingnashui-3000)<1E-6即yingnashui <= 3000) - 注意各分支的边界划分,不要遗漏或重叠
ex6-4:运算符推断
#include <stdio.h>
int main()
{
int a, b, c;
char op;
scanf("%d,%d,%d", &a, &b, &c);
if (a + b == c) {
op = '+'; printf("%c\n", op);
}
else if (a - b == c) {
op = '-'; printf("%c\n", op);
}
else if (a * b == c) {
op = '*'; printf("%c\n", op);
}
else if (b != 0 && a / b == c) {
op = '/'; printf("%c\n", op);
}
else if (b != 0 && a % b == c) {
op = '%'; printf("%c\n", op);
}
else {
printf("error\n");
}
return 0;
}要点:
- 除法和取余必须先判断除数不为 0:
b != 0 && a / b == c - 注意检查顺序:先判断
b != 0再计算a / b(短路求值)
ex6-5:条件判断 + 简单算法
#include <stdio.h>
int main() {
int n, x, y;
scanf("%d %d %d", &n, &x, &y);
int eaten = (y + x - 1) / x; // 向上取整
int remaining = n - eaten;
if (remaining < 0) {
remaining = 0;
}
printf("%d\n", remaining);
return 0;
}要点:
(y + x - 1) / x是整数向上取整技巧if (remaining < 0) remaining = 0防止负值
ex4-4:指针基础——取地址与解引用
#include<stdio.h>
int main()
{
int x=100,y=200;
int *p,*q,sum;
p=&x; // p 指向 x
q=&y; // q 指向 y
sum=*p+*q; // 取值并相加(*p 即 x 的值)
printf("x的地址=%d\n",p); // 输出地址(应使用 %p)
printf("y的地址=%d\n",q);
printf("*p=%d\n",*p); // 输出 100
printf("*q=%d\n",*q); // 输出 200
printf("*p+*q=%d\n",sum); // 输出 300
return 0;
}要点:
&取变量的地址:p = &x(p 存 x 的地址)*解引用:*p取 p 所指变量的值int *p中*表示 p 是指针类型(定义时),*p表示取值(使用时)- 地址格式符:
%p(不应使用%d,程序此处不规范)
作业重点
if条件中==(等于)和=(赋值)绝对不可混淆else总是与最近的未配对if匹配(悬空 else)- 多语句时用
{}括成复合语句 switch的case后必须是整型常量,不能是变量或浮点数switch没有break会贯穿到下一个case- 浮点数不能直接用
==比较,应判断差的绝对值是否小于一个极小值 &&和||的短路求值规则- 指针基础:
&取地址,*解引用