一 结构体的声明
1.概念
结构是一些值的集合,这些值称为成员变量
结构的每个成员可以是不同类型的变量
结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间
结构体变量才包含了实实在在的数据,需要内存空间来存储
2.结构体的声明
struct tag
{
member-list;
}variable-list;
tag为结构体标签,用来区分不同的结构类型
struct tag
为结构体类型
member-list
为成员列表,是结构体所包含的基本的结构类型
variable-list
变量列表(可写可不写)
结构体声明结束时;
切勿忘记
当结构体声明在main函数之外的创建的结构体变量是一个全局变量,反之为局部变量
结构体成员变量也可以是另一个结构体类型,用法:嵌套结构体
3.特殊的声明(匿名结构体类型)
注意:除非只想使用一次创建的结构体类型才可以使用匿名结构体类型
提问:当两个匿名结构体类型的成员变量完全一样时,可以看作是相同的类型吗
#include<stdio.h>
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
int main(){
pa=&x;
return 0;
}
结果:
原因:编译器会把上面连个声明的结构体类型当成两个不同的类型
4.typedef使用
可以这样写,typedef struct node{ }NODE;
或者typedef struct n{ }NODE。
在申请变量时就可以这样写,NODE n;
二 结构的自引用
在结构中包含一个类型为该结构本身的成员是否可以呢?
struct node{
int a;
struct node next;
};
答案:不可以
因为sizeof(struct Node)
的计算没有尽头
正确写法
struct node{
int a;
struct node *next;
};
因为成员next是指向struct node结构的指针,可以确定指针next所需要的内存空间,而指针无非就是4/8个字节,不会出现无法计算的情况。
注意typedef的使用
typedef struct
{
int data;
Node* next;
}Node;//这样不可行,因为在结构体内部出现的Node是未定义的
正确写法
typedef struct Node
{
int data;
struct Node* next;
}Node;
三 结构体变量定义和初始化
注意
关于结构体变量的初始化与初始化数组类似;也是使用花括号括起来,用逗号分隔的初始化好项目列表,注意每个初始化项目必须要和要初始化的结构体成员类型想匹配
struct node{
int a;
char name[20];
float c;
}p1;//声明结构类型时定义变量p1
struct node p2;//定义结构体变量p2
struct node p3={3,"Joshua",20.5
};//初始化:定义变量的同时赋初值
结构体嵌套初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化
四 结构体内存字节
1.先了解结构体对齐规则
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
参考以下代码理解
#include<stdio.h>
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
int i;
};
struct S3{
double d;
char c;
int i;
};
struct s4{
char c1;
struct S3 s3;
double j;
};
int main(){
printf("%d\n",sizeof(struct S1));
printf("%d\n",sizeof(struct S2));
printf("%d\n",sizeof(struct S3));
printf("%d\n",sizeof(struct s4));
return 0;
}
结果
2. 如何节省空间
结构体的内存对齐是拿空间换取时间
经过上面代码可发现让占用空间小的成员尽量集中在一起可以节省空间
3.怎么修改默认对齐数#pragma pack()
例如
`
在#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认这里插入代码片`
五 结构体传参
传参方式
1.传值,当结构体过大时,参数压榨时系统的开销较大,会导致性能下降
2.传地址,永远是4或8个字节
注意:结构体变量名用.来访问结构体成员
结构体变量地址用->来访问
举例
#include <stdio.h>
struct N{
int a;
char name[10];
};
void print1(struct N n){
printf("%s\n",n.name);
}
void print2(struct N* n){
printf("%s\n",n->name);
}
int main(){
struct N n={10,"Joshua"
};
print1(n);
print2(&n);
return 0;
}