结构体定义和结构体变量初始化
结构体本质上还是一种数据类型,但它可以包含若干个“成员”,每个成员的类型可相同也可不同。定义结构体的格式如下:
//结构体的定义
struct 结构体名称
{
成员列表;
};
注:在定义任何一个结构体时,{}后的;一定不能忘!!!
例:定义一个学生类型的结构体,包括学号,姓名,性别,年龄
struct Student//定义一个名为Student的结构体
{
int s_id;
char s_name[20];
char s_sex[5];
int s_age;
}stu;//在结构体声明的同时定义了一个结构体变量stu
在结构体中要想访问成员时,要使用结构体成员运算符点(.)访问,一般形式是 结构体变量名.成员名
若我们想使用以上的Student结构体中的成员,就可以直接输入结构体变量名和相应运算符stu. 编译器就会自动跳出内部包含的成员供你使用,如果没有自动跳出,就说明输入的结构体变量名有误或结构体成员运算符使用有误。例如:
对以上结构体进行初始化操作,即: struct Student stu1 = { 01,"zhangsan","man",18 };
若想对以上的成员值进行修改,不是字符串的可以直接进行结构体成员变量和相应运算符访问修改,是字符串的要使用strcpy()函数
注:在使用strcpy()函数时,要引入头文件#include<string.h>
嵌套结构体
定义:在结构体中又包含其他结构体
struct Score
{
float c_score;//语文成绩
float m_score;//数学成绩
float e_score;//英语成绩
};
struct Address
{
char province[20];//省
char city[10];//市
};
struct Student
{
char name[10];//姓名
int age;//年龄
char sex[10];//性别
Score stu_score;//成绩结构体
Address address;//地址结构体
};//学生结构体
我们在学生结构体里嵌套了成绩结构体和地址结构体,初始化如下:
Student s = { "www",17,"male",{88,99,55},{"shanxi","xian"} };
如果想要对语文成绩进行更改到98,应为:s.stu_score.c_score=98;
如果想要对市进行更改为yulin,应为:strcpy(s.address.city,"yulin");
由此说明,若想访问此嵌套结构体里的变量,应使用两次"."如果结构体嵌套了三层,那么就应该使用三次"."去定位
结构体指针
一旦定义了指向结构体变量的指针,就可以通过该指针间接引用所指向的结构体变量,结构体指针定义如下:
struct Student//定义一个名为Student的结构体
{
int s_id;
char s_name[20];
char s_sex[5];
int s_age;
}stu;//在结构体声明的同时定义了一个结构体变量stu
Student stu1={1,"zhangsan","man",20);//对结构体进行赋初值操作
Student *p=&stu1;//定义指向结构体变量的指针变量p
此时若想对各个成员值进行更改,就要使用指针变量进行修改,一定是(*结构体指针变量).成员名
等价于 结构体指针->成员名。这里的 ->为指向运算符。因为成员运算符"."优先级高于间接引用运算符"*",所以这里的()不能省略,例:
Student stu1={1,"zhangsan","man",20);//对结构体进行赋初值操作
Student *p=&stu1;//定义指向结构体变量的指针变量p
(*p).s_id=2;//p->s_id=2
strcpy((*p).s_name,"lisi");//strcpy(p->s_name,"lisi")
strcpy((*p).s_sex,"woman");//strcpy(p->s_sex,"woman")
(*p).s_age=18;//p->s_age=18
结构体数组
定义:数组的每个元素都是一个结构体。例:
struct Student//定义一个名为Student的结构体
{
int s_id;
char s_name[20];
char s_sex[5];
int s_age;
}stu;//在结构体声明的同时定义了一个结构体变量stu
struct Student stu1[3]={{1,"zahngsan","man",17},{2,"lisi","man",16},{3,"lihua","woman",23}};
stu1 | s_id | s_name | s_sex | s_age |
stu1[0] | 1 | zahngsan | man | 17 |
stu1[1] | 2 | lisi | man | 16 |
stu1[2] | 3 | lihua | woman | 23 |
要进行修改时:
stu1[0].s_id=10;//将stu1[0]的id更改为10
strcpy(stu1[2].s_name,"huahua");//将stu1[2]的名字改为huahua
若想对结果进行输出,用一个for循环打印就好
结构体大小
如何计算结构体大小:
①结构体变量的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍
②结构体变量的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节整数倍
③结构体变量的总大小,是结构体变量中“最大基本数据类型成员所占字节数”的整数倍
例:
struct Student//定义一个名为Student的结构体
{
int s_id;//4
char s_name[20];//1
char s_sex[5];//1+2
int s_age;//4
}stu;//12
struct node
{
char ca[20];//1
char cb[20];//1+2
int c;//4
};//8
计算结构体大小时,要考虑内存对齐,也叫字节对齐,主要是为了提升CPU效率
什么是内存对齐呢?
①内存的大小基本单位是字节,理论上讲,可以访问任意地址,但由于CPU是以2,4,8的倍数的字节块来访问的,所以就会对基本数据类型的地址做出限制,即必须是2,4,8的倍数,这样就使得数据类型按照一定的规则进行排序,这就是对齐
②有些平台每次读地址都是从偶地址开始,如果一个int(X86,32位系统)存放在偶地址开始的地方,那么读一个周期就能找到这32bit(4字节)。如果存放在奇地址开始的地方,那就需要读两个周期,并对读到结果的高低字节进行拼凑才能得到这32bit,这显然降低了效率
③由于平台不同,字节对齐方式可能不同,所以同样的结构在不同的平台得到的大小可能不同,在无意识情况下,互发数据,可能导致数据出现错乱
Windows默认对齐方式 8字节
Linux 默认对齐方式4字节