复杂数据类型
复杂数据类型
结构体struct
结构体的描述和定义变量
//结构体定义的方式
struct 结构体名称
{
数据类型 成员变量1;
数据类型 成员变量2;
数据类型 成员变量3;
数据类型 成员变量...;
};//必须要有分号
struct 结构体名称 data;//结构体定义的变量
struct 结构体名称
{
数据类型 成员变量1;
数据类型 成员变量2;
数据类型 成员变量3;
数据类型 成员变量...;
}data0,data1;也可以这样定义变量
struct //没有结构体名称只能在下面定义
{
数据类型 成员变量1;
数据类型 成员变量2;
数据类型 成员变量3;
数据类型 成员变量...;
}data0,data1;也可以这样定义变量
结构体是可以存放大量不同数据类型的类型。结构体不能包含不完整的数据类型和函数类型,结构体也不能包含自己定义的类型(原因是因为自己的函数类型还没有构建完成),但是可以包含自己定义的结构体类型的指针。
struct studentinfo
{
char name[100];
int age;
long number;
char sex[10];
struct studentinfo stu1;//这个是不可以的
struct studentinfo *stu1;//这个是可以的
};
- 结构体的访问
.和->
访问结构体内部成员需要使用这两个运算符
struct studentinfo
{
char name[100];
int age;
long number;
char sex[10];
}stu1,*stu2;
int main()
{
//如果访问的是结构体定义的普通变量内部的成员,使用.
stu1.age stu1.name stu1.number stu1.sex
//如果访问的是结构体定义的结构体指针内部的成员,使用->
stu2->age stu2->name stu2->number stu2->sex
//这两个运算符也可以互相转换
(*stu2).age (&stu1)->age
return 0;
}
需要注意的是在使用堆空间申请空间指向结构体类型的话,把这个空间给到指针,不能直接使用箭头访问,这个空间是用来存储地址的,还没有把结构体变量的指针,或者普通变量的地址赋值给,在堆空间申请的内存。直接访问会访问到NULL,导致段错误
struct studentinfo a;
struct studentinfo *p = (struct studentinfo *)malloc(sizeof(struct studentinfo));
//也就是这样,不能直接访问
p->age
//需要让他指向一个结构体,这样就可以
p = &a;
p->age
- 结构体的大小
在定义结构体的时候,结构体并不会获得内存,他只是一个数据类型,只有在使用这个结构体类型定义变量的时候才会获得空间
这个空间是多大的,一般是由每一个成员的空间大小相加,需要注意的是在计算机的内部的数据总线和地址总线都是有系统决定的(32位地址和数据总线都是4个字节)(64位地址和数据总线都是8个字节),计算机会根据自己的效率决定,结构体有一个概念字节对齐,就是不够这个字节系统会自动补齐,32是4个字节对齐,64位是8个字节对齐,这就是典型的以空间换时间案例
struct studentinfo
{
char name[100];
int age;
long number;
char sex[10];
};
//64位系统
//如果只是普通的计算这个结构体的大小为100+4+8+10=132字节
//但是他是遵循8字节对齐,从往下看,是否合适8个字节,如果上一个加这个超过8字节,那么就不能把这一个加上去,上一个就要补齐8个字节,从这一个再次开始,往下面看是否满足8个字节
name100字节 剩余4个字节
上面4个字节和age刚好8个字节
number刚好8个字节
sex才10个字节需要补6个凑8的倍数
n个字节对齐就是n的倍数
C语言提供了一个预处理指令,可以设置字节对齐#pragma pack(n)
n:1、2、4、8....
#pragma pack(1)
struct studentinfo
{
char name[100];
int age;
long number;
char sex[10];
};
//这里面遵循1字节对齐
#pragma pack()//默认系统
一般而言结构体类型的名称很长,不方便使用,typedef
使用这个关键字可以把数据类型从新命名
typedef unsigned int uint32_t;
//就可以使用uint32_t定义数据类型一般而言_t都是别名
typedef struct studentinfo
{
char name[100];
int age;
long number;
char sex[10];
}s_t;
//现在这个s_t就不是变量,而是数据类型的别名
联合体union
联合体而言,内部所有的成员都共用一个内存,这个内存空间就是最大字节的成员,也是遵循字节对齐。和结构体类似。
union u
{
int a;
char b;
}c;
//成员a,b都共用一个空间就是a这个空间,所以他们的地址都是一样的,只是字节长度的问题
int main()
{
c.a = 0x12345678;
printf("%#x",c.b);//小端 0x78,大端 0x12
}
枚举体enum
枚举内部的成员都是常量,意义就是将常量赋予有意义的词,提高可读性
- 如果内部成员没有被赋值,那么第一个成员会自动赋值为0,下一个成员等于当前成员的值+1。
enum
{
a, //0
b, //1
c = 10, //10
d //11
};
//可以在程序中直接使用,和常量一样