C语言进阶知识点笔记


一、void* 与内存操作函数

1. void* 无类型指针

  • 本质:存储地址值,不关联具体数据类型

  • 限制:不能进行算术运算(+/-),不能直接解引用(*p)(不知类型空间)。

  • 用途:通用内存操作、泛型函数参数。


ElemType val;
void* p = &val;  // 合法,存储val的地址
// *p; p++;  // 均为非法操作

2. memset:内存初始化

  • 作用:逐字节将内存块赋值为指定值(常用于清零)。

  • 原型void* memset(void* ptr, int value, size_t num);

  • 示例


int a = 0;
memset(&a, 0, sizeof(a));  // 将变量a的所有字节置0

int arr[100];  // 未初始化时为随机值
memset(arr, 0, sizeof(int) * 100);  // 将数组arr全部置0
  • 注意:按字节赋值,若value非0,仅对字符类型或无符号字符(一个字节)类型有预期效果,对int等多字节类型会产生非预期值。
  • why:例如给一个int 类型赋值1,赋值结果为| 1111 |(因为有4个字节,每个字节都赋值为1),

3. memcpy:内存拷贝

  • 作用:将src指向的n字节数据拷贝到aim指向的内存。

  • 原型void* memcpy(void* aim, const void* src, size_t n);

  • 示例


int a = 10, b;
memcpy(&b, &a, sizeof(int));  // 等价于 b = a

int arr[] = {1,2,3,4,5,6,7};
int brr[7] = {8,9};
// 将arr中{3,4,5}拷贝到brr的{9}之后
memcpy(brr+2, arr+2, 3*sizeof(int));
// 结果 brr = {8,9,3,4,5,?,?}
  • 限制不处理内存重叠,若源和目标内存区域重叠,结果未定义。

4. memmove:安全内存拷贝(处理重叠)

  • 作用:功能同memcpy,但能正确处理内存重叠场景。

  • 核心逻辑

    • src + n >= aim(源区域在目标区域前方且重叠),从后往前拷贝,避免覆盖未读数据。

    • 否则,直接调用memcpy从前往后拷贝。

  • 示例


int arr[] = {1,2,3,4,5,6,7,8};
// 将{2,3,4,5}拷贝到{4,5,6,7}位置(内存重叠)
memmove(arr+3, arr+1, 4*sizeof(int));
// 结果 arr = {1,2,3,2,3,4,5,8}
  • 对比memmove更安全,memcpy在无重叠场景下效率更高。

5. memcmp:内存比较

  • 作用:逐字节比较两块内存的前n个字节。

  • 返回值

    • 0:两块内存内容完全相同。

    • 正数:第一块内存大于第二块。

    • 负数:第一块内存小于第二块。


二、结构体(struct

1. 基础定义与使用


// 定义结构体类型
struct Student {
    char name[20];
    int age;
};

// 定义变量
struct Student s1;          // 单个变量
struct Student arr[2];      // 结构体数组
struct Student* p = &s1;    // 结构体指针

2. typedef 重命名

  • 简化类型名,避免重复写struct关键字。

typedef struct Student {
    char name[20];
    int age;
} Student;  // Student 现在是类型名,等价于 struct Student

Student stu = {"zs", 10};  // 直接使用新类型名
  • 进阶用法:

typedef int Array[2];      // Array 代表 int[2] 类型
Array brr;                 // 等价于 int brr[2]

typedef int (*PFun)(int, int);  // PFun 代表函数指针类型
int add(int a, int b) { return a+b; }
PFun p = add;  // 函数指针变量

3. 成员访问

  • 变量:用.访问成员:s1.age = 20;

  • 指针:用->访问成员:p->age = 20;(*p).age = 20;

4. 结构体大小与内存对齐

  • 编译器会自动进行内存对齐,以提升访问效率,结构体大小通常大于各成员大小之和。

  • 规则:

    1. 每个成员的起始偏移量是自身大小的整数倍。(如int必须要4的倍数,short要2的倍数)

    2. 结构体总大小是其最大成员大小的整数倍。

  • 示例:


struct S {
    char c;    // 1字节
    int i;     // 4字节(起始偏移量为1,则要补3个字节)
    short s;   // 2字节(起始偏移量为8,则要补0个字节)
};
// 实际大小:12字节(对齐后)而非 7字节(1+4+3+2=10,补到12是4的倍数)

5. 位段设计

  • 作用:在一个整型变量内分配若干位,用于节省存储空间。

  • 规则

    • 位段成员必须是无符号整数类型unsigned int/short/char)。

    • 不能取位段成员的地址

    • 位段跨单元存储时由编译器决定,可移植性差。

  • 示例:


struct Room {
    unsigned short roomid : 9;  // 占9位,范围 0~511
    unsigned short isused : 1;  // 占1位,0/1
    unsigned short price : 6;   // 占6位,范围 0~63
};
// 总位宽 9+1+6=16位,占用2字节

三、枚举(enum

1. 定义与使用

  • 本质是一组命名的整型常量,用于提高代码可读性。

typedef enum Status {
    Ok,    // 默认值 0
    Err,   // 默认值 1
    OutMem // 默认值 2
} Status;

// 使用
Status st = Ok;
switch(st) {
    case Ok: break;
    case Err: break;
    case OutMem: break;
}
  • 可手动赋值:

enum Status { Ok=0, Err=5, OutMem=8,9,10,11 };

2. 特点

  • 枚举常量是编译期常量,不能被修改。

  • 枚举变量本质是int类型,可与整数互相赋值。


四、联合体(union

1. 核心特性:共享内存

  • 所有成员共享同一块内存空间,同一时间只能存储一个成员的值。

  • 联合体大小等于最大成员的大小


union Test {
    int i;
    char c[4];
};
// 大小为 4字节(int的大小)

2. 用途

  • 类型双关:用不同类型视角解读同一块内存(如判断系统大小端)。

union Test u;
u.i = 0x12345678;
// 小端系统:c[0]=0x78, c[1]=0x56, c[2]=0x34, c[3]=0x12
// 大端系统:c[0]=0x12, c[1]=0x34, c[2]=0x56, c[3]=0x78
  • 节省空间:多个互斥使用的成员共享内存。

3. 与结构体的区别

特性 结构体(struct 联合体(union
内存分配 各成员独立占用内存 各成员共享同一块内存
总大小 各成员大小之和(含对齐) 等于最大成员的大小
成员访问 可同时访问多个成员 同一时间只能有效访问一个成员

五、自定义数据类型封装示例


// 动态数组封装
typedef struct Array {
    int* element;  // 指向堆区数组
    int size;       // 当前有效元素个数
    int capacity;   // 数组容量
} Array;

// 初始化
void initArray(Array* a, int cap) {
    a->element = (int*)malloc(sizeof(int)*cap);
    a->size = 0;
    a->capacity = cap;
}

// 销毁
void destroyArray(Array* a) {
    free(a->element);
    a->element = NULL;
    a->size = 0;
    a->capacity = 0;
}

六、核心对比总结

函数/类型 核心作用 关键注意点
memcpy 内存拷贝 不处理内存重叠
memmove 安全内存拷贝 处理内存重叠,效率略低
memset 内存初始化 按字节赋值,注意多字节类型
struct 聚合不同类型数据 内存对齐,位段节省空间
enum 定义命名常量 本质是int,提高可读性
union 共享内存 同一时间仅一个成员有效

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