文章目录
一、结构体
结构就是一些值的集合,其中的值称作它的成员,这些成员可能具有不同的类型。
1. 声明和定义结构体
以下第一个声明就是创建了一个student的结构体变量,第二个创建了一个student2的结构变量和指向student2的指针pstudent。
需要注意的是编译器认为student和student2是不同的结构体,即使他们内部的成员类型相同,所以pstdent = &student
是非法的。
srtuct{
char name[20];
int age;
bool male;
float score;
}student;
srtuct{
char name[20];
int age;
bool male;
float score;
}student2,*pstudent;
那么我们每次想要使用student这种类型的结构体时必须要,重新定义吗?并不是这样的,我们可以用以下的方式定义student这种类型,如下:
struct student{
char name[20];
int age;
bool male;
float score;
};
int main() {
struct student student1;
struct student student2;
}
需要注意的是我们最初的struct student
的操作并没有创建变量,它只是声明了一种结构体标签,我们可以在其他函数中使用struct student student1
来定义一个结构体变量student1
。
但是每一次都要定义的时候都要使用struct student
来定义显然很繁琐,我们可以使用typedef
来对它进行重命名,创建student
类型。如下:
typedef struct{
char name[20];
int age;
bool male;
float score;
}student, *pstudent;
int main() {
student student1;
pstudent pstudent;
}
这时我们可以直接使用student
和pstudent
作为一种变量类型来定义变量。
2. 如何访问结构体中的成员
直接访问
结构变量是通过.
来访问其中的成员的,具体如下:
typedef struct{
char name[20];
int age;
bool male;
float score;
}student, *pstudent;
int main() {
student student1;
student1.name = "zhangsan";
student1.age = 18;
}
点操作符.
接受两个操作数,左操作数为结构变量的名字,右操作数为需要访问的成员名字
间接访问
我们知道了结构变量如何访问其中的成员,那么结构指针该如何访问呢?
typedef struct{
char name[20];
int age;
bool male;
float score;
}student, *pstudent;
int main() {
pstudent pstudent1;
(*pstudent1).name = "zhangsan";
(*pstudent1).age = 18;
}
我们先要对其进行解引用再访问其中的成员,但是这种访问方式十分的繁琐,c语言中引入了箭头操作附来完成以上操作,具体如下:
typedef struct{
char name[20];
int age;
bool male;
float score;
}student, *pstudent;
int main() {
pstudent pstudent1;
pstudent1->name = "zhangsan";
pstudent1->age = 18;
}
3. 对结构体进行初始化
和数组初始化的方式很相似,使用花括弧进行初始化,具体如下:
student1 = {
"zhangsan",
18,
true,
66.6
};
4. 结构体的内存分配——内存对齐
编译器会按照成员列表的顺序一个接一个的给每个成员分配分配内存,分配要求满足正确的边界对齐。只看这个没有理解没关系,我们接着往下看例子中的具体分析。
如上文中我们定义的student
,它所占的内存是多少呢?使用sizeof来测试一下有多大?
但是如果我们正常一个结构中所有成员所占的内存应该是:
sizeof(name) + sizeof(int) + sizeof(bool) + sizeof(float) = 20 + 4 + 1 + 4= 29
,但实际上一个student结构占有32个字节,原因就是由于内存对齐引起的,如在给student结构进行内存分配时:
在我们student中 int
类型和float
类型所占有的内存最大,均是四个字节,结构体再分配内存的时候将会以4为标准对齐分配内存,由于分配到male的时候只有一个字节下一个为float为四个字节无法和其一起分配,所以将会补齐3个字节实现内存对齐的分配要求。
二、联合体
联合体中的所有成员引用的是内存中相同的位置,当你想要在不同时刻将不同的东西存储在同一个位置,就可以使用联合。
1. 联合的定义
定义如下:
union Integer{
int data;
char bytes[4];
};
一个int为四个字节,我们可以将一个int型的数字放入data然后使用bytes来看这个data按照字节具体的存储内容,主函数中如下:
int main(){
union Integer n;//字节顺序只出现在整型中
n.data = 12348774;
printf("%#x\n",n.data);
for(int i=0;i<4;++i){
printf("%#hhx\n",n.bytes[i]);
// %x 以十六进制整形输出。
// int为4个字节,char型数组中的每个数据有效位为一个字节,如果直接按照整形输出就会一次性读取4个字节。
// 所以用hh限制每次读取一个字节,只有一个h表示限制读取两个字节。
}
}
所以在某种意义上我们可以使用联合看同一事物的不同表现。
2. 联合的初始化
联合变量可以进行初始化,但是这个初始值必须是联合第一个成员的类型,而且必须统一在一对花括号里面。
union {
int a;
float b;
char c[4];
}x = { 5 };
以上就是将x.a
初始化为5, 如果给出的初始值是其他类型的值如5.56,它将会将其转化为一个整数给a。
3. 联合的内存分配
分配给联合的内存数量取决于它的最长成员的长度,这样,联合的长度总是可以容纳它最大的成员。如果这些成员的长度相差悬殊,将会浪费很多的空间,最好的办法是在联合中存储不同成员的指针而不是直接存储成员本身,因为所有的指针长度都是相同的。