指针 #
- 指针是变量的引用,指针变量保存的是变量的地址。
注意事项 #
- 数组名为首元素地址,我们可以将其看作一个指针,但该指针值是一个常量,不能修改,所以给数组名自增/自减或赋值都是不允许的。
- 利用指针变量间接访问内存数据,指针变量能访问多大的内存空间,取决于指针变量的类型
- static int 无法直接用变量/运行时表达式初始化,是因为静态变量的初始化必须在编译时完成,而变量、函数结果等属于「运行时才能确定」的值,无法满足「编译时常量」的要求。但可以通过「先声明静态变量,再在运行时赋值」的方式,间接实现用变量值初始化静态变量的效果。
指针类型 #
常量指针 #
- const int *p;
- 数据无法修改,但指针可以修改。
- 常量数据需要再定义静态变量时初始化,不能用变量初始化。
指针常量 #
- int *const p;
- 指针可以修改,但数据无法修改。
- 指针常量定义时,必须初始化。
数组指针 #
- int (*p)[N];
- 数组指针是指向数组的指针。
- 数组指针往往是用于接收二维数组地址的,并且可以间接访问二维数组中的数据。
指针数组 #
- int *p[N];
- 指针数组是元素是指针类型的数组。
- 用于数组外排序
字符指针 #
- char *p;
- 字符指针是指向字符的指针。
- 保存字符串的两种方法:字符指针、字符数组 区别:
- 字符指针保存的是字符串的地址,字符串的内容不能改变。
- 字符数组保存的是字符串的内容,字符串的内容可以改变。
- 创建字符指针时,必须初始化,否则会报错。
- 字符数组其实是保存了字符串常量的一份内存拷贝,而字符指针是直接引用字符串常量本身。
函数指针 #
- int (*p)(int, int);
- 函数指针是指向函数的指针。
- 函数指针可以作为参数传递给其他函数,也可以作为返回值返回给其他函数。
- 应用场景:回调函数
指针函数 #
- int *func(int a, int b);
- 指针函数是指向函数的指针。
- 指针函数返回地址,要求函数返回后,该地址上的数据不能被回收。
多级指针 #
- int **p;
- 多级指针是指向指针的指针。
- 多级指针可以保存多维数组的地址。
- 应用场景:main函数参数,argv参数为多维数组,argv[0]为字符串数组,argv[0][0]为字符。
动态内存管理 #
- malloc()函数分配内存,返回一个指针,指向分配的内存。 参数:size_t size
- calloc()函数分配内存,返回一个指针,指向分配的连续内存。 参数:size_t nmemb, size_t size
- realloc()函数重新分配内存,返回一个指针,指向重新分配的内存。 参数:void *ptr, size_t size
内存操作 #
- memset()函数将内存块设置为某个值。 参数:void *ptr, int value, size_t n 常用:内存空间清零
- memcpy()函数将内存块复制到另一个内存块。 参数:void *dest, const void *src, size_t n
- memmove()函数将内存块复制到另一个内存块,但允许内存块重叠。 参数:void *dest, const void *src, size_t n
- memcmp()函数比较内存块。 参数:const void *ptr1, const void *ptr2, size_t n
结构体 #
- 使用 typedef 定义结构体,使用时不需要在写 struct
- 结构体指针 *p = &s; p->name = “新名字”;
- 结构体总大小:必须是最大成员类型大小的整数倍。
- offsetof 获取成员偏移量
数组成员定义 #
| 结构体成员 | 核心特点与初始化方式 | 优缺点及注意事项 |
|---|---|---|
定长字符数组char name[20]; | 最推荐、最安全。 1. 初始化:声明时可用 {..., "鼠标"} 直接赋值。2. 修改值:必须用 strcpy(p.name, "新名字");。 | 优点:内存自动管理,不易出错,适合绝大多数场景。 缺点:长度固定,无法存储超过数组长度的字符串。 |
字符指针char *name; | 灵活但需谨慎。 1. 初始化:声明时可用 {..., "鼠标"} 指向常量。2. 修改值:可直接用 p.name = "新名字"; 改变指向。 | 优点:赋值极其方便,节省空间。 致命坑:指向常量字符串时绝对不可修改内容(否则程序崩溃);若要接收用户输入,必须先手动 malloc 分配内存。 |
柔性数组成员char name[]; | 高级用法(不推荐新手)。 1. 初始化:不能使用普通的静态变量和花括号初始化。 2. 使用:必须配合 malloc(sizeof(struct) + 长度) 动态分配。 | 优点:内存连续,适合处理不定长数据且追求极致性能的场景。 缺点:用法复杂,极易踩到内存越界或管理的坑。 |
联合体 #
- 联合体成员共用同一块内存,只能同时保存一个成员变量的值,按不同类型解释。
- 联合体大小为最大成员变量大小。
区别:
| 对比 | struct | union |
|---|---|---|
| 内存 | 各成员独立 | 共享内存 |
| 大小 | 成员总和(含对齐) | 最大成员大小 |
| 成员能否同时使用 | 可以 | 不可以 |
| 作用 | 描述对象 | 节省内存 |
大小端 #
- 大小端 CPU存储多字节数据时:字节存放顺序不同
- 小端,低位存放在低地址,高字节存放在高地址; 大端,高字节放低地址。
#include <stdio.h>
union Test
{
int a;
char b;
};
int main()
{
union Test t;
t.a = 1;
if (t.b == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
}枚举 #
- 枚举类型用于定义一组命名的常量。
- typedef 配合 enum
- 枚举成员可以值相同,枚举成员不能重复定义名字,枚举成员是常量
| 对比 | enum | #define |
|---|---|---|
| 类型 | 有类型 | 无类型 |
| 调试 | 更方便 | 不方便 |
| 可读性 | 高 | 一般 |
| 本质 | 整数常量 | 文本替换 |
