当前位置: 首页 > news >正文

解码C语言结构体

一、结构体的定义与声明

结构体是一种 自定义数据类型,用于将多个不同类型的变量组合成一个整体。

1. 定义结构体类型

struct Student {char name[20];// 字符数组成员int age;// 整型成员float score;// 浮点型成员
};

2. 统一 typedef 定义

确保通过 typedef 定义的类型名全局唯一:

//在头文件中统一定义
typedef struct Point {int x;int y;
} Point;// struct Point 和 Point 类型一致

3. 声明结构体变量

// 方式1:先定义类型,再声明变量
struct Student stu1;// 方式2:定义类型时直接声明变量(了解)
struct Book {char title[50];float price;
} book1, book2;// 同时声明book1和book2

4.省略标签声明方式(声明后不可以定义变量)

// 省略标签,直接定义变量
struct {char name[50];int age;float height;
} person1, person2;// 直接声明变量
// 或者使用typedef创建别名
typedef struct {char name[50];int age;float height;
} Person;// Person现在是类型名Person person3;// 可以直接使用

使用省略标签的场景(嵌套结构体)

#include <stdio.h>typedef struct {
// 内嵌匿名结构体,只在DateTime中使用,其他地方不能定义与date同型结构体
struct {int hour;int minute;int second;} time;struct {int year;int month;int day;} date;
} DateTime;int main() {DateTime dt = {{12, 30, 45}, {2024, 1, 15}};printf("时间: %02d:%02d:%02d\n",dt.time.hour, dt.time.minute, dt.time.second);return 0;
}

二、结构体的初始化

1. 直接初始化

在声明时直接赋值:

struct Student stu1 = {"Alice", 18, 95.5};

2. 按成员初始化(C99标准)

指定成员赋值,顺序可调:

struct Student stu2 = {.age = 20,.name = "Bob",.score = 88.0
};

3. 动态初始化

通过代码逐个赋值:

struct Student stu3;
strcpy(stu3.name, "Charlie");// 字符串需用strcpy
stu3.age = 22;
stu3.score = 92.5;

4. 结构体整体赋值仅限同类型结构体

结构体类型必须完全一致(包括成员顺序、类型和名称):

struct PointA { int x; int y; };
struct PointB { int x; int y; };struct PointA a = {1, 2};
struct PointB b = a;// 错误!虽然成员相同,但类型名不同
struct PointA c = a;//正确

三、结构体成员的访问

1. 普通结构体变量

使用 . 运算符访问成员:

printf("姓名:%s,年龄:%d,分数:%.1f\n", stu1.name, stu1.age, stu1.score);

2. 结构体指针

使用 -> 运算符或 (*ptr). 访问成员:

struct Student *p = &stu1;
printf("姓名:%s\n", p->name);// 等价于 (*p).name
printf("年龄:%d\n", (*p).age);

四、结构体数组

1. 声明与初始化

struct Student class[3] = {{"Alice", 18, 95.5},{"Bob", 19, 88.0},{"Charlie", 20, 92.5}
};

2. 访问数组成员

for (int i = 0; i < 3; i++) {printf("学生%d:%s,%d岁,分数%.1f\n",i+1, class[i].name, class[i].age, class[i].score);
}

五、结构体与指针

1. 指向结构体的指针

struct Student stu = {"David", 21, 90.0};
struct Student *p = &stu;// 修改成员值
p->age = 22;
strcpy(p->name, "Dave");

2. 动态分配结构体内存

struct Student *p_stu = (struct Student*)malloc(sizeof(struct Student));
if (p_stu != NULL) {strcpy(p_stu->name, "Eve");p_stu->age = 23;p_stu->score = 85.5;free(p_stu);// 释放内存
}

六、结构体作为函数参数

1. 传递结构体副本

函数内修改不影响原结构体:

void print_student(struct Student s) {printf("姓名:%s\n", s.name);
}print_student(stu1);

2. 传递结构体指针

函数内可直接修改原结构体:

void update_age(struct Student *p, int new_age) {p->age = new_age;
}update_age(&stu1, 19);// stu1.age变为19

七、结构体嵌套

结构体可以包含其他结构体作为成员:

