目录
一.结构体
结构体(struct)是一种复合数据类型,它允许你将多个不同类型的数据项组合成一个单一的类型。结构体常用于表示具有多个属性的复杂对象,如一个包含姓名、年龄和地址的人。
1.1结构体变量的创建和初始化
// 声明一个名为Person的结构体
struct Person
{
char name[50]; // 名字,字符数组
int age; // 年龄,整数
char aess[100]; // 地址,字符数组
};
一旦你声明了结构体,你就可以创建该类型的变量,并访问其成员。例如:
#include <stdio.h>
struct Person
{
char name[50];
int age;
char aess[100];
};
int main()
{
struct Person john;
// 初始化john的成员
strcpy(john.name, "John Doe");
john.age = 30;
strcpy(john.aess, "123 Main St");
// 打印john的信息
printf("Name: %s\n", john.name);
printf("Age: %d\n", john.age);
printf("Address: %s\n", john.aess);
return 0;
}
1.2结构的自引用
构的自引用指的是在结构体的定义中,结构体自身包含指向其自身类型的指针或数组。这种自引用结构通常用于创建链表、树、图等数据结构,其中每个节点或元素都可能需要引用其他相同类型的节点或元素。
代码示例:
typedef struct Node
{
int data;
struct Node* next;
}Node;
1.3结构体对齐
struct S1
{
char c1;
int i;
char c2;
};
![b6691943ba1f4ba4890e20655e67e758.png](https://img-blog.csdnimg.cn/direct/b6691943ba1f4ba4890e20655e67e758.png)
代码示例:
struct S2
{
char c1;
char c2;
int i;
};
从图中知道1+1+2+4 =8 满足结构体总大小为最大对齐数的整数倍
运行结果:
1.4修改默认对齐数
#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;
}
输出结果:
6
因为此时对齐数被修改为1 ,对于int i来说,它的大小为4字节,而默认对齐数为1,两者比较,取较小值,此时偏移量从1的倍数开始,因此,struct S的总大小是 1 + 4 + 1 = 6 字节。
1.5 结构体传参
#include<stdio.h>
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
1.6结构体实现位段
#include <stdio.h>
struct bit {
unsigned int flag1 : 1; // 1位
unsigned int flag2 : 2; // 2位
unsigned int field : 4; // 4位
unsigned int l_field : 8; // 8位(即1字节)
unsigned int even_larger : 16; // 16位(即2字节)
};
int main() {
struct bit bf;
bf.flag1 = 1;
bf.flag2 = 3; // 在2位范围内,3的二进制表示是11
bf.field = 15; // 在4位范围内,15的二进制表示是1111
bf.l_field = 255; // 在8位范围内,255的二进制表示是11111111
bf.even_larger = 65535; // 在16位范围内,65535的二进制表示是11111111 11111111
printf("flag1: %d\n", bf.flag1);
printf("flag2: %d\n", bf.flag2);
printf("field: %d\n", bf.field);
printf("l_field: %d\n", bf.l_field);
printf("even_larger: %d\n", bf.even_larger);
return 0;
}
输出结果:
flag1: 1
flag2: 3
field: 15
l_field: 255
even_larger: 65535
位段的具体内存布局(即如何在内存中排列这些位)是依赖于编译器和平台的。因此,不应假设位段在内存中的具体顺序或对齐方式。
位段不能包含浮点数、双精度数、指针或聚合类型(如数组或结构体)。
位段不能跨越多个存储单元(即它们不能跨越多个字节)。如果一个位段需要更多的空间,那么编译器可能会在下一个存储单元中为它分配空间,并可能在它们之间插入填充位。
当读取或写入位段时,它会被当作一个有符号整数或无符号整数来处理,具体取决于该位段的类型。
1.7位段的应用
简化程序源代码:
特定应用场景:
1.8 位端的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型。
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的⽅式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。
1.9位段跨平台问题
.int位段被当成有符号数还是⽆符号数是不确定的。
.位段中最大位的数目不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。
.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
.当⼀个结构包含两个位段,第二个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
2.0 总结
通过结构体,我们能够将多个相关字段封装成一个单一的数据类型,这不仅使得代码更加清晰和易于理解,还提高了代码的可维护性和可重用性。
位段是C语言中一种用于在结构体中定义按位分配内存的字段的特性,它允许开发者精确控制内存使用,但具体行为取决于编译器和平台,使用时需谨慎并确保代码的可移植性和健壮性。
感谢大家阅读这篇关于结构体的章,希望它能够为你带来一些启发和帮助。祝你在编程的道路上越走越远,收获更多的知识和成就!