目录
结构体
结构体的基本知识
在C语言中,结构体(struct)是一种可以存储多个不同类型数据的复合数据类型。它允许您组合多个数据类型,以便更好地组织和管理数据。
以下是一些关于C语言结构体的基本知识:
1.定义结构体:
要定义一个结构体,您需要使用
struct
关键字,后跟结构体的名称和包含的数据类型,用大括号括起来。例如,以下是一个定义一个名为Person
的结构体的示例:
struct Person { char name[50]; int age; float height; };
这个结构体包含了一个字符数组name
、一个整数age
和一个浮点数height
。
2.创建结构体变量:
定义结构体后,您可以使用结构体变量来存储实际的数据。要创建结构体变量,只需使用结构体名称即可。例如:
struct Person person1;
这样就创建了一个名为person1
的结构体变量。
3.初始化结构体变量:
您可以在创建结构体变量的同时为其初始化。例如:
struct Person person1 = {"John Doe", 30, 1.75f};
这样就初始化了person1
结构体变量的name
、age
和height
字段。
4.访问结构体变量的字段:
要访问结构体变量的字段,您可以使用
.
运算符。例如:
printf("Name: %s\n", person1.name); // 输出 "Name: John Doe"
printf("Age: %d\n", person1.age); // 输出 "Age: 30"
printf("Height: %.2f\n", person1.height); // 输出 "Height: 1.75"
5.结构体变量之间的赋值:
您可以使用赋值运算符将一个结构体变量的值复制到另一个结构体变量中。例如:
struct Person person2 = person1;
这样就将person1
的值复制到了person2
中。
结构体的自引用
结构体的自引用是指结构体中的一个成员变量的类型是该结构体本身的指针。这种结构体常用于树形结构、链表等数据结构的实现,通过自引用,可以将多个结构体连接成一条链或树。
以下是一个使用自引用的结构体定义示例:
struct TreeNode {
int value;
struct TreeNode* left; // 左子树指针
struct TreeNode* right; // 右子树指针
};
在此定义中,TreeNode结构体中的left和right成员变量的类型都是struct TreeNode*,即指向自身的指针类型。这样,我们可以用TreeNode结构体来表示树结构中的每个节点,同时通过left和right指针来表示左右子树节点的连接关系。
例子:
5
/ \
4 6
/ / \
2 1 3
可以用如下方式创建此树的节点:
struct TreeNode node2 = {2, NULL, NULL};
struct TreeNode node4 = {4, &node2, NULL};
struct TreeNode node1 = {1, NULL, NULL};
struct TreeNode node3 = {3, NULL, NULL};
struct TreeNode node6 = {6, &node1, &node3};
struct TreeNode node5 = {5, &node4, &node6};
其中,每个节点都被表示为一个TreeNode结构体变量,其中left和right指针被设置为对应节点的左右子树指针,如果某个节点没有左子树或右子树,则该指针被设置为NULL。通过此方法,可以用结构体自引用来实现树形数据结构的存储和遍历。
结构体的内存对齐
C语言中的结构体内存对齐是指编译器按照规定的对齐方式,将结构体变量各成员放置在内存中的位置。
首先得掌握结构体的对齐规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
例如,以下结构体定义:
struct MyStruct {
int a;
char b;
double c;
short d;
};
按照一般的对齐方式,该结构体的对齐值为8字节(double类型的对齐值最大,为8),结构体总大小为24字节(按照a、b、c、d的顺序,分别为4、1、8、2字节)。因此,在内存中,该结构体变量的起始地址必须是8字节的倍数,且结构体变量的大小必须是8字节的倍数。
在结构体中出现较大类型、大小相对较小的成员变量,可能会导致空间浪费,这对于内存有限或需要优化内存使用的系统来说是不利的。结构体内存对齐也是为了提高内存使用效率和系统性能而设计的。
如果需要关闭内存对齐,可以使用预编译指令#pragma pack(n),其中n为对齐字节数,通常n为1、2、4、8等,也可以使用__attribute__((aligned))来指定对齐方式。
位段
位段是C语言中一种特殊的结构体成员,它允许将结构体中的一个整型变量分成几个不同位数的部分,每一部分成为一个位段,每个位段可以单独进行访问。
在定义结构体时,使用冒号来指定每个位段的位数。例如:
struct Flags {
unsigned int a: 1;
unsigned int b: 2;
unsigned int c: 3;
};
上述结构体定义了一个名为Flags的结构体,并定义了三个位段,分别为a、b、c。a的位数为1,表示只能取0或1;b的位数为2,表示可以取0、1、2或3;c的位数为3,表示可以取0~7。由于每个位段占据的位数不同,因此结构体Flags的大小也会受到影响。
在使用位段时,可以像访问结构体成员一样访问每个位段:
struct Flags f;
f.a = 1;
f.b = 2;
f.c = 5;
位段的使用可以节省内存空间,但也有一些限制。例如,位段只能是int、unsigned int或signed int类型,不能是其他类型,因此在使用位段时需考虑数据类型的选择。此外,由于位段是按位存储的,因此其位序可能与不同编译器、不同CPU架构下的不同处理器有关,因此需要谨慎使用,需要保证位序的兼容性。
枚举
C语言枚举是一种定义枚举类型的数据类型。枚举类型指的是一组具有相同属性的常量的集合,其中每个常量都被赋予一个标识符和一个整数值。
枚举的基本语法如下:
enum 枚举类型名 {
枚举值1,
枚举值2,
...
};
例如,我们可以定义一个名为“color”的枚举类型,其中包含三个枚举值red、green、blue:
enum color {
red,
green,
blue
};
在定义枚举类型时,每个枚举值都被赋予一个默认整数值。在上面的例子中,red的默认整数值为0,green为1,blue为2。也可以显式地为枚举值指定整数值:
enum color {
red = 1,
green = 2,
blue = 4
};
枚举类型的变量可以像其他变量一样进行声明和定义,例如:
enum color c1, c2;
也可以定义枚举类型的指针变量,例如:
enum color *c_ptr;
枚举类型的变量赋值可以使用枚举值或整数值,例如:
c1 = red;
c2 = 2;
枚举类型的变量可以用于switch语句中,例如:
switch(c1) {
case red:
printf("c1 is red\n");
break;
case green:
printf("c1 is green\n");
break;
case blue:
printf("c1 is blue\n");
break;
default:
printf("c1 is unknown\n");
break;
}
枚举类型在C语言中使用广泛,常用于定义状态、类型、错误码等常量集合,便于代码的编写和维护。
联合(共用体)
联合的认识
C语言中,联合是一种特殊的数据类型,它允许多个变量共用同一段存储空间,即不同的成员变量可以存储在同一个内存位置。这个存储空间的大小只取决于定义该联合类型中最大成员变量所占的存储空间大小。
联合的语法如下:
union union_name {
type member1;
type member2;
...
};
其中,union_name 是联合名称,member1、member2 等是联合的成员变量,type 是成员变量的数据类型。
在使用时,可以通过联合名和成员变量名访问联合成员变量。例如:
union union_name u;
u.member1 = 10;
printf("u.member1 = %d\n", u.member1);
联合的最大优点是可以节约内存空间,但也存在一些缺点。比如,联合的大小只能适应所有成员中最大的那一个,不能同时存储多个成员,也无法在联合中定义多个不同类型的成员变量。此外,在联合中存储一个成员变量后,其他成员变量的值都会被破坏,因此需要慎重使用。
联合类型的主要应用包括以下几个方面:
- 节约内存:多个变量可以共用同一段存储空间,从而减少了内存的使用。
- 数据类型转换:联合类型可以方便地进行不同数据类型之间的转换。
- 位操作:联合类型可以用于进行位操作,例如位域操作,在一段存储单元中存放多个位域。
联合大小的计算
- 联合的大小至少是最大成员的大小。
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。