struct Date {int year;int month;int day;
};struct Person {char name[20];struct Date birthday;// 嵌套结构体
};// 初始化嵌套结构体
struct Person p = {"Tom", {2000, 5, 15}};// 访问嵌套成员
printf("出生日期:%d年%d月%d日\n",p.birthday.year, p.birthday.month, p.birthday.day);

八、结构体的大小与内存对齐(面试)

结构体的大小由成员大小和内存对齐规则决定,可通过 sizeof 获取:

struct Example {char c;// 1字节int i;// 4字节double d;// 8字节
};printf("结构体大小:%zu字节\n", sizeof(struct Example));// 输出可能是16(对齐到8字节)
注:规则
1.内存按结构体成员的先后顺序排序,当排到该成员时,其前面已开辟的空间字节数必须是该成员类型所占字节数的整数倍
2.整体空间必须是其最大成员类型所占字节的整数倍。
3.根据操作系统:指针(32位系统):4字节;指针(64位系统):8字节
通过 #pragma pack(n) 可强制指定对齐值(n为1、2、4、8等)

九、常见错误与注意事项

错误 说明 解决方法
未初始化结构体 结构体成员可能包含随机值。 声明时初始化或手动赋值。
结构体赋值浅拷贝 直接赋值结构体时,指针成员指向同一内存。 深拷贝需手动复制指针指向的内容。
混淆.->运算符 对指针使用.或对普通变量使用-> 明确指针用->,普通变量用.
内存对齐浪费空间 结构体成员顺序不合理导致内存浪费。 按成员大小降序排列减少填充。

十、示例代码

1. 动态创建结构体数组

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {char name[20];int age;
};int main() {int n = 3;struct Student *class = (struct Student*)malloc(n * sizeof(struct Student));if (class == NULL) {printf("内存分配失败!\n");return 1;}// 初始化strcpy(class[0].name, "Alice");class[0].age = 18;strcpy(class[1].name, "Bob");class[1].age = 19;// 输出for (int i = 0; i < n; i++) {printf("学生%d:%s,%d岁\n", i+1, class[i].name, class[i].age);}free(class);return 0;
}

2. 结构体与文件操作

#include <stdio.h>
struct Student {char name[20];int age;
};int main() {FILE *fp = fopen("students.dat", "wb");if (fp == NULL) {printf("文件打开失败!\n");return 1;}struct Student stu = {"Tom", 20};fwrite(&stu, sizeof(struct Student), 1, fp);// 写入文件fclose(fp);// 读取文件fp = fopen("students.dat", "rb");struct Student read_stu;fread(&read_stu, sizeof(struct Student), 1, fp);printf("读取数据:%s,%d岁\n", read_stu.name, read_stu.age);fclose(fp);return 0;
}
http://www.hskmm.com/?act=detail&tid=9948

相关文章:

  • 已完成今日求所有满足长为 $a$ 的和为 $b$ 的按位或为 $c$ 的非负整数序列的异或和的异或和大学习
  • Hello Yqc!
  • 2025.9.19——卷9-10选择
  • 软件工程学习日志2025.9.19
  • ECT-OS-JiuHuaShan 框架元推理,是人类良医与福音
  • upload-labs全通关
  • SAPO去中心化训练:多节点协作让LLM训练效率提升94%
  • mybatis-plus学习笔记
  • 区间问题
  • 操作系统,知识体系一共包含哪些部分? - 实践
  • vscode 下载 VS Code Server 卡住(无需手动下载)
  • 查询本地IPV6 地址
  • 解决 Ubuntu 25.04 下 make menuconfig 报 ncurses 错误的问题 - 指南
  • web359
  • web360
  • 缺失的第一个正数-leetcode
  • hbase的安装应用
  • 如何在后端优雅地生成并传递动态错误提示?
  • 深入解析:Java全栈开发面试实录:从基础到微服务的实战解析
  • web358
  • 04_Redis凭啥这么牛:核心特性剖析
  • WPF包
  • 惊爆!Flutter消息通道的超神全解析!
  • ctfshow web351
  • ctfshow web353
  • Linux虚拟机常用命令与Hadoop生态组件启动大全
  • BGP路由属性与选路-1
  • private void Form1_Load和 private void Form1_Activated 方法区别
  • BGP反射路由器
  • HarmonyOS Stage模型与ArkTS:现代应用开发的核心架构与最佳实践 - 详解