结构体知识点整合(前篇)
Posted 追梦杰尼龟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结构体知识点整合(前篇)相关的知识,希望对你有一定的参考价值。
结构体知识点整合(前篇)
结构体知识点(前篇)
(1)结构体类型的声明
(2)结构体变量的定义和引用
(3)结构体大小的求解
(4)结构体类型的初始化
(5)结构体数组的定义和初始化
首先什么是结构体?
为什么需要结构体呢?
c语言中有许多数据类型,比如int double float等等,当我们想要把这些复杂的数据类型组合到一起的时候,比如当我们需要一个学生的信息,我们需要把他的姓名,性别,年龄,年级等不同的数据类型整合到一起的时候,我们就需要用到结构体。
结构体可以把功能相同的数据组织
起来,存在一起,用的时候方便。可以把有内在联系的不同的变量组织起来,封装成一个整体,即定义为一个结构体。之后就可以像处理基本数据类型那样,对结构体类型进行处理。
1.结构体类型的声明
结构体是一种构造类型
,它由若干成员组成。其成员可以是一个基本数据类型,也可以是另一个构造类型。
构造数据类型:构造数据类型是根据已定义的一个或多个数据类型用构造的方法来定义的。也就是说,一个构造类型的值可以分解成若干个“成员”或“元素”。
声明结构体时使用的关键字是struct
,如以下形式:
struct 结构体名
成员
;
例如:
/*关键字是struct*/
struct Student /*声明结构体*/
char Name[20]; /*成员*/
int Number;
char xy;
int Grade;
; //注意末尾大括号后的分号
/*在结构体中定义了4个不同的变量*/
2.结构体变量的定义和引用
<1>.定义结构体变量的方式有以下两种
(1)先声明结构体类型,再定义变量。
需要提到的一点是声明结构体类型的时候,系统是不会对其分配储存空间的,只有当定义结构体变量的时候系统才会对其分配储存空间
。
struct Student /*声明结构体*/
char Name; /*定义结构体成员*/
int number;
float num;
double grade;
char xy;
;
struct Student one;/*定义结构体类型变量*/
struct Student two;
(2)声明结构体类型的同时定义结构体变量。
struct Student //Student是结构体类型
char Name;
int number;
float num;
double grade;
char xy;
;one,two; /*定义结构体变量*/
结构体的类型和变量是不同的,Student是结构体类型,而one,two是结构体变量,那么只能对变量进行赋值,是不可以对类型进行赋值操作的。
结构体的成员也可以是结构体类型的变量。例如:
struct shape /*声明结构体类型*/
int hight; //包含了身高体重发型
int weight;
char hair;
;
struct Student
char Name;
int number;
float num;
double grade;
char xy;
struct shape boy; //结构体成员里含有结构体类型变量
one,two;
在struct Student结构体类型中包含struct shape结构体类型;
<2>.结构体变量的引用
定义了结构体类型变量后就可以进行引用该变量了,引用的格式为“结构体变量名.成员名”
。
例如:
struct Student
char Name[20];
int Number;
char xy[20];
int Grade;
one;
one.Name = "caigiegie";/*引用*/
one.Grade = 1;
对结构体变量进行赋值等运算,就是对结构体成员进行操作。上面的赋值运算就是对成员Name和Grade进行的操作。
注意:不能直接将结构体变量作为一个整体进行输入和输出。
例如:
pirntf("%s%d%s%d",one); //这样子是错误的
需要使用运算符“.”
。
printf("%s",one.Name);
printf("%d",one.Number);
printf("%s",one.xy);
printf("%d",one.Grade);
结构体变量的成员可以像普通的变量一样进行运算。
例如:
one.Number++;
因为“.”的运算符的优先级别最高
,所以one.Number++是成员进行自加运算。
3.结构体大小的求解
在第2点中我们提到,声明结构体类型的时候是不会分配储存空间的,只有在定义结构体变量的时候才会分配存储空间的,那么给结构体分配了多少的内存空间呢?那么怎么去求解它呢?
看如下的代码
struct Student
char Name; //1 bytes
char xy; // 1 bytes
int number; // 4 bytes
float num; // 4 bytes
double grade; // 8 bytes
;
struct Student one;
int main()
int a = sizeof(one.Name );
int b = sizeof(one.xy );
int c = sizeof(one.number);
int d = sizeof(one.num );
int e = sizeof(one.grade);
int m = sizeof(one);
printf("%d %d %d %d %d\\n",a,b,c,d,e);
printf("%d",m);
是将结构体中的每一个变量类型的大小加起来吗?
是1+4+4+8+1 = 18吗?
运行过后,发现并不是简单的将结构体成员的每个内存单元加起来就是该结构体的大小,并且将结构体成员简单的调换一下顺序结果也不一样。
struct Student
char Name; // 1 bytes
int number; // 4 bytes
float num; // 4 bytes
double grade; // 8 bytes
char xy; // 1 bytes
;
那么为什么有所不同呢?
结构体的大小求解:结构体的大小为最后一个成员的偏移量+其所占的字节数
.
偏移量指的是结构体变量中成员的地址和结构体变量的地址的差,第一个成员的偏移量为0
,第二个成员的偏移量为第一个成员的偏移量加上第一个成员所占字节数的大小
,依次类推。
计算结构体大小还需要分两种情况:
<1>:没有结构体嵌套;
法一:
结构体的大小为最后一个成员的偏移量+其所占的字节数
,除了这个准则外,还需要满足以下的两个原则:
1:结构体中成员的偏移量必须是该成员所在字节数的整数倍
。(0是任何所占字节数的倍数
)
2:结构体的大小必须是所有成员的整数倍
,即最小公倍数。
struct Student
char Name; //1 bytes
char xy; // 1 bytes
int number;// 4 bytes
float num; // 4 bytes
double grade; // 8 bytes
;
成员 | 所占字节数 | 偏移量 |
---|---|---|
Name | 1 | 0 |
xy | 1 | 1+0=1(是所占字节数的倍数) |
number | 4 | 1+1=2–>4(补齐到是字节数的倍数) |
num | 4 | 4+4=8(是4的倍数) |
grade | 8 | 4+8=12–>16(补齐到是8的倍数) |
该结构体的大小为最后成员的所占字节数大小+偏移量大小
就是8+16=24(此时还要看一看是不是满足第二个原则)
24正好是所有成员的倍数,满足,不需要补齐。
所以最终结构体大小就是24。
再看看调换顺序的那个结构体大小是怎么求解的
struct Student
char Name; // 1 bytes
int number;// 4 bytes
float num;// 4 bytes
double grade; // 8 bytes
char xy;// 1 bytes
;
成员 | 所占字节数 | 偏移量 |
---|---|---|
Name | 1 | 0 |
number | 4 | 1+0=1–>4 |
num | 4 | 4+4=8 |
grade | 8 | 4+8=12–>16 |
xy | 1 | 16+8=24 |
结构体大小是24+1=25–>32(不满足第二原则,补齐至32)
法二:(图解)
(1)首先找到结构体成员中所占字节数最大的占几个字节
(2)以该字节大小为单元,从上至下一次填入各个成员,当第一个单元出现再填入一个成员会超出该单元的情况时,将此成员移动至下一个单元,再依次填入。
(3)结构体大小就为n * 单元大小
(n就是几个单元)
例如:
struct Student
char Name; //1 bytes
char xy; // 1 bytes
int number;// 4 bytes
float num; // 4 bytes
double grade; // 8 bytes
;
struct Student
char Name; // 1 bytes
int number;// 4 bytes
float num;// 4 bytes
double grade; // 8 bytes
char xy;// 1 bytes
;
<2>:有结构体嵌套:
还是遵循结构体的大小为最后一个成员的偏移量+其所占的字节数
需要将嵌套的结构体展开,并且被展开结构体的第一个成员变量的偏移量必须为这个被展开结构体中所占最大字节成员的整数倍
。
并且遵循上面的两个原则
1:结构体中成员的偏移量必须是该成员所在字节数的整数倍。
2:结构体的大小必须是所有成员的整数倍,即最小公倍数。
struct Student
char Name; //1 bytes
char xy;//1 bytes
struct m
int a; // 4 bytes
char b; // 1 bytes
;
int number;// 4 bytes
float num; // 4 bytes
double grade; // 8 bytes
one;
int main()
printf("%d",sizeof(one));
成员 | 所占字节数 | 偏移量 |
---|---|---|
Name | 1 | 0 |
xy | 1 | 1+0=1 |
a | 4 | 4 |
b | 1 | 4+4=8 |
number | 4 | 1+8=9–>12 |
num | 4 | 12+4=16 |
grade | 8 | 16+4=20–>24 |
结构体大小为8+24 = 32(满足条件2)
所以结构体大小就为32
我们再来一道:
struct Student
char Name; //1 bytes
char xy;//1 bytes
struct m
int a; // 4 bytes
double c;//8 bytes
char b; // 1 bytes
;
int number;// 4 bytes
float num; // 4 bytes
double grade; // 8 bytes
one;
int main()
printf("%d",sizeof(one));
成员 | 所占字节数 | 偏移量 |
---|---|---|
Name | 1 | 0 |
xy | 1 | 1+0=1 |
a | 4 | 1+1=2 ->8(最大字节数的倍数) |
c | 8 | 4+8=12->16 |
b | 1 | 16+8=24 |
number | 4 | 24+1=25->28 |
num | 4 | 28+4=32 |
grade | 8 | 32+4=36->40 |
所以结构体大小为40+8=48 (满足是所有成员所占字节数的倍数)
所以结构体的大小就是48字节。
4.结构体类型的初始化
结构体类型的初始化也有两种方式
(1)在定义结构体变量时指定初始值。
例如:
struct Student
char Name[20];
char xy[10];
int Grade;
one = "Caigiegie","男",1; /*定义结构体变量并且设置初始值*/
(2)后续定义结构体变量再赋值
struct Student
char Name[20];
char xy[10];
int Grade;
;
int main()
struct Student one = "Caigiegie","男",1; /*后续定义结构体变量并且赋予初始值*/
printf("姓名:%s\\n",one.Name );
printf("性别:%s\\n",one.xy );
printf("年级:%d\\n",one.Grade );
5.结构体数组的定义和初始化
<1>.结构体数组的定义
定义结构体数组与定义结构体变量的方法是一样的。
例如:
struct 结构体名
成员;
数组名;
例如定义结构体数组,包含5个学生的信息。
struct Student
char Name[20];
int age;
int Grade;
char xy[20];
one[5];//定义结构体类型的同时定义了结构体数组
或者先声明结构体类型后定义结构体数组
struct Student one[5];
<2>.结构体数组的初始化
初始化结构体数组的形式如下:
struct 结构体名
成员列表;
数组名 = 初始化值;
例如:
struct Student
char Name[20];
int age;
int Grade;
char xy[20];
one[3] = "c",15,1,"男","d",16,2,"女",
"c",17,3,"男"; /*定义数组并且初始化*/
关于将结构体数组输出:
利用循环将其输出.
int i;
for(i=0; i<3; i++) //定义循环变量i
printf("%s %d %d %s\\n",one[i].Name,one[i].age,one[i].Grade,one[i].xy);
前篇知识点完结--------
以上是关于结构体知识点整合(前篇)的主要内容,如果未能解决你的问题,请参考以下文章