11类C语言易错点,你一定犯过的错

C语言作为一门底层且灵活的编程语言,存在许多容易混淆或出错的知识点。以下是一些常见的易错点及其解析:


在这里插入图片描述

1. 指针与数组

  • 混淆点:指针和数组的相似性与差异。

    • 数组名不是指针:数组名是首元素地址的常量(不可修改),但 sizeof(arr) 返回数组总大小,而指针返回指针的大小。
    • 声明区别int *p 是指针,int a[10] 是数组。尽管 p = a 合法,但 a = p 非法(数组名不可修改)。
    int a[5];
    int *p = a;      // 合法
    a = p;           // 非法!
    
  • 函数参数传递:数组作为函数参数时退化为指针。

    void func(int arr[]); // 实际等价于 void func(int *arr)
    

2. 内存管理

  • 内存泄漏:忘记释放 malloc/calloc 分配的内存。

    int *p = (int*)malloc(10 * sizeof(int));
    // 必须最后调用 free(p);
    
  • 野指针:释放内存后未置空指针。

    free(p);
    p = NULL; // 避免后续误用
    
  • 重复释放:对同一指针多次调用 free 会导致未定义行为。


3. 指针与函数

  • 函数指针与指针函数
    • 指针函数:返回指针的函数,如 int* func();
    • 函数指针:指向函数的指针,如 int (*func_ptr)(int, int);
    int add(int a, int b) { return a + b; }
    int (*func_ptr)(int, int) = add; // 函数指针
    

4. 预处理与宏

  • 宏的副作用:宏参数可能被多次求值。

    #define MAX(a, b) ((a) > (b) ? (a) : (b))
    int x = 1, y = 2;
    MAX(x++, y++); // x++ 可能被求值两次!
    
  • 条件编译陷阱

    #ifdef DEBUG
      // 可能因为未定义 DEBUG 被忽略
    #endif
    

5. 结构体与联合体

  • 内存对齐:结构体成员因对齐规则导致实际大小与预期不同。

    struct S {
        char c;    // 1字节
        int i;     // 4字节(可能在前填充3字节)
    };
    // sizeof(struct S) 可能是 8 而非 5
    
  • 联合体共享内存:所有成员共享同一块内存,修改一个会影响其他成员。


6. 作用域与链接性

  • static 关键字

    • 函数内:变量生命周期延长到程序结束,但作用域仍为局部。
    • 全局变量/函数:限制为当前文件可见(避免命名冲突)。
  • extern 关键字:声明变量/函数在其他文件中定义。


7. 类型转换与溢出

  • 隐式类型转换:混合类型运算可能导致意外结果。

    int a = 5;
    float b = a / 2;    // 结果为 2.0(整数除法)
    float c = (float)a / 2; // 正确:2.5
    
  • 有符号与无符号比较

    int a = -1;
    unsigned int b = 100;
    if (a < b) { /* 结果为 false!因为 a 被转为无符号数 */ }
    

8. 标准库函数误用

  • 字符串函数

    • strcpy 不检查缓冲区大小,可能导致溢出,推荐 strncpy
    • strlen 返回长度不包含 \0,分配内存时需 +1
  • scanf 的陷阱:

    char str[10];
    scanf("%s", str); // 输入超长会导致溢出,建议用 fgets
    

9. 运算符优先级

  • 常见错误

    if (x & 1 == 0) { ... } // 实际等价于 x & (1 == 0)
    // 应写为 if ((x & 1) == 0)
    
  • 自增/自减运算符

    int i = 0;
    int j = i++ + i++; // 未定义行为(同一变量多次修改)
    

10. 未定义行为(UB)

  • 常见UB场景
    • 数组越界访问:int arr[3]; arr[5] = 10;
    • 使用未初始化变量:int x; printf("%d", x);
    • 修改字符串字面量:char *s = "hello"; s[0] = 'H'; (应使用字符数组)

11. 浮点数比较

  • 精度问题:直接比较浮点数可能导致错误。
    float a = 0.1 + 0.2;
    if (a == 0.3) { /* 可能不成立! */ }
    // 应使用误差范围:fabs(a - 0.3) < 1e-6
    

总结

C语言的灵活性是一把双刃剑,需要严格遵循语法规则和内存管理原则。建议通过以下方法避免错误:

  1. 使用静态分析工具(如 clang-tidy)。
  2. 启用编译器警告(如 gcc -Wall -Wextra)。
  3. 编写单元测试验证边界条件。
  4. 阅读经典书籍(如《C陷阱与缺陷》)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值