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

初识C语言12. 结构体(自定义类型的核心工具)

目录

前言:

一、结构体:从“声明”到“初始化”的基础逻辑

1.1 定义类型时直接创建变量:

1.2 先声明类型,再创建变量:

1.3 匿名结构体(仅用于一次性变量):

二、结构体的核心操作:成员访问与传参

2.1 成员访问: . 与 -> 的区别

2. 2结构体传参:值传递 vs 地址传递

三、底层细节:内存对齐与位段

3.1 对齐规则:

3.2 修改对齐数

四、 结构体实现位段

4.1 什么是位段

4.2 位段的内存分配

4.3 位段的跨平台问题

总结:


前言:

在C语言的编程体系中,“结构体”是实现自定义复合数据类型的核心机制,它让开发者能够将不同类型的数据封装为一个逻辑整体,是构建复杂数据结构(如链表、树)与贴近现实场景数据模型的基础。本文将结合“自定义类型”的学习框架,拆解结构体的核心用法与底层逻辑。

一、结构体:从“声明”到“初始化”的基础逻辑

结构体的使用首先从类型声明开始——通过 struct 关键字定义新的类型模板,例如描述学生信息的结构体:

// 声明结构体类型
struct Student {char name[20];  // 字符数组存储姓名int age;        // 整型存储年龄float score;    // 浮点型存储成绩
};

声明仅定义“模板”,需创建变量并初始化才能实际存储数据(此时并没有开辟新的空间)

1.1 定义类型时直接创建变量:

struct Student {char name[20];int age;float score;
} stu1 = {"Zhang", 18, 92.5};  // 同时创建并初始化变量stu1

1.2 先声明类型,再创建变量:

struct Student stu2;
// 逐个成员赋值
strcpy(stu2.name, "Li");
stu2.age = 19;
stu2.score = 88.0;

1.3 匿名结构体(仅用于一次性变量):

struct {int x;int y;
} point = {3, 4};  // 无类型名,仅能在此处创建变量

二、结构体的核心操作:成员访问与传参

2.1 成员访问: . 与 -> 的区别

访问结构体成员需使用成员访问操作符:
 
- 当操作结构体变量时,用 (.):

printf("姓名:%s\n", stu1.name);  // 输出"Zhang"

- 当操作结构体指针时,用 (-> ):

struct Student *p = &stu2;
printf("年龄:%d\n", p->age);     // 输出19

数据在上面创建中已经初始化

2. 2结构体传参:值传递 vs 地址传递

结构体作为函数参数传递时,有两种方式:
 
- 值传递:将整个结构体拷贝一份传入函数,修改不会影响原变量(内存开销大):

void printStudent(struct Student s) {printf("成绩:%.1f\n", s.score);
}
printStudent(stu1);  // 传入stu1的拷贝

- 地址传递:传入结构体指针,修改会影响原变量(内存开销小):

void updateScore(struct Student *p, float newScore) {p->score = newScore;
}
updateScore(&stu2, 90.0);  // 修改stu2的成绩为90.0

实际开发中优先选择地址传递,尤其是结构体成员较多时。

三、底层细节:内存对齐与位段

结构体的内存布局并非简单的成员大小相加,而是遵循内存对齐规则——这是编译器为了提升CPU访问效率的优化策略:

3.1 对齐规则:


首先得掌握结构体的对齐规则:

1. 结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处 2

. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的⼀个对齐数 与 该成员变量大小的较齐值。

- VS 中默认的值为 8 -

Linux中 gcc 没有默认对齐数,对齐数就是成员自身的大小

 3. 结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

struct Demo {char a;  // 占1字节,偏移0int b;   // 占4字节,偏移4(补3字节)char c;  // 占1字节,偏移8(补3字节)
};
// 总大小:12字节(而非1+4+1=6字节)

3.2 修改对齐数

可通过 #pragma pack(n) 指定对齐数,以平衡内存效率与空间占用。
 
若需进一步节省内存,可使用结构体位段——通过指定成员占用的二进制位数实现精细化存储:
 

#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S));
return 0;
}

四、 结构体实现位段

4.1 什么是位段

位段的声明和结构是类似的,有两个不同:

1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以选择其他类型。

2. 位段的成员名后边有⼀个冒号和⼀个数字

struct BitField {
int a : 2; // 占用2位
int b : 5; // 占用5位
int c : 10; // 占用10位
};

4.2 位段的内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型

2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。

3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

4.3 位段的跨平台问题

1. int 位段被当成有符号数还是无符号数是不确定的。

2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会

出问题。

3. 位段中的成员在内存中从左向右分配,还是从右向左分配,标准尚未定义。

4. 当⼀个结构包含两个位段,第⼆个位段成员比较大,无法容纳于第⼀个位段剩余的位时,是舍弃

剩余的位还是利用,这是不确定的。

总结:

跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但位段的跨平台兼容性较差(不同编译器的存储规则可能不同),需谨慎使用

总结:

结构体是C语言脱离“单一基础类型”、实现灵活数据组织的关键工具,其语法虽简单,但内存对齐、传参方式等细节直接影响程序的效率与稳定性。掌握结构体,是从“基础语法”迈向“实际开发”的重要一步。

http://www.dtcms.com/a/520903.html

相关文章:

  • webrtc源码走读(二)-QOS-RTT
  • 【Java】线程安全问题
  • 数据结构算法学习:LeetCode热题100-链表篇(下)(随机链表的复制、排序链表、合并 K 个升序链表、LRU 缓存)
  • 网络营销网站 功能南京微信小程序开发制作
  • 域名打不开原来的网站手机免费网站制作
  • 中药饮片网购是什么?主要的市场特点及未来发展潜力如何?
  • 自己做的网站数据库360优化大师app
  • Python-__init__函数
  • 沈阳网站维护公司网站建设财务怎么入账
  • JavaEE:知识总结(一)
  • 各家高性能MCU的内置Flash逐渐走向MRAM之路,关于嵌入式 MRAM 的性能和能效
  • Leetcode 35
  • GPIO口输出
  • 专教做美食的网站胶州哪里有做网站的
  • 企业网站制作 徐州网站设计原则的历史
  • 隐私保护与数据安全合规(十三)
  • 2025年高真空共晶炉排名
  • 网站做转链接违反版权吗wordpress页面不显示子类
  • 5.3类的构造方法
  • 视频监控系统原理与计量
  • 蓝桥杯高校新生编程赛第一场题解——Java
  • JavaScript 的优势和劣势是什么?
  • 鸿蒙Next的Camera Kit:开启全场景智慧影像开发新纪元
  • 软件开发包含网站开发吗搭建网站成本
  • asp.net 微网站开发教程比较大的建站公司
  • h5游戏免费下载:小猪飞飞
  • 基于单片机的档案库房漏水检测报警labview上位机系统设计
  • 网站开发图标汕头网站建设seo外包
  • DeepSeek-OCR:光学Token:长上下文建模的范式转变
  • Windows 11 24H2内核堆栈保护:系统安全新盾牌