2
基础语法:变量、运算符、流程控制
Types · Operators · Control Flow
这一章是"识字"。C 的语法比 Python 啰嗦(每行都要分号、类型要写明),但规则简单粗暴,半天就能过完。重点是记住每个数据类型占几个字节——这是后面学指针和内存的地基。
变量与数据类型:每个类型占几个字节
C 是"强类型"语言,每个变量出生前必须报上户口(什么类型)。sizeof 运算符能告诉你一个类型占多少字节(1 字节 = 8 个二进制位)。
| 类型 | 典型大小 | 装什么 |
|---|---|---|
char | 1 字节 | 一个字符(如 'A'),本质是 0~127 的小整数。 |
short | 2 字节 | 小整数,范围约 ±3 万。 |
int | 4 字节 | 最常用的整数,范围约 ±21 亿。 |
long | 4 或 8 字节 | 更大的整数(64 位系统上通常 8 字节)。 |
float | 4 字节 | 单精度小数,约 6~7 位有效数字。 |
double | 8 字节 | 双精度小数,约 15 位有效数字,默认用它。 |
_Bool / bool | 1 字节 | 真或假(C99 后 include <stdbool.h> 就能写 bool)。 |
变量声明、初始化、用 sizeof 探大小
#include <stdio.h>
#include <stdbool.h> // 为了能用 bool / true / false
int main() {
int age = 18;
double pi = 3.14159265;
char grade = 'A'; // 字符用单引号
bool done = false;
printf("int 占 %zu 字节\n", sizeof(int)); // %zu 是 sizeof 的专用格式符
printf("你今年 %d 岁,等级 %c\n", age, grade);
return 0;
}
运行结果
int 占 4 字节
你今年 18 岁,等级 A
运算符:算术、关系、逻辑、位、三目
运算符和别的语言差不多,但有几个 C 特色(++ 自增、&& 短路、三目 ?:)。位运算在嵌入式和网络编程里天天见,第 10 章单独讲。
常见运算符一览
int a = 10, b = 3;
a + b // 13 加
a / b // 3 整数除法,小数直接砍掉(10/3 = 3,不是 3.33)
a % b // 1 取余数,判断奇偶全靠它
a == b // 假 注意:判断相等是两个等号 ==,一个等号 = 是赋值!
a > b // 真
(a > 5) && (b > 5) // 假,&& 是"并且",左边为假右边直接不算(短路)
(a > 5) || (b > 5) // 真,|| 是"或者"
(a > b) ? "大" : "小" // 三目运算:条件 ? 真时 : 假时
祖传大 bug
把判断相等写成赋值:if (a = 5) 是把 5 赋给 a,然后永远为真,整个分支形同虚设。正确写法是 if (a == 5)。老程序员为了防手滑,故意写成 if (5 == a)——把常量放左边,一旦漏写成 =,编译器会当场报错。
类型转换:隐式的会偷偷搞事
C 在计算时会自动把"小类型"往"大类型"提升(int 遇到 double,int 先变 double)。你也可以用 (类型) 手动强制转换。
整数除法的坑 + 强制转换
int x = 7, y = 2;
double r1 = x / y; // 3.0 —— 两个 int 先除完得 3,再变 double,小数丢了!
double r2 = (double)x / y; // 3.5 —— 先把 x 强转成 double,y 自动跟着提升,才算对
printf("%f %f\n", r1, r2);
运行结果
3.000000 3.500000
流程控制:if / switch / 循环
和其他语言长得几乎一样,唯一需要单独点名的是 switch 的 break,以及 C 里那个名声不太好的 goto。
if / for / while 与 switch 忘写 break 的后果
int score = 85;
// if-else:判断等级
if (score >= 90) printf("A\n");
else if (score >= 60) printf("及格\n");
else printf("补考\n");
// for:从 0 数到 4
for (int i = 0; i < 5; i++) {
printf("%d ", i);
}
// 输出:0 1 2 3 4
// switch:千万别忘 break,不然会"贯穿"下去
switch (score / 10) {
case 10:
case 9: printf("优秀\n"); break; // 不加 break 就会继续往下执行 case 8
case 8: printf("良好\n"); break;
default: printf("继续加油\n"); // 以上都不匹配时走这里
}
运行结果
及格
0 1 2 3 4
良好
谈关于 goto
教科书都劝你别用 goto,因为它会把代码跳得满世界都是、像面条一样乱("面条式代码")。但它在一种场景下是合理且优雅的:函数出错时,从多层嵌套里一次性跳到末尾统一释放资源。很多内核代码就是这么用的。记住:goto 不是洪水猛兽,乱跳才是。