一、为什么要有结构体?
在c语言中提供了很多的数据内省如char、int、float、long、double等等,这些为基本的数据内型,可以定义单个变量。当然我们定义变量可以有几个变量就定义几个变量,有很多意义相关的变量可以用数组来定义,但是碰见了意义相关但数据类型不一样的时候数组就派不上用场了,因为一个数组只能存储类型相关的变量,这个时候也就产生了结构体。
什么是结构体呢?结构体是一种里面包含很多元素、这些元素的数据类型可以是相同、也可以是不同,所以结构体是一种数据封装的方法。
二、如何声明结构体?
要想声明一个结构体,就得用到一个关键字struct,结构体的声明格式如下:
Struct 结构体名{
成员列表;
}变量名列表;
注:结构体名一般都为大写,方便与变量区分开。成员列表以及变量名列表可以是一个也可以是多个。
其实结构体的定义归根结底也就三种,关于结构体声明的三种方法,这里我以日期作为例子:
2.1 结构体声明用法一:单独定义
struct Data
{
uint16_t Year;
uint8_t Mon;
uint8_t Day;
};
int main()
{
struct Data Today;
struct Data Tomorrow;
Today.Year = 2024;
Today.Mon = 5;
Today.Day = 24;
Tomorrow.Day = 25;
printf("Today Data:%d-%d-%d\n",Today.Year,Today.Mon,Today.Day);
printf("Tomorrow Data:%d-%d-%d\n",Today.Year,Today.Mon,Tomorrow.Day);
}
当然创建变量部分可以放在函数体也可以放在函数外,无非是局部变量与全局变量。
2.2 结构体声明用法二:混合定义
struct Data
{
uint16_t Year;
uint8_t Mon;
uint16_t Day;
}Today;
int main()
{
Today.Year = 2024;
Today.Mon = 5;
Today.Day = 24;
printf("Today Data:%d-%d-%d\n",Today.Year,Today.Mon,Today.Day);
}
这里我们声明了一个结构体,其名字为Data,成员有年、月、日,变量名为今天。(当然你还可以加上明天,在变量名后加逗号分隔,写上Tomorrow)。如:
struct Data
{
uint16_t Year;
uint8_t Mon;
uint16_t Day;
}Today,Tomorrow;
int main()
{
Today.Year = 2024;
Today.Mon = 5;
Today.Day = 24;
Tomorrow.Day = 25;
printf("Today Data:%d-%d-%d\n",Today.Year,Today.Mon,Today.Day);
printf("Tomorrow Data:%d-%d-%d\n",Today.Year,Today.Mon,Tomorrow.Day);
}
这里我省了明天的年月赋值,直接用的是Today的。
2.3 结构体声明用法三:匿名结构体
struct
{
uint16_t Year;
uint8_t Mon;
uint8_t Day;
}Today,Tomorrow;
int main()
{
Today.Year = 2024;
Today.Mon = 5;
Today.Day = 24;
Tomorrow.Day = 25;
printf("Today Data:%d-%d-%d\n",Today.Year,Today.Mon,Today.Day);
printf("Tomorrow Data:%d-%d-%d\n",Today.Year,Today.Mon,Tomorrow.Day);
}
这种结构体的定义只能使用一次,也就是你开局就确定了结构体变量,因为你省去了结构体名,也就是你无法再通过struct再定义一个结构体变量。
三、typedef与结构体
当我们使用法一去定义结构体以及变量的时候,都需要加上struct关键字,要想在定义结构体变量省去struct关键字,我们就可以在声明结构体时加上关键字typedef。
在之前我们先了解一下关键字typedef的作用,它可以给变量类型换名字,例如下列代码,通过typedef给类型起别名,也就是下边的Data 就相当于上边srtuct Data。当然struct后的Data结构体名可以省去,这也就是为什么下边声明结构体变量时不需要加struct的原因,Data中已经包含struct了。这也就导致了为什么有些结构体花括号外面有时为结构体变量,有时候有为名字,以至于很多人懵懵懂懂,现在大家知道了结构体该如何定义了吧!
typedef struct Data
{
uint16_t Year;
uint8_t Mon;
uint8_t Day;
}Data;
int main()
{
Data Today;
Data Tomorrow;
Today.Year = 2024;
Today.Mon = 5;
Today.Day = 24;
Tomorrow.Day = 25;
printf("Today Data:%d-%d-%d\n",Today.Year,Today.Mon,Today.Day);
printf("Tomorrow Data:%d-%d-%d\n",Today.Year,Today.Mon,Tomorrow.Day);
}
四、结构体的嵌套
struct Time{
uint8_t hour;
uint8_t minute;
uint8_t second;
};
typedef struct
{
uint16_t Year;
uint8_t Mon;
uint8_t Day;
struct Time time;
}Data;
这样就完成了结构体的嵌套,当然这两个完全可以拿一个结构体全部定义完成,我这里只是举例子,定义了一个结构体其中包含另一个结构体,其中为时分秒。
五、结构体的赋值
上面讲了结构体的定义,那么该如何赋值呢?方法1是直接引出结构体变量进行一个个赋值:
Data Today;
Today.Year = 2024;
Today.Mon = 5;
Today.Day = 24;
Today.time.hour = 12;
Today.time.minute = 45;
Today.time.second = 55;
第二种方法是利用大括号进行赋值:注“嵌套的结构体赋值还得加上大括号”
struct Time{
uint8_t hour;
uint8_t minute;
uint8_t second;
};
typedef struct
{
uint16_t Year;
uint8_t Mon;
uint8_t Day;
struct Time time;
}Data;
int main()
{
Data Today = {2024,5,24,{12,45,55} };
printf("Today Data:%d-%d-%d %d:%d:%d\n",Today.Year,Today.Mon,Today.Day,
Today.time.hour,Today.time.minute,Today.time.second);
}
六、结构体数组
6.1 结构体数组的作用
结构体数组是c语言中处理复杂数据的一种强大工具,通过结构体数组,我们可以操作管理多个相同类型的结构体数据。结构体数组是一种特殊的数组,他每个元素都是一个结构体。通过结构体数组,我们可以将多个相关联的结构体数据组织在一起,形成一个逻辑单元。
6.2结构体的使用
关于结构体的定义声明和上边讲的结构体定义方法一样,也是三种,这里直接使用第二种,还是拿日期举例子:
struct Data
{
uint16_t Year;
uint8_t Mon;
uint16_t Day;
}Dat[3]={{2025,1,1},{2025,1,2},{2025,1,3}};
int main()
{
printf("Today Data:%d-%d-%d\n",Dat[0].Year,Dat[0].Mon,Dat[0].Day);
printf("Tomorrow Data:%d-%d-%d\n",Dat[1].Year,Dat[1].Mon,Dat[1].Day);
printf("The day after tomorrow Data:%d-%d-%d\n",Dat[2].Year,Dat[2].Mon,Dat[2].Day);
}
七、结构体指针
通过指向结构体变量的指针变量输出结构体变量中成员的信息。
struct student
{
char name[4];
char age;
}*P;
//或者写成
struct student
{
char name[4];
char age;
};
student *p;
如何使用指针访问结构体成员呢?
方法一: (*p).name = "ABC";
方法二: p->name = "ABC";
八、结构体的内存计算
struct Time{
uint8_t hour;
uint8_t minute;
uint8_t second;
};
typedef struct
{
uint16_t Year;
uint8_t Mon;
uint8_t Day;
struct Time time;
}Data;
int main()
{
Data Today;
printf("Time Size:%d\n",sizeof(Today.time));
printf("Time Size:%d\n",sizeof(Today));
}
假如上述两个结构体,它们分别占多少字节呢?对于第一个结构体,里面有三个无符号字符型成员,也就是3字节,对于第二个结构体,4+1+1+3=9字节,那么结果是不是这样呢?我们试着打印出来:
可以发现第一个结构体确实是三字节,但是第二个结构体就不一样了,占12字节。这里涉及到了另一个知识就是内存对齐,也就是第二个结构体其第一个变量占四个字节,而后边会自动将两个字节的char算成4字节,再把三字节的结构体也算成四字节,也就是有三个四字节所以为12。
我们再在这个结构体里面添加成员:
typedef struct
{
uint8_t Mon;
uint16_t Year;
uint8_t Day;
uint16_t Year2;
uint8_t Day2;
uint16_t Year3;
uint8_t Day3;
struct Time time;
}Data;
我们来计算一下内存,其中mon和day为一字节,一起为两字节,中间有4字节的year,也就是这三个一起占两个四字节也就是八字节,year2和day2都是四字节(内存对齐使day2为四字节),同理,也就是有4+4+4+4+4+4+4=28字节,可以发现确实没问题。