一、结构体是什么
结构体就是一些不同类型数据的集合,结构体的作用就是把这些不同类型的数据相当于是打包在一起了,是一种自定义的类型
二、为什么需要结构体
因为内置类型不能满足我们的需求了,例如int是定义整型的,float是定义浮点型的,char是定义字符型的,但是如果一个数据的属性有整型、浮点型、字符型,那此时这些数据类型就都不能满足我们的需求了,没有一种类型可以定义浮点数、整数和字符,为了完成这些需求,就需要我们自己定义一种类型,可以包含浮点数、整数和字符,那结构体就出现了,它可以包含多种类型的数据。
例如在定义一个学生时,学生有学号(int类型的)、姓名(char类型的)、性别(char类型的)、年龄(int类型的),我们所知道的所有的内置类型都定义不了一个学生,此时我们就可以用结构体来定义这个学生,结构体就相当于是把学生所有的属性都给打包在一起了,那结构体就是我们自己定义的数据类型,是一种自定义的数据类型。
三、C语言中的结构体
1.格式
struct student
{
int id;//学生的学号
char name;//学生的名字
char gender;//学生的性别
int grade;//学生的成绩
};
//struct是结构体关键字
//student是结构体的名字
//{};中的内容是结构体中的成员
注:C语言中的结构体不能包含函数,只能是一些变量
2.结构体的大小
说到结构体的大小,我们就要来好好说说内存对齐了
内存对齐
(1)内存对齐是什么
就是一种规则,在计算结构体的大小时,需要看此结构体的内存对齐规则是什么,才能够去计算大小
1.第一个成员在结构体变量偏移量为0的地址;(就是说第一个变量的地址从0开始算)
2.其他成员变量需要对齐到某个数字(对齐数)的整数倍处;
对齐数=编译器的默认对齐数 与 该成员大小中的较小值
VS默认对齐数为8,linux默认对齐数为4
(注:因为VS的默认对齐数为8,所以一般如果是在VS中结算结构体的大小时,对齐数=该成员的大小)
3.结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍;
4.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是最大对齐数(含嵌套结构体的对齐数)的整数倍处
(2)为什么需要内存对齐
a、平台原因
并不是说所有的硬件可以访问任意地址上的任意数据的,其实有时硬件在访问地址时,是有限制的,某些硬件平台只能在某些地址处取某些特殊的数据,否则就会抛出异常;
b、性能原因
数据结构(尤其是栈)应该尽可能的在自然边界上对齐,如果不对齐,处理器为了访问未对齐的内存,可能需要多次访问,但是如果对齐了的话,访问一次就好
(3)使用预处理命令设置默认对齐数
#pragma pack(n);//n必须是2的次方,例如n可以为1,或者 2 或者 4 或者 8 或者 16
(4)如何计算结构体中某成员相对于结构体起始位置的偏移量?
如下结构体,如何计算成员变量_gender相对于结构体起始位置的偏移量?
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
using namespace std;
#pragma pack(1)
struct student
{
int _id;//学生的学号
char _name[10];//学生的名字
char _gender[5];//学生的性别
int _grade;//学生的成绩
void SetInfo(int id, char*name, char*gender, int grade)
{
_id = id;
strcpy(_name , name);
strcpy(_gender, gender);
_grade = grade;
cout << _id << "," << _name << "," << _gender << "," << grade << endl;;
}
};
int main()
{
struct student s;
s.SetInfo(2102993, "张三", "男", 100);
cout << sizeof(student) << endl;
system("pause");
return 0;
}
计算成员_gender相对于结构体起始位置的偏移量:
第一种方法:偏移量=成员自己的地址-结构体的地址
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
using namespace std;
#pragma pack(1)
struct student
{
int _id;//学生的学号
char _name[10];//学生的名字
char _gender[5];//学生的性别
int _grade;//学生的成绩
void SetInfo(int id, char*name, char*gender, int grade)
{
_id = id;
strcpy(_name , name);
strcpy(_gender, gender);
_grade = grade;
cout << _id << "," << _name << "," << _gender << "," << grade << endl;;
}
};
int main()
{
struct student s;
s.SetInfo(12, "张三", "男", 100);
cout << sizeof(student) << endl;
int num = (int)&s._gender - (int)&s;//num是计算的偏移量
cout << num << endl;
system("pause");
return 0;
}
int num = (int)&s._gender - (int)&s;
//&s._gender得到的是成员_gender的地址
//&s得到的是结构体的地址
第二种方法:使用宏offsetof
offsetof的使用格式:
offsetof(结构体,结构体中的成员变量)
此成员是需要计算偏移量的成员
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
using namespace std;
#pragma pack(1)
struct student
{
int _id;//学生的学号
char _name[10];//学生的名字
char _gender[5];//学生的性别
int _grade;//学生的成绩
void SetInfo(int id, char*name, char*gender, int grade)
{
_id = id;
strcpy(_name , name);
strcpy(_gender, gender);
_grade = grade;
cout << _id << "," << _name << "," << _gender << "," << grade << endl;;
}
};
int main()
{
struct student s;
s.SetInfo(12, "张三", "男", 100);
cout << sizeof(student) << endl;
int num = (int)&s._gender - (int)&s;
cout << num << endl;
cout << offsetof(student, _gender) << endl;
system("pause");
return 0;
}
运行结果:
上述结构体的大小:
结构体大小 = 结构体中所有变量大小之和
struct student
{
int _id;//占字节0-3,共4个字节
char _name[10];//占字节4-13,对齐数为1,故现在有14个字节
char _gender[5];//占字节14-18,对齐数为1,故故现在有19个字节
int _grade;//占字节19-22,对齐数为4,所以需要对齐到4的整数倍处--->24,所以现在有24个字节
};
所以,此结构体的大小为24
四、C++中的结构体
1.格式
struct student
{
int _id;//学生的学号
char _name[10];//学生的名字
char _gender[5];//学生的性别
int _grade;//学生的成绩
void SetInfo(int id, char*name, char*gender, int grade)
{
_id = id;
strcpy(_name , name);
strcpy(_gender, gender);
_grade = grade;
cout << _id << "," << _name << "," << _gender << "," << grade << endl;;
}
};
ps:C语言中的结构体不允许有函数,而C++中的结构体是可以有函数
2.结构体的大小
结构体大小=结构体中所有变量之和
ps:计算方法也是以内存对齐原则为依据
五、C中的结构体与C++中的结构体的区别
1.是否可以有函数
(1)C中的结构体不可以有函数
(2)C++中的结构体可以有函数,且允许该函数为虚函数,但是放的函数是与结构体中的成员有关的
2.在定义变量时的格式不同
(1)C中定义变量,必须把关键字struct带上,例如struct student s;必须这样定义
(2)C++中在定义变量时可以不加关键字struct,例如:student s;
3.结构体成员的访问权限不同
(1)C中结构体成员的访问权限只能是public
(2)C++中结构体成员的访问权限可以有三种,分别为:public、protected、private(注意:结构体成员的默认权限是public)
4.结构体是否可以继承
(1)C中的结构体是不可以继承的
(2)C++中的结构体是可以从其他类或者其他的结构体继承过来的
以上都是表面的区别,实际的区别是面向过程和面向对象编程思想的区别
C中的结构体只是把数据变量给包裹起来了,并不涉及算法
C++中的结构体是把数据变量和这些数据变量涉及的相关算法进行了封装
ps:C中是没有类的概念的,但是C语言可以通过结构体内创建函数指针来实现面向对象的思想
六、C++中结构体与类的区别
1.关键字不同
(1)结构体的关键字是struct
(2)类的关键字是class
2.成员的访问权限不同
(1)结构体的成员变量和成员函数在不定义访问权限时,默认为公有public(这是为了兼容C)
(2)类的成员变量和成员函数在不定义访问权限时,默认为私有private(这是为了不破坏类的封装性)
3.继承时的权限不同
(1)结构体的继承默认是公有(public)的
(2)类的继承默认是私有(private)的