C语言-流程控制
一、C语言关系运算符
运算符 | 说明 | 例子 |
---|---|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
<、> | 小于和大于 | a > b, a < b |
<=(=<)、=>(>=) | 小于等于和大于等于 | a <= b, a >= b |
! | 非 | !(0)、!(NULL) |
逻辑返回值:bool 类型的 true 和 false。
false:0, null,‘\0’
!!(x): 逻辑归一化。假如 x = 3, !3 = 0, !!3 = 1。
二、分支结构
1. if 语句(选择语句)
// 第一种
if (表达式) {
}
// 第二种
if (表达式) {
代码段1;
} else {
代码段2;
}
// 第三种
if (表达式1) {
代码段1;
} else if (表达式2){
代码段2;
} else {
代码段3;
}
if 作用一条语句(语句:单语句(分号结尾),复合语句(一个花括号所表示的一条语句))。
随堂练习-1
程序读入一个正整数 n,代表学生的成绩,根据分数输出分数档位。
n = 0, FOOLISH
0 < n < 60, FAIL
60 <= n < 75, MEDIUM
75 <= n <= 100, GOOD
代码演示
#include <stdio.h> int main() { int n; while(~scanf("%d", &n)) { if (n == 0) { printf("FOOLISH\n"); } else if (n > 0 && n < 60) { printf("FAIL\n"); } else if (n >= 60 && n < 75) { printf("MEDIUM\n"); } else { printf("GOOD\n"); } } return 0; }
优化:
#include <stdio.h> int main() { int n; while(~scanf("%d", &n)) { if (!n) { printf("FOOLISH\n"); } else if (n < 60) { printf("FAIL\n"); } else if (n < 75) { printf("MEDIUM\n"); } else { printf("GOOD\n"); } } return 0; }
2. switch 语句
switch (a) {
case 1: 代码块1;
case 2: 代码块2;
case 3: 代码块3;
default : 代码块;
}
case 作为条件入口,程序进入 case 所对应的代码段,依次执行后续代码,直到遇到 break,或者 switch 结构末尾。a 要能映射成一个整形值。
随堂练习-2
请使用 switch 结构完成如下任务,程序读入一个整数 n:
如果 n = 1:输出 one
如果 n = 2:输出 two
如果 n = 3:输出 three
否则输出 error
代码:
#include <stdio.h> int main() { int n; while (~scanf("%d", &n)) { switch (n) { case 1: { printf("one\n"); break; } case 2: { printf("two\n"); break; } case 3: { printf("three\n"); break; } default: { printf("error\n"); break; } } } return 0; }
题目练习:回文整数。
操作系统底层:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
// likely 代表 x 经常成立
// unlikely 代表 x 不经常成立
代码:
bool isPalindrome(int x) {
// x < 0 是不经常出现的(这是站在 cpu 指令执行层面的代码优化)
if (__builtin_expect(!!(x < 0), 0)) return false; // 等价于 if (x < 0) return false;
int y = 0, z = x;
while (x) {
y = y * 10 + x % 10;
x /= 10;
}
return z == y;
}
cpu 不喜欢分支结构,因为指令预加载,容易出错,cpu 有自带的分支预测功能,但是有可能失败。一旦发现分支预测之后的结果是错误的, 会回滚之前的操作。之前 cpu 的并行操作,也就相当于变成了串行操作。
相关系列函数:
对于 if else 语句,我们可以用三目运算符去代替: ? : ,这样的话在 cpu 的底层就不需要分支预测。
三、循环结构
1. while 循环
// 每当表达式为真时,代码块就执行一次
while (表达式) {
代码块;
}
// 每当代码段执行一次,就会判断一次表达式是否为真
do {
代码块;
} while (表达式);
一般情况下,两种循环没有差异,都能完成相关任务。但是 while 与 do/while 的循环的差别仅在 while 至少做 0 次,后者至少做一次。
随堂练习-3
请使用 while 循环实现程序,输出 1 – 100
#include <stdio.h> int main() { int n = 1; while (n <= 100) { printf("%d\n", n); n++; } return 0; }
#include <stdio.h> int main() { int n = 1; do { printf("%d\n", n); n++; } while (n <= 100); return 0; }
2. for 语句
for (初始化;循环条件;执行后操作) {
代码块;
}
step 1:初始化
step 2:循环条件判断
step 3:执行代码块
step 4:执行后操作
step 5:跳转到 step2
在使用变量前最近的地方定义变量。在 for 循环里,++i 要比 i++ 快,这是底层实现决定的,后++ 涉及值拷贝的问题。
逻辑与或者逻辑或配合表达式也能实现条件判断。比如: i && printf(“ ”);
回文数字判断
能对 int32 实现判断,因为当超过一定大小之后,如果不是回文数,翻转会超出 INT32_MAX = 2147483647,计算机会用一个负值去表示,也就不影响程序的正确性。
#include <stdio.h> int rev_num(int n) { if (n < 0) return 0; int x = n, temp = 0; while (x) { temp = temp * 10 + x % 10; x /= 10; } return temp == n; } int main() { int n; scanf("%d", &n); printf("%s\n", rev_num(n) ? "yes" : "no"); return 0; }