在c语言的自定义类型中,主要就是结构体,联合,位段,枚举这几种。今天就让我们详细讲述一下他们各自的特点。
在这几种自定义类型中,应用最广泛的我觉得就是结构体了吧。
比如我们定义一个结构体。
struct A{
char job[20];
int age;
char *p;
float c;
}a,*p;
struct 是结构体的类型,A 是结构体的名称,而其中的 char job[20]; int age; float height;等都是结构体的成员,最后的a *p 都是 定义出来的结构体变量。
在结构体定义创造的过程中,结构体的名称的存在保证了你可以以 struct A a;的形式在函数内定义结构体局部变量,如果把A 省去,则只能在结构体定义的最后像a这样定义全局变量,结构体变量可以省略吗?当然可以。结构体内可以没有结构体成员吗?不可以,定义要求结构体内部至少有一个结构体变量。
那什么时候可以省略结构体名称还可以在函数内部定义结构体变量?
typedef struct A{
int i;
char pc[0];
}s;
通过typedef 定义过的类型可以直接在函数内部 s arr[ 3 ];的形式 结构体变量。
在这里我们注意,我们不可以在结构体内套一个结构体,很容易理解,这样在开辟空间的时候会崩溃,一个结构体,套一个结构体,这个结构体大小无法计算。所以,我们通常通过嵌套结构体指针的方式进行定义。
struct A{
int i;
char pc[2];
struct A *p;
}s;
在我们学习结构体的时候,我们很容易联想到另一个类型,数组,他们之间有很多相似处,比如,他们都是一起开辟的一段连续的内存单元;他们的地址都和首元素的地址在数值上相同,今天我们又特别强调一点,他们初始化也是相似的,也就是说结构体可以整体初始化。 struct A a={1,{1,2},NULL };
当然我们也可以用memset函数进行初始化0;
内存中,不是所有位置都可以访问的,而结构体内部个成员变量的类型是不同的,这样就存在内存对齐问题。
在考虑内存对齐问题中,我们重点注意四点。
1.结构体的第一个成员在内存中存储时,偏移量为0,也就是说默认是对齐的,也可以认为她不用对齐。
2.结构体的其他元素对齐到自身对齐数的整数倍,(对齐数:就是系统默认对齐数,和自身成员大小的较小值,系统默认的对齐数linux平台下是4,vs编译器下是8)
3.结构体的总大小要求是成员中最大对齐数的整数倍。
4.当结构体嵌套结构体时,内部的结构体的对齐数为其内部成员的最大对齐数,而外部的结构体在计算最大对齐数时应包含内部结构体的对齐数。
这样就可以解释,为什么计算我们用sizeof求结构体大小 并非是类型大小累加了。
关于位段,是按比特位分配存储的,他的功能是尽可能的压缩、节省空间。
struct node
{
int a:4; //位段a,占4位
unsigned int :0; //无名位段,占0位
unsigned int b:4; //位段b,占4位
int c:32; //位段c,占32位
int :6; //无名位段,占6位
};
当一个 字节剩余的空间可以放下当前变量时,就放,不能完全放下时,则开辟新的字节存放。
关于枚举,其实就是整形,他列举了一件事件所有发生的可能性,这样增强了程序的可读性,规范性。建议使用。
enum DAY
{
MON=1, TUE, WED=4, THU, FRI, SAT, SUN
};
联合共用体 是指一段空间被多个变量共同使用,空间大小,为最大的变量大小。
union data{
int n;
char ch;
double f;
};
union data a, b, c;
以上就是我个人关于自定义类型学习的一点小总结。