自定义类型
结构体
1>声明&定义
1.结构体是一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量。
struct stu
{
char name[20];
int age;
char sex[5];
char id[15];
}p1; //声明类型的同时定义变量p1
typedef struct stu
{
char _name;
int _age;
}stu; //这样写之后之后定义结构体只用 stu p1;
//而不像之前 struct stu p2;
2.特殊的声明
(1)不完全声明(匿名结构体类型)
//下面两个结构体在声明的时候省略掉了结构体标签(tag)
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20],*p; //声明的时候定义了两个变量,一个数组类型,一个指针类型>
p != &x; //编译器会把前面的两个声明当成完全不同的两个类型,所以p = &x;是非法的
2>结构体成员的访问
通过"->“与”."访问结构体成员
(1)定义结构体指针,访问成员时就用“->”。
(2)定义结构体变量,访问成员时就用“.”。
struct A {
int a;
char b;
};
struct A q;
q.a; //结构体变量访问成员就用:
struct A *p;
p->a; //结构体指针访问成员就用:
3>结构体变量赋值
struct stu s = {"张三","MALE",19};//定义变量的同时初始化。
struct Node
{
int date;
struct Node* next;
}n1 = {10,NULL}; //定义结构体时初始化
struct Node s = {23,NULL}; //结构体嵌套初始化。
4>结构体传参
1.结构体传参
void print1(struct stu s)
{
printf("%d\n",stu.num);
}
2.结构体地址传参
void print2(struct stu* s)
{
printf("%d\n",stu->num);
}
3.小结
结构体传参首选结构体地址传参,因为函数传参时函数是需要压栈的,会有时间和空间上的系统开销,如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降。
5>结构体自引用
struct Node
{
int date;
struct Node* next;
};
6>结构体内存对齐
7>位段
位段的声明和结构体类似,与结构体有处不同:
1>位段的成员必须是 int , unsigned int ,signed int,或者是 char(属于整型家族)类型。
2>位段成员名后边有一个冒号和一个数字。
3>位段在空间上是按照需要以4字节(int)或者1字节(char)的方式开辟的,位段涉及很多不确定因素,位段是不跨平台的,注意可移植程序应该避免使用位段。
struct A
{
int _a:10;
int _b:2;
};
枚举
1>定义
枚举(列举)就是把可能的值列举。
enum Color
{
RED,
GREEN,
BLUE,
BLACK,
WHITE
};
2>赋值
(1)默认从0开始,一次递增1。
(2)定义的时候也可以赋初值。
enum Color
{
RED=1,
GREEN=2,
BLUE=4
};
3>枚举的优点
(1)增加代码的可读性和可维护性。
(2)与define定义的标识符相比较枚举有类型检查,更加严谨。
(3)防止命名污染。
(4)便于调试。
(5)使用方便,一次可以定义多个常量。
4>枚举的使用
只能拿枚举常量给枚举变量赋值,才不会出现类型差异。
联合(共用体)
1>定义
联合体是一种特殊的自定义类型,这种类型定义的变量包含一系列的成员,特征是这些成员公用同一块空间(所以联合体也叫共用体)。
union un
{
char c;
int i;
int k;
};
2>特点
联合体的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小.
3>联合体的大小计算
1.联合体的大小至少最大成员的大小。
2.当前最大成员大小不是最大对齐数的整数倍时,就要对齐到最大对齐数的整数倍。