(2)C语言基础语法精讲
一、数据类型核心要点
1. 整型家族(内存占用与编译器相关)
char c = 'A'; // 1字节,ASCII值65
short s = 30000; // 2字节(-32768~32767)
int i = 2147483647; // 4字节(典型范围)
long l = 123L; // 4或8字节
unsigned int ui = 4000000000; // 无符号扩展范围
// 验证类型大小:
printf("short size: %zu\n", sizeof(short));
2. 浮点类型
float f = 3.1415f; // 4字节,6-7位有效数字
double d = 3.1415926;// 8字节,15位有效数字
// 精度丢失示例:
float money = 0.1f; // 实际存储值≈0.10000000149
3. 特殊类型
void func(void); // 无返回值函数声明
void *ptr = NULL; // 泛型指针
_Bool flag = 1; // C99布尔类型(需)
二、运算符优先级陷阱
常见陷阱案例:
int x = 5, y = 3;
int r1 = x << 1 + 2; // 实际计算x << (1+2) = 5<<3=40
int r2 = x & y == 1; // 实际计算x & (y==1) = 5 & 0=0
// 正确写法:
int r1_safe = (x << 1) + 2; // 10+2=12
int r2_safe = (x & y) == 1; // 5&3=1 → 1==1 → true
解决方案:
1. 复杂表达式加括号明确优先级
2. 拆分多步运算
3. 记忆优先级口诀:算术 > 移位 > 关系 > 位运算 > 逻辑
三、流程控制实战
1. if-else 最佳实践
// 常量放左边避免误写=
if(5 == x) { /* 正确写法 */ }
// 多条件清晰排版
if(age >= 18 &&
hasLicense &&
!isDrunk) {
allowDriving();
}
2. switch 防穿透技巧
switch(deviceState) {
case INIT:
initHardware();
break; // 必须显式中断
case RUNNING:
processData();
// 故意穿透到ERROR处理
case ERROR:
logError();
break;
default:
handleUnknownState();
}
3. 循环控制
// while处理不确定次数循环
while((ch = getchar()) != EOF) {
process(ch);
}
// for固定次数循环(C99支持循环内声明)
for(int i=0; i<10; i++) {
printf("%d ", i);
}
// 防止死循环
unsigned char count = 0;
do {
// 当count=255时,count++会溢出为0
} while(count++ < 200);
四、调试技巧实战
1. printf调试法
#define DEBUG 1
int calc(int a, int b) {
#if DEBUG
printf("[DEBUG] 输入值: a=%d, b=%d\n", a, b);
#endif
int result = a * b;
#if DEBUG
printf("[DEBUG] 计算结果: %d\n", result);
#endif
return result;
}
2. GDB快速入门
# 编译时添加调试信息
gcc -g test.c -o test
# 启动调试
gdb ./test
# 常用命令:
(gdb) break main # 在main函数设断点
(gdb) run # 运行程序
(gdb) next # 执行下一行(不进入函数)
(gdb) step # 进入函数内部
(gdb) print x # 查看变量值
(gdb) watch var # 监控变量变化
(gdb) backtrace # 查看调用栈
(gdb) quit # 退出
调试内存问题:
// 示例问题代码
int *ptr;
*ptr = 5; // 野指针访问
// GDB检测方法:
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
(gdb) backtrace
#0 0x000055555555515d in main () at test.c:5
重点避坑指南
1. 数据溢出:使用`limits.h`中的常量(如INT_MAX)检查边界
2. 浮点比较:不用`==`直接比较,使用误差范围
if(fabs(a - b) < 1e-6) // 判断浮点数相等
3. 循环变量:避免在循环体内修改控制变量
4. switch限制:case值必须是整型常量表达式
本教程建议配合实际代码编写进行验证,每个知识点建议完成:
1. 编写验证程序(如测试不同数据类型的sizeof值)
2. 故意制造错误观察编译器警告
3. 使用GDB跟踪变量变化