引言:从"听话"到"会思考"
欢迎回来!上一节课,我们让程序学会了"说话"------它能打印出Hello, World!,还能做简单的数学题。但你不觉得它有点"死脑筋"吗?我们让它算1+1,它绝不会给你算2+2。它就像一个刚出生的婴儿,你喂它什么,它就吃什么。
今天,我们要给这个婴儿装上大脑 ,让它学会自己做决定 和重复做事情。
- 做决定:比如,"如果今天下雨,我就带伞;否则,我就不带。" 这在我们生活中无处不在。
- 重复做事 :比如,老师让你把"我错了"抄写100遍。你肯定不会傻傻地写100行
printf,你会想:"有没有办法让电脑自己重复100次?"
在编程里,我们管这两种能力叫 "流程控制" 。掌握了它,你的程序就从"计算器"升级成了"自动机器人"!这对于我们未来分析病毒和漏洞至关重要,因为恶意软件的行为就是由无数个判断和循环构成的。
第一部分:程序的"比较心"------运算符详解
想让程序会判断,首先得教会它"比较"。这就需要用到运算符。
1. 算术运算符:老朋友,新规矩
这些你在Python里都见过,但C语言有点"小气"。
| 运算符 | 作用 | 例子 (C语言) | 和Python的差异 |
|---|---|---|---|
+ |
加 | a + b |
一样 |
- |
减 | a - b |
一样 |
* |
乘 | a * b |
一样 |
/ |
除 | a / b |
注意! 5 / 2 结果是 2,不是2.5!因为两个整数相除,结果还是整数,小数部分直接被丢弃(不是四舍五入)。 |
% |
取模(求余数) | 5 % 2 结果是 1 |
一样 |
重点吐槽:C语言没有幂运算符!
在Python里,你可以轻松地写 2**3 来计算2的3次方。在C语言里?没这好事! 你得用 pow(2, 3) 这个函数,而且记得要在开头 #include <math.h>。
底层原理小贴士: 为什么 5 / 2 等于2?因为CPU有专门的整数运算单元,做整数除法非常快。如果要得到小数结果 2.5,你必须至少让其中一个数变成小数形式,比如 5.0 / 2 或 5 / 2.0。这体现了C语言"贴近硬件"的特性,它默认使用最高效的方式。
2. 关系运算符:比比谁大谁小
这些运算符用来比较两个值,结果是"真"或"假"。在C语言中,"真"用数字 1 表示,"假"用数字 0 表示。
| 运算符 | 含义 | 例子 |
|---|---|---|
== |
等于 | 5 == 3 结果是 0 (假) |
!= |
不等于 | 5 != 3 结果是 1 (真) |
> |
大于 | 5 > 3 结果是 1 (真) |
< |
小于 | 5 < 3 结果是 0 (假) |
>= |
大于等于 | 5 >= 5 结果是 1 (真) |
<= |
小于等于 | 5 <= 3 结果是 0 (假) |
血泪教训:= 和 == 是天壤之别!
=是赋值 ,比如a = 5;意思是"把5放进变量a里"。==是比较 ,比如a == 5意思是"看看变量a的值是不是等于5"。- 如果你在
if条件里错写成if (a = 5),编译器可能不会报错,但这行代码的意思是"把5赋给a,然后判断a的值(5)是否为真(真)",结果这个if永远都会执行!这是C程序员最常犯的错误之一。
3. 逻辑运算符:处理复杂条件
当需要同时满足多个条件时,就用它们。
| 运算符 | 含义 | 例子 | 和Python的差异 |
|---|---|---|---|
&& |
逻辑与 (and) | (a > 0) && (a < 10) // a大于0 并且 a小于10 |
Python用关键字 and |
| ` | ` | 逻辑或 (or) | |
! |
逻辑非 (not) | !(a == 0) // a 不等于0 |
Python用关键字 not |
记忆技巧: && 像两根绳子拴在一起,必须都满足。|| 像两条岔路,满足一条就行。
第二部分:程序的"十字路口"------条件分支语句
现在,我们让程序根据比较的结果,走不同的路。
1. if 语句:如果...就...
这是最简单的判断。
c
if (条件) {
// 如果条件为真,就执行这里面的代码
}
例子:
c
int score = 95;
if (score >= 60) {
printf("恭喜,你及格了!\n");
}
2. if-else 语句:如果...就...否则...
二选一。
c
if (条件) {
// 条件为真,执行这里
} else {
// 条件为假,执行这里
}
例子:
c
int age = 16;
if (age >= 18) {
printf("你可以进入网吧。\n");
} else {
printf("未成年人禁止入内!\n"); // 这行会被执行
}
3. else-if 结构:多岔路口
用于多种可能性的判断。
c
int score = 85;
if (score >= 90) {
printf("优秀!\n");
} else if (score >= 80) {
printf("良好!\n"); // 这行会被执行
} else if (score >= 70) {
printf("中等!\n");
} else if (score >= 60) {
printf("及格!\n");
} else {
printf("不及格,要加油了!\n");
}
执行流程: 程序会从上到下逐个判断条件,一旦某个条件为真,就执行对应的代码块,然后直接跳过 后面所有的 else-if 和 else。
4. switch-case 语句:精确匹配
当你的判断是基于一个变量精确等于某个值 时,用 switch 更清晰。
c
int day = 3;
switch (day) {
case 1:
printf("星期一\n");
break; // 记住这个break!
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n"); // 这行会被执行
break;
default: // 如果所有case都不匹配,就执行default
printf("无效的天数\n");
break;
}
break的重要性: break 的作用是跳出整个 switch 语句 。如果没有 break,程序会从匹配到的那个 case 开始,一直执行下去,直到遇到 break 或者 switch 结束!这叫做"case穿透"。(虽然有时故意用它来实现高级功能,但新手务必每个case都加上break)。
底层原理小贴士: 为什么有了if-else还要switch?因为switch在底层实现上,编译器有时会为它生成一种叫跳转表 的机制。想象成一个电梯,switch(变量)直接把你送到对应的楼层(case),非常高效。而一长串的if-else-if则像爬楼梯,需要一层一层地判断。在处理大量分支时,switch性能通常更好。
第三部分:程序的"永动机"------循环语句
现在,我们来解决"抄写100遍"的问题。
1. while 循环:只要...就继续...
先检查条件,再决定是否执行循环体。
c
while (条件) {
// 只要条件为真,就重复执行这里的代码
}
例子:打印1到10
c
int i = 1; // 1. 初始化计数器
while (i <= 10) { // 2. 循环条件
printf("%d\n", i);
i++; // 3. 更新计数器 (i++ 相当于 i = i + 1)
}
注意: 如果你忘了写 i++,i 的值永远不变,条件 i <= 10 就永远为真,循环会永远执行下去,这叫 死循环 。在控制台里,你可以按 Ctrl+C 来强行终止它。
2. do-while 循环:先干再说...
先执行一次循环体,再检查条件。
c
do {
// 先执行这里的代码...
} while (条件); // ...然后看条件是否为真,为真就再执行一次
它与 while 的最大区别: do-while 至少会执行一次循环体,而 while 可能一次都不执行。
例子:让用户输入密码,直到正确为止
c
int password;
int correct_password = 123456;
do {
printf("请输入密码:");
scanf("%d", &password);
} while (password != correct_password);
printf("登录成功!\n");
3. for 循环:全能王
for 循环把循环三要素(初始化、条件、更新)都写在了一行,结构非常清晰,是最常用的循环。
c
for (初始化; 循环条件; 更新) {
// 循环体
}
例子:打印1到10 (for循环版)
c
for (int i = 1; i <= 10; i++) {
printf("%d\n", i);
}
执行顺序:
int i = 1;(初始化,只执行一次)i <= 10;(判断条件,若为真,进入循环体;若为假,结束循环)- 执行
printf("%d\n", i); i++(更新计数器)- 跳回第2步,继续判断...
for循环的底层视角: 你可以把for循环看作是while循环的"语法糖"。编译器最终会把for循环翻译成类似while循环的底层指令。但它把循环控制逻辑封装得更好,使得代码更易读、更不易出错(比如,不容易忘记写计数器更新)。
4. 循环里的两个"叛徒":break 和 continue
break:立刻终止整个循环,直接跳出来。就像在游戏中接到了"立刻撤退"的命令,不管任务完成没有,马上就走。continue:跳过 本次循环中continue之后的代码,直接进入下一次循环。就像体育课上老师让你"跳过这个动作,做下一个"。
例子:
c
// break 例子:找到第一个能被3整除的数就停止
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0) {
printf("找到了:%d\n", i);
break; // 找到6后,立刻结束循环,7、8、9、10就不会被检查了
}
}
// continue 例子:打印1-10中所有的奇数
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) { // 如果是偶数
continue; // 跳过下面的printf,直接进行i++
}
printf("%d 是奇数\n", i); // 只有奇数会执行到这里
}
第四部分:实战演练------思维体操
光说不练假把式,我们来两个经典的练习,把今天学的知识全部用上。
实战一:猜数字游戏
游戏规则: 程序随机生成一个1-100的数字,玩家来猜。程序会根据玩家猜的数字,提示"大了"或"小了",直到猜中为止,并告诉玩家猜了多少次。
代码实现:
c
#include <stdio.h>
#include <stdlib.h> // 为了用rand()和srand()
#include <time.h> // 为了用time()
int main() {
// 1. 生成随机数种子,这样每次运行的随机数才不一样
srand(time(NULL));
// 2. 生成1-100的随机数
int secret_number = rand() % 100 + 1;
int guess;
int count = 0; // 计数器
printf("欢迎来到猜数字游戏!我已经想了一个1-100之间的数字。\n");
do {
printf("请输入你的猜测:");
scanf("%d", &guess);
count++; // 猜的次数+1
if (guess > secret_number) {
printf("太大了!\n");
} else if (guess < secret_number) {
printf("太小了!\n");
} else {
printf("太棒了!你猜对了!就是 %d!\n", secret_number);
printf("你一共猜了 %d 次。\n", count);
}
} while (guess != secret_number); // 只要没猜对,就继续循环
return 0;
}
这个程序综合运用了: do-while循环、if-else-if分支、运算符、变量和输入输出。好好体会它的逻辑流程!
实战二:计算斐波那契数列的前N项
数列规则: 这个数列从0和1开始,后面的每一项都是前两项之和。像这样:0, 1, 1, 2, 3, 5, 8, 13, 21...
代码实现:
c
#include <stdio.h>
int main() {
int n;
printf("请输入要生成斐波那契数列的前几项:");
scanf("%d", &n);
if (n <= 0) {
printf("请输入一个正整数。\n");
} else {
printf("斐波那契数列前 %d 项为:\n", n);
long long a = 0, b = 1, next; // 用long long防止数字太大溢出
for (int i = 1; i <= n; i++) {
if (i == 1) {
printf("%lld ", a); // 第一项是0
} else if (i == 2) {
printf("%lld ", b); // 第二项是1
} else {
next = a + b;
printf("%lld ", next);
a = b; // 更新a和b,为计算下一项做准备
b = next;
}
}
printf("\n");
}
return 0;
}
这个程序综合运用了: for循环、if-else-if分支、变量的更新。它展示了如何用循环来生成一个序列,并处理了边界情况(前两项)。
总结与展望
恭喜你!经过这一节课的学习,你的程序已经"活"过来了。它不再只是机械地执行指令,而是学会了根据情况做决策,并能不知疲倦地重复劳动。
- 运算符是程序进行比较和逻辑判断的工具。
if-else和switch让程序有了选择的能力。while,do-while,for让程序能够自动化地处理重复性任务。break和continue让你能更精细地控制循环的流程。
所有这些,都是构建复杂程序的基石。一个病毒扫描程序,就是通过无数个循环和判断,来检查文件是否匹配病毒特征。一个网络爬虫,也是通过循环来不断地抓取网页。
在下一节课,我们将学习函数------一种能将复杂任务分解成多个小任务的"魔法",这将让我们的代码变得井井有条,威力倍增。旅程越来越有趣了,加油!