目录
1.定义
2.应用
2.1初始化
2.2使用
3.结构体对齐规则与存储
C语言中结构体(struct关键字定义)是一种自定义数据类型。通过结构体的定义可以将多种不同类型数据形成一个组合,是一个数据集。
什么情况下使用结构体?结构体的定义具有一定面向对象思想,当一个对象具有多个属性类型数据去表达时,可以定义为结构体,比如学生,结构体成员包含姓名、年龄、学号、成绩。
定义方法如下:
方法一:直接使用struct关键字定义结构体
struct 结构体名称
{
结构体成员1类型 结构体成员1名称;
结构体成员2类型 结构体成员2名称;
......
结构体成员N类型 结构体成员N名称;
};//注意结束分号
方法二:使用typedef定义,简化使用
typedef struct 结构体名称
{
结构体成员1类型 结构体成员1名称;
结构体成员2类型 结构体成员2名称;
......
结构体成员N类型 结构体成员N名称;
}自定义结构体类型名称;//注意结束分号
定义一个学生类型结构体实例:
//方法一
struct student_t
{
char name[20];//姓名
unsigned char age;//年龄
unsigned int number;//学号
float grade;//成绩
};//注意需要有分号结束,组成一个完整语句
//方法二
typedef struct student_t
{
char name[20];//姓名
unsigned char age;//年龄
unsigned int number;//学号
float grade;//成绩
}Student_t;//注意需要有分号结束,组成一个完整语句
1、方法一:定义时隐性赋值
struct student_t stdu ={ "Tom", 20, 0x9001, 89.5,};
说明: 此方法初始化时不需要写明成员名称,但需按照结构体成员顺序进行赋值,不能错位。
2、方法二:定义时显性赋值
struct student_t stdu =
{
.name = "Tom",
.age = 20,
.number = 0x9001,
.grade = 89.5,
};
说明:此方法初始化时显性给出了结构体成员名称,逐个赋值,可以进行乱序赋值(即不按照成员的顺序进行赋值),但为了保持良好编程风格,建议按顺序进行赋值。
3、方法三:先定义再赋值
struct student_t stdu;
//stdu.name = "Tom";//注意:不能直接对数组名赋值字符串常量,此处了解数组和指针相关知识
strcpy(stdu.name, "Tom");
stdu.age=20;
stdu.number=0x9001;
stdu.grade=89.5;
说明:此方法和方法二一样,可以不按顺序赋值。类似一般类型变量定义之后,再赋值。
以学生结构体定义后打印到控制台为例,以下是在VS2022中调试可运行的完整C代码
#include
#include
#include
#include
#include
#pragma warning(disable:4996)//用以解决strcpy不安全使用编译错误问题
typedef struct student_t
{
char name[20];//姓名
unsigned char age;//年龄
unsigned int number;//学号
float grade;//成绩
}Student_t;//注意需要有分号结束,组成一个完整语句
int main(int argc, char* argv[])
{
//方法一
//Student_t stdu ={ "Tom", 20, 0x9001, 89.5,};
//
//方法二
Student_t stdu =
{
.name="Tom",//注意此处不能使用stdu.name,因为是不可修改左值
.age=20,
.number=0x9001,
.grade=89.5,
};
//
//
//方法三
//struct student_t stdu;
stdu.name = "Tom";//不能直接对数组名赋值字符串常量,此处了解数组和指针相关知识
//strcpy(stdu.name, "Tom");
//stdu.age = 20;
//stdu.number = 0x9001;
//stdu.grade = 89.5;
printf("Student information:\n");
printf(" name: %s\n", stdu.name);
printf(" age: %d\n", stdu.age);
printf(" number: %x\n", stdu.number);
printf(" grade: %f\n", stdu.grade);
return 0;
}
运行后效果截图:
结构体在内存中存储需符合以下2条规则:
1. 结构体每一个成员的偏移量都必须是该成员存储大小的倍数。
2. 完整结构体的大小必须是该结构体字节数最大成员类型的倍数。(注意是类型大小而不是成员变量大小)。
以学生结构体(struct student_t)为例说明:
第一个成员name偏移量是0,符合规则一;
第二个成员age偏移量是20,是char类型整数倍,符合规则一;
第三个成员number偏移量是name变量大小加age变量大小,即20+1=21,而unsigned int类型长度是4,21不是4的整数倍,不符合规则一。需要进行大小补齐,补齐到24后符合规则一;
第四个成员grade偏移量是24(补齐后)+4=28,符合规则一;
整个结构体大小是grade成员偏移量加grade变量自身大小,即28+4=32字节。
验证规则二:成员中字节数最大类型是float,4字节(unsigned int也是4字节),32是4字节的倍数,无需补齐,所以整个学生结构体大小就是32。
注:规则二说明的是类型而不是成员变量,成员变量name的大小是20字节,但其类型是char,1字节,4个成员变量类型分别是char、unsigned char、unsigned int、float,所以最大字节数的类型是unsigned int和float,是4字节。
存储图示如下:
使用sizeof计算,运行输出大小如下