一、结构体的定义:
结构体(Struct)是C语言中的一个重要数据类型,它可以用来存储多个不同类型的变量。结构体类似于一个自定义的数据类型,可以包含多个不同类型的成员变量,每个成员变量可以有自己的数据类型和值。
二、结构体存储数据方式
结构体存储数据遵循两个原则:
原则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。
原则二:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。
三、结构体定义变量的方式
1、在struct{}之后直接定义变量名
struct Books
{char title[50];char author[50];char subject[100];int book_id;
} book;
2、在main函数当中定义变量名
struct Books
{char title[50];char author[50];char subject[100];int book_id;
};int main()
{struct Books
}
四、结构体赋值方式以及注意事项
在定义结构体时是不能在结构体里给变量初始化, 因为定义结构体时,并未给其分配内存,所以初值是无法存储的。
就如下面:
struct A{int age =18;char name[10] = "zs";
}
这个是不允许的!!!
结构体中赋初值有如下方式:
1、
struct A{int age;char name[10];char sex[4];
}int main()
{struct A a = {18,"zs","男"};
}
2、 注意字符数组不能直接a.name = "zs",因为这相当于char name[10];name[10] = "zs",这是不允许的,要用strcpy()函数给字符串数组赋值,但是,如果结构体里定义的是char *name,那么就可以直接a.name = "zs";
struct A{int age;char name[10];char sex[4];
}int main()
{struct A a;a.age = 4;strcpy(a.name,"zs");strcpy(a.sex,"男");
}
3、结构体中不能在定义完变量后整体赋初值,如:
struct A{int age;char name[10];char sex[4];
}int main()
{struct A a;a = {18,"zs","nan"}
}
4、在定义结构体类型的同时进行结构体变量初始化,这个是可以的
struct student{char name[32];int age;char gender;double score;}Phoebe = {“Phoebe”,17,'F', 92.5};
5、 结构体变量部分初始化:
struct student{char name[32];int age;char gender;double score;}Phoebe = {“Phoebe”, 17};
6、 结构体变量指定部分初始化:
struct student{char name[32];int age;char gender;double score;}Phoebe = {.name = “Phoebe”, .score = 17.0};
3、结构体中偏移量问题
1、整个结构体的大小会是结构体中所占字节数最大的那个数据类型的整数倍
2、每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的(以结构体变量首地址为0计算)
如:
#include<stdio.h>
struct A{char a;char b;int c;double d;
};
int main()
{struct A a;printf("%ld\n",sizeof(a));
}
其中各数据所占图为:
(1-8表示字节数)其中double类型在该结构体中所占字节数最大,所以结构体的整体大小应该是double类型的整数倍,也就是8的整数倍。
①先存放a,因为a是char类型,占一个字节
②再放b,b也是char类型,占一个字节,a占1个字节,刚好是b类型的1倍,所以b直接放在a后面
③再放c,c是int型变量,占4个字节,因为每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,所以前面空两格,这样的话前面刚好4个字节,所以c放在5的位置
④最后放d,d是double型变量,占8个字节,前面的变量已经占了8个字节(包括空出来的)所以d直接放在下一行
如上,该结构体一共占2×8个字节数,打印结果:
4、结构体中位域问题
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位为此,C 语言又提供了一种数据结构,称为"位域"或"位段",是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数,每个域有一个域名,位域在本质上就是一种结构类型,不过其成员是按二进位分配的,带有预定义宽度的变量被称为位域,在结构体中可以指定数据占多少位,如
struct A{char a:5;char b:3;
}int main(){struct A a;
}
在一个字节中,一共有八位,而上面a和b刚好能把一个字节占满,故在打印sizeof(a)时,显示出来a占1个字节。遵循的原则,相同的数据类型,在一行中能放的下就放,放不下就重新开一行
(1-8表示位数)
但如果时下面这种情况:
struct A{char a:5;char b:7;
}int main(){struct A a;
}
因为一个字节八位,a占5位,后面剩下3位,不足以存放b的位数,所以b会在新的一行存放7位,故a所占字节数位2。
还有一种,当里面数据类型不一样时,如:
struct A{char a:5;char b:7;int c:9;
}int main(){struct A a;
}
此时sizeof(a)的大小为4个字节,因为a占5位,但是因为b和a的数据类型一样,当一行里放不下b时,b会在下一行(下一个字节)存放,而c与b的数据类型不一样,所以c会在b的后面继续存放,现在已存放了三行,根据结构体中结构体所占字节大小为结构体中最大数据的字节数的整数倍,所以还会在下一行补充一行,故一共占4个字节。如图所示:
打印结果: