C语言核心概念速查表

本文整理了 C 语言开发中最核心的概念,供面试复习和日常开发参考。内容涵盖指针、内存、数组、函数、结构体等关键知识点。

指针基础

指针声明与初始化

声明含义
int *p指向 int 的指针
int **p指向指针的指针(二级指针)
int *p[10]指针数组(10个指针元素)
int (*p)[10]数组指针(指向10个int的数组)
int *p()返回指针的函数
int (*p)()函数指针

指针运算

  • p + n - 向前移动 n 个元素(p + 1 真正地址偏移 sizeof(*p) 字节)
  • p - n - 向后移动 n 个元素
  • p++ / ++p - 移动到下一个元素
  • p1 - p2 - 两个指针相差的元素个数

NULL 与 void*

类型说明
NULL空指针常量,值为 0 或 (void*)0
void*通用指针,可转换为其他指针类型
NULL 检查使用 if (p != NULL) 或简写 if (p)

数组与指针

数组名与指针的区别

int arr[10];

/* 以下情况数组名等同于指针:*/
int *p = arr;     // 数组名作为右值
printf("%zu", sizeof(p));  // 指针大小(64位8字节)

/* 以下情况数组名是数组,不是指针:*/
sizeof(arr);      // 整个数组大小:40 字节
sizeof(arr);      // &arr 获取的是整个数组的地址

数组作为函数参数

/* 三种等价的函数声明 */
void func(int arr[10]);   // 声明时写长度(被忽略)
void func(int arr[]);       // 不写长度
void func(int *arr);        // 写成指针形式(推荐)

/* 传递数组及长度 */
void process_array(int *arr, size_t n) {
    for (size_t i = 0; i < n; i++) {
        /* 处理 arr[i] */
    }
}

内存管理

内存分配函数对比

函数用途初始化
malloc(n)分配 n 字节不初始化
calloc(n, s)分配 n 个元素,每个 s 字节全部初始化为 0
realloc(p, n)调整已分配内存大小可能保留原内容
free(p)释放内存-

常见内存错误

错误类型描述调试工具
内存泄漏分配后未释放Valgrind
双重释放free 两次同一指针Valgrind
悬挂指针释放后继续使用Valgrind
缓冲区溢出写入超出分配范围AddressSanitizer
空指针解引用NULL *p = ...GDB

结构体

结构体定义与使用

typedef struct {
    int id;
    char name[32];
    double score;
} Student;

/* 初始化 */
Student s1 = {1, "Alice", 95.5};
Student s2 = {.name = "Bob", .id = 2};  /* 指定初始化器(C99)*/

/* 指针使用 */
Student *p = &s1;
p->id = 10;       /* 等价于 (*p).id = 10 */
printf("%s", p->name);

内存对齐规则

  • 结构体起始地址必须能被最宽成员大小整除
  • 每个成员起始地址必须是其自身大小的整数倍
  • 结构体总大小必须是最大对齐要求的整数倍
  • 使用 #pragma pack(n) 可改变对齐规则
  • 优化技巧: 按大小递减顺序排列成员可减少填充

字符串处理

安全函数(C11/C99 扩展)

不安全安全替代说明
strcpystrcpy_s目标缓冲区大小参数
strcatstrcat_s目标缓冲区大小参数
sprintfsprintf_s格式化安全
getsgets_s已废弃,用 fgets

常用字符串函数

strlen(s)      /* 字符串长度(不含\0)*/
strcmp(s1,s2) /* 字符串比较,0表示相等 */
strncmp(s1,s2,n) /* 比较前n个字符 */
strchr(s,c)    /* 查找字符首次出现位置 */
strstr(s,sub)  /* 查找子串首次出现位置 */
strtok(s,delim) /* 字符串分割(非线程安全)*/

预处理器

常用宏与指令

指令用途
#define定义宏和常量
#ifdef / #ifndef条件编译
#include文件包含
#pragma编译器特定指令
__FILE__当前文件名
__LINE__当前行号
__DATE__编译日期
__TIME__编译时间

防止头文件重复包含

/* 方式1:传统宏保护 */
#ifndef HEADER_H_
#define HEADER_H_
/* 头文件内容 */
#endif

/* 方式2:Pragma once(大多数编译器支持)*/
#pragma once
/* 头文件内容 */

函数

函数指针基础

/* 比较函数类型,qsort 使用 */
int (*compare)(const void *, const void *);

/* 定义并使用函数指针 */
int max(int a, int b) { return a > b ? a : b; }

int (*pmax)(int, int) = &max;
printf("%d", (*pmax)(3, 4));  /* 输出 4 */
printf("%d", pmax(3, 4));      /* 也可简化写法 */

可变参数

#include 

int sum(int count, ...) {
    int total = 0;
    va_list args;
    va_start(args, count);
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);
    }
    va_end(args);
    return total;
}

/* 调用 */
printf("%d\n", sum(3, 1, 2, 3));  /* 输出 6 */

位运算

常用位操作

操作表达式用途
获取第 n 位(x >> n) & 1检查某位
设置第 n 位为 1x | (1 << n)开启某位
设置第 n 位为 0x & ~(1 << n)关闭某位
切换第 n 位x ^ (1 << n)翻转某位
清除最低位的 1x & (x - 1)快速清除最低1
获取最低位的 1x & (-x)提取最低1

标志位操作示例

#define FLAG_READ   0x01  /* 0001 */
#define FLAG_WRITE  0x02  /* 0010 */
#define FLAG_EXEC   0x04  /* 0100 */
#define FLAG_ALL    0x07  /* 0111 */

int flags = 0;

/* 设置标志位 */
flags |= FLAG_READ | FLAG_WRITE;

/* 检查标志位 */
if (flags & FLAG_READ) { /* 可读 */ }

/* 清除标志位 */
flags &= ~FLAG_WRITE;

/* 切换标志位 */
flags ^= FLAG_EXEC;

常见陷阱

易错点总结

  • 赋值 vs 等于:if (a = b) 是赋值,不是比较
  • 浮点数比较:避免用 == 比较浮点数,用 fabs(a-b) < eps
  • 贪心解析:*p++ 是 *(p++),不是 (*p)++
  • switch 穿透:每个 case 记得加 break,除非有意穿透
  • 整数溢出:a + b 可能溢出,考虑用 long long
  • 隐式类型转换:char + int 会自动提升为 int
  • size_t:循环变量用 size_t 更安全(无符号)

常用调试命令

GDB 快速参考

命令简写用途
runr启动程序
breakb设置断点
nextn单步执行(不进入函数)
steps单步执行(进入函数)
printp打印变量值
backtracebt显示调用栈
continuec继续执行
quitq退出 GDB

总结

这份速查表涵盖了 C 语言最核心的概念。建议收藏本文,面试前或开发中遇到不确定的地方可以快速查阅。更多详细内容请参考站内其他技术文章。