16、C 语言高级指针与结构体

C 语言高级指针与结构体:void*、结构体、字节对齐、memcpy

1. void* ------ C 语言的"万能指针"

void* 又叫"通用指针",可以接收任意类型的地址,是很多底层库函数(如 memcpy、qsort)的基础。

1.1 void* 能做什么?

  • 可以存储任意指针
  • 可以作为函数参数 → 实现泛型效果
  • 可以作为函数返回值
  • 适合实现通用库函数(如 memcpy)

示例:

c 复制代码
int a = 20;
char s[100] = "hello";

void *p = &a;
printf("%d\n", *(int*)p);

p = s;
printf("%s\n", (char*)p);

1.2 void* 不能直接做什么?

  • ❌ 不能解引用:*p(因为不知道类型)
  • ❌ 不能 p++ 递增(无类型 → 无步长)

必须 强制转换后 才能使用:

c 复制代码
(int*)(p) + 1
(char*)(p) + 1

2. 自定义 memcpy / mystrcpy / myintcpy

为了理解 void* 和内存操作,我们手写了简单的内存拷贝函数。

⭐ 2.1 mystrcpy --- 字符串拷贝

c 复制代码
char* mystrcpy(char* dst,char* src)
{
    char* tmp = dst;
    while(*src!='\0')
    {
        *dst = *src;
        dst++;
        src++;
    }
    *dst='\0';
    return tmp;
}

2.2 myintcpy --- int 数组拷贝

c 复制代码
int *myintcpy(int *dst,int *src,int len)
{
    int *tmp=dst;
    for(int i=0;i<len;i++)
    {
        *dst=*src;
        dst++;
        src++;
    }
    return tmp;
}

⭐ 2.3 mymemcpy(万能 memcpy)

关键代码:

c 复制代码
int *mymemcpy(void *dst, void *src, int len)
{
    void *tmp = dst;
    char *d = (char*)dst;
    char *s = (char*)src;

    for(int i=0;i<len;i++)
    {
        *d = *s;
        d++;
        s++;
    }
    return tmp;
}

解释:

  • 使用 char* 进行拷贝,因为 char 是 1 字节,最适合逐字节复制。
  • 这就实现了真正意义上的通用 memcpy。

3. 结构体(struct)基础

3.1 结构体定义

c 复制代码
struct date
{
    int year;
    int month;
    int day;
};

3.2 结构体初始化

c 复制代码
struct date d1 = {2025, 11, 24};  // 完全初始化

struct date d2 = {                 // 部分初始化
    .year = 2025,
    .day = 10
};

未赋值的成员会自动设为 0


4. 结构体指针与成员访问

结构体变量使用点号访问:

c 复制代码
d1.year;

结构体指针使用箭头访问:

c 复制代码
struct date *p = &d1;
p->year;

等价于:

c 复制代码
(*p).year;

5. 结构体字节对齐(重点)

字节对齐的目的:

提高 CPU 访问内存的效率

对齐规则:

  1. 每个成员的地址必须是其类型大小的整数倍(如 int 必须对齐到 4 的倍数)
  2. 结构体总大小 必须是 最大成员类型大小的整数倍

示例代码(来自你今天的实验):

c 复制代码
struct per
{
    char name[50];
    char sex;
    int age;
    int score;
};

struct per3
{
    double a;
    char c;
    short s;
    struct per2 p;
};

输出结构体大小:

c 复制代码
printf("sizeof p is %lu\n", sizeof(p));
printf("sizeof p3 is %lu\n", sizeof(p3));
printf("sizeof p4 is %lu\n", sizeof(p4));

通过观察不同类型排列导致的对齐变化,可以深入理解结构体布局规则。


6. 结构体数组与函数传参

结构体数组:

c 复制代码
struct PER
{
    char name[50];
    float heigh;
};

struct PER per[3] =
{
    {"zhangsan",1.75},
    {"lisi",1.70},
    {"wangmazi",1.95},
};

传给函数时应使用指针,提高效率:

c 复制代码
void show_array(struct PER* per, int len)
{
    for(int i=0;i<len;i++)
        printf("%d %s %f\n", i, per[i].name, per[i].heigh);
}

调用:

c 复制代码
show_array(per, 3);

7. 综合示例:结构体操作与 mymemcpy

c 复制代码
struct person per = {"zhangsan",20,90.5};
struct person per2 = {0};

mymemcpy(&per2, &per, sizeof(per));

printf("%s %d %f\n", per2.name, per2.age, per2.score);

这就实现了结构体的深拷贝。

相关推荐
月殇_木言43 分钟前
Python期末复习
开发语言·python
Booksort44 分钟前
【LeetCode】算法技巧专题(持续更新)
算法·leetcode·职场和发展
楠语1 小时前
从指针行为理解Git中的reset操作
git
OJAC1111 小时前
2026高校毕业生1270万!但这些学生却被名企用高薪“提前预定”!
算法
Controller-Inversion1 小时前
岛屿问题(dfs典型问题求解)
java·算法·深度优先
小白程序员成长日记1 小时前
力扣每日一题 2025.11.28
算法·leetcode·职场和发展
Swift社区1 小时前
LeetCode 435 - 无重叠区间
算法·leetcode·职场和发展
sin_hielo1 小时前
leetcode 1018
算法·leetcode
念风1 小时前
[lvgl]如何优雅地向lv_port_linux中添加tslib支持
linux