结构体的定义:
struct 结构体标签
{
成员1;
成员2;
...
};
struct 结构体名
{
成员类型1 成员名1;
成员类型2 成员名2;
成员类型3 成员名3;
};
结构体初始化
结构体定义和初始化
-
由于结构体内部拥有多个不同类型的成员,因此初始化采用与类似列表方式
-
结构体的初始化有两种方式:①普通初始化;②指定成员初始化。
-
为了能使用结构体类型的升级迭代,一般建议采用指定成员初始化
结构体嵌套:
#include <stdio.h>
#include <string.h>// 创建日期结构体
struct date
{
int y; // 年
int m; // 月
int d; // 日
};// 学生
struct student
{
char name[256]; // 姓名
struct date birthday; // 生日
};int main(int argc, char const *argv[])
{
// 普通初始化,栈区
struct student st = {"jack",2000,01,01};
printf("%s,%d--%d--%d\n",st.name,st.birthday.y,st.birthday.m,st.birthday.d);
// 练习:使用指定成员初始化
struct student st1 = {
.name = "jack", // 定义数组的时候并初始化,是将jack赋值到name
.birthday.y = 2000,
.birthday.m = 9,
.birthday.d = 8
};
printf("%s,%d--%d--%d\n",st1.name,st1.birthday.y,st1.birthday.m,st1.birthday.d);return 0;
}
练习:什么叫做指定成员初始化?这样做有什么好处?
指定成员初始化是在C语言中初始化结构体或联合体成员时,通过指定成员名称来赋值的一种方式。它的语法形式是在初始化列表中使用成员名称和对应的值进行初始化。
指定成员初始化的好处有以下几点:1. 易读性:通过指定成员名称,可以清晰地表达出每个成员的含义,提高了代码的可读性和可维护性。
2. 灵活性:可以选择性地初始化结构体的部分成员,而不需要按照顺序初始化所有成员。
3. 兼容性:在结构体定义发生变化时,使用指定成员初始化可以避免因为成员顺序变化而导致的错误。
4. 可扩展性:当结构体成员较多时,使用指定成员初始化可以更方便地添加或修改成员的初始化值。
总的来说,指定成员初始化提供了一种更灵活、易读且具有兼容性的初始化方式,可以提高代码的可读性和可维护性。
普通变量的m值
以32位系统为例,由于CPU存取数据总是以4字节为单元,因此对于一个尺寸固定的数据而言,当它的地址满足某个数的整数倍时,就可以保证地址对齐。这个数就被称为变量的m值。 根据具体系统的字长,和数据本身的尺寸,m值是可以很简单计算出来的。
char c; // 由于c占1个字节,因此c不管放哪里地址都是对齐的,因此m=1
short s; // 由于s占2个字节,因此s地址只要是偶数就是对齐的,因此m=2
int i; // 由于i占4个字节,因此只要i地址满足4的倍数就是对齐的,因此m=4
double f; // 由于f占8个字节,因此只要f地址满足4的倍数就是对齐的,因此m=4(32位系统),64位系统m=8)printf("%p\n", &c); // &c = 1*N,即:c的地址一定满足1的整数倍
printf("%p\n", &s); // &s = 2*N,即:s的地址一定满足2的整数倍
printf("%p\n", &i); // &i = 4*N,即:i的地址一定满足4的整数倍
printf("%p\n", &f); // &f = 8*N,即:f的地址一定满足8的整数倍
// 32位系统
struct node
{
short a; // 尺寸=2,m值=2
double b; // 尺寸=8,m值=4
char c; // 尺寸=1,m值=1
};struct node n; // M值 = max{2, 4, 1} = 4;
// 64位系统
struct node
{
short a; // 尺寸=2,m值=2
double b; // 尺寸=8,m值=8
char c; // 尺寸=1,m值=1
};struct node n; // M值 = max{2, 8, 1} = 8;
-
以上结构体成员存储分析:
-
结构体的M值等于4,这意味着结构体的地址、尺寸都必须满足4的倍数。
-
成员a的m值等于2,但a作为结构体的首元素,必须满足M值约束,即a的地址必须是4的倍数
-
成员b的m值等于4,因此在a和b之间,需要填充2个字节的无效数据(一般填充0)
-
成员c的m值等于1,因此c紧挨在b的后面,占一个字节即可。
-
结构体的M值为4,因此成员c后面还需填充3个无效数据,才能将结构体尺寸凑足4的倍数。
联合体(共用体)基本概念
联合体内部成员的这种特殊的“堆叠”效果,使得联合体有如下基本特征:
-
整个联合体变量的尺寸,取决于联合体中尺寸最大的成员。
-
给联合体的某个成员赋值,会覆盖其他的成员,使它们失效。
-
联合体各成员之间形成一种“互斥”的逻辑,在某个时刻只有一个成员有效。
union 联合体标签
{
成员1;
成员2;
...
};
基本操作
// 普通初始化:第一个成员有效(即只有100是有效的,其余成员会被覆盖)
union attr at = {100, 'k', 3.14};
// 指定成员初始化:最后一个成员有效(即只有3.14是有效的,其余成员会被覆盖)
union attr at = {
.x = 100,
.y = 'k',
.z = 3.14,
};
测试大小端
#include <stdio.h>
union node
{
int data;
char ch;
};int main(int argc, char const *argv[])
{
union node n;
n.data = 0x12345678;
// 通过联合测试,字节序为小端模式
printf("%x\n",n.ch);return 0;
}
枚举
枚举类型的本质是提供一种范围受限的整型,比如用0-6表示七种颜色,用0-3表示四种状态等,但枚举在C语言中并未实现其本来应有的效果,直到C++环境下枚举才拥有原本该有的属性
#include <stdio.h>
// 如果Color成员没有被赋值,默认是从0开始逐一递增
//enum Color{red,gree,blue,yellow};
// 如果Color成员被赋值,后面的成员在此基础上逐一递增
// 枚举成员可以直接使用
enum Color{red=10,gree,blue=15,yellow};int main(int argc, char const *argv[])
{
printf("size : %ld\n",sizeof(enum Color));
// enum Color是一个整型空间,内容为随机数
// 相当于 int mc_color;
enum Color mc_color;
mc_color = red;
// 枚举成员可以直接使用
printf("%d,%d,%d,%d\n",mc_color,gree,blue,yellow);
return 0;
}