一、结构体(struct)
- 定义和概念
- 结构体是一种用户自定义的数据类型,它允许将不同类型的数据组合成一个单一的实体。例如,如果你要表示一个学生的信息,学生有姓名(字符串类型)、年龄(整数类型)、成绩(浮点数类型)等不同类型的数据,就可以使用结构体来组织这些数据。
- 语法格式一般为:
struct student {
char name[20];
int age;
float score;
};
- 这里定义了一个名为
student
的结构体类型,它包含了三个成员:name
(字符数组)、age
(整数)和score
(浮点数)。
- 使用方法
- 声明结构体变量:
struct student stu1;
- 访问结构体成员:可以使用点运算符(
.
)来访问结构体变量中的成员。例如,给stu1
的成员赋值:
strcpy(stu1.name, "Tom");
stu1.age = 18;
stu1.score = 90.5;
- 结构体也可以作为函数的参数传递。例如:
void printStudent(struct student s) {
printf("Name: %s\n", s.name);
printf("Age: %d\n", s.age);
printf("Score: %.2f\n", s.score);
}
- 可以在主函数中调用这个函数来打印学生信息:
int main() {
struct student stu1;
strcpy(stu1.name, "Tom");
stu1.age = 18;
stu1.score = 90.5;
printStudent(stu1);
return 0;
}
-
内存布局
-
结构体成员在内存中是按照定义的顺序依次存储的。例如,对于上面的
student
结构体,name
数组可能占据一段连续的内存空间,然后age
和score
依次存储在后面的内存位置。编译器会根据成员的类型和对齐要求来分配内存。不同的编译器可能会有不同的对齐方式,这会影响结构体的大小。 -
例如,在 32 位系统下,如果
int
类型是 4 字节对齐,char
数组本身没有严格的对齐要求,但float
也是 4 字节对齐。假设name
数组实际占用 20 字节,那么这个结构体可能会因为对齐而在name
数组后填充一些字节,使得age
的存储地址是 4 的倍数。
-
-
嵌套结构体
- 结构体可以嵌套其他结构体。例如,定义一个包含学生地址信息的结构体,并且将这个结构体嵌套在学生信息结构体中:
struct address {
char city[20];
char street[30];
};
struct student {
char name[20];
int age;
float score;
struct address addr;
};
二、联合(union)
- 定义和概念
- 联合也是一种用户自定义的数据类型。它的特点是所有成员共享同一段内存空间。联合的大小取决于它的最大成员的大小。
- 语法格式一般为:
union data {
int i;
float f;
char c[4];
};
- 这里定义了一个名为
data
的联合类型,它有三个成员i
(整数)、f
(浮点数)和c
(字符数组)。
- 使用方法
- 声明联合变量:
union data myData;
- 访问联合成员:同样使用点运算符(
.
)。但是要注意,由于成员共享内存,在某一时刻只能正确存储和访问其中一个成员的值。例如:
myData.i = 10;
// 此时如果访问myData.f,得到的值是不确定的,因为内存中存储的是按照整数格式存储的10
// 但如果将内存中的内容按照浮点数来解释,结果是不可预测的
- 联合常用于节省内存空间或者在不同的数据格式之间进行转换。例如,在某些通信协议中,一个数据字段可能根据不同的情况表示不同类型的数据,就可以使用联合来实现这种灵活性。
-
内存布局
- 联合的所有成员都从同一起始地址开始存储,所以联合的大小等于其最大成员的大小。在上面的
union data
例子中,如果int
是 4 字节,float
是 4 字节,char
数组c
长度为 4 字节,那么这个联合的大小就是 4 字节。 - 因为成员共享内存,当给一个成员赋值后,再访问其他成员时,需要谨慎考虑数据的解释方式,避免出现错误的结果。
- 联合的所有成员都从同一起始地址开始存储,所以联合的大小等于其最大成员的大小。在上面的
-
与结构体的区别
- 结构体的每个成员都有自己独立的内存空间,联合的所有成员共享同一段内存。
- 结构体用于将多个相关的数据组合在一起,方便管理和传递;联合主要用于在同一内存空间存储不同类型的数据,以达到节省空间或者灵活转换数据格式的目的。