什么是结构体?
由多种数据类型共同构成而成的数据类型,他们可以是标量、数组、指针、甚至是其他结构体。
结构体的声明
//例
struct Stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
结构体成员和.运算符
访问结构体对象的各个成员时使用.运算符,该运算符称为句点运算符
Stu.name //表示结构体Stu的成员name
结构体成员和->运算符
能够通过简洁的表示式来访问指针指向的对象成员
Stu->name //用指针访问结构体Stu中的成员name
结构体变量的定义和初始化
//定义
struct Student
{
char name[20];
int height;
float weight;
long schols;
}S1; //声明类型的同时定义变量p1
struct Student S2; //定义一个全局的结构体变量S2
int main()
{
struct Student S3;//定义一个局部的结构体变量S3
}
//初始化
struct Point p3 = {
x, y};//定义变量的同时赋初值
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s = {
"zhangsan", 20};//初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {
10, {
4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {
20, {
5, 6}, NULL};//结构体嵌套初始化
数组和结构体的不同之处
- 数组用于操作相同类型的数据集合,结构体用于操作不同类型的数据集合(有时也会出现成员类型相同的情况)
- 即便两个数组的元素的个数相同,也不能相互赋值。但是,相同类型的结构体可以互相赋值
结构体的自引用
struct Node
{
int data;
struct Noda* next;
}
返回结构体的函数
因为结构体可以进行赋值,所以可以用作函数的返回值类型。
#include<stdio.h>
struct xyz
{
int x;
long y;
double z;
};
struct xyz xyz_of(int x, int y, int z)
{
struct xyz temp;
temp.x = x;
temp.y = y;
temp.z = z;
return temp;
}
int main()
{
struct xyz s = {
0,0,0 };
s = xyz_of(12, 7654321, 89.2);
printf("xyz.x=%d\n", s.x);
printf("xyz.y=%ld\n", s.y);
printf("xyz.z=%f\n", s.z);
return 0;
}
结构体的内存对齐
结构体的对齐规则
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8 - 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
为什么存在内存对齐?
为什么存在内存对齐?
-
平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常 -
性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。