1,问题的引入 现实世界物体需要抽象成计算机语言中的数据类型 学生: 学号 ==> int 姓名 ==> char[] 性别 ==> char 年龄 ==> int 地址 ==> char[] 颜值 ==> int ... 这些都是物体的属性 ==>组合到一个数据类型中去 C语言允许程序定义自己的组合类型==>struct(结构体) 2,结构体: 自定义的一种组合数据类型 (1)结构体类型的定义: struct 结构体名 { 成员类型1 成员名1; 成员类型2 成员名2; ... 成员类型n 成员名n; }; eg: struct student { int num; char name[32]; char sex; int age; int score; char addr[32]; };//分号不能少 上面我们定义了一个新的类型 struct student 这个类型里面包含num,name,sex,age... struct student stu1;//定义了一个结构体变量stu1,他的类型是struct student 注意:结构体属于构造数据类型,我们必须要先定义(构造)结构体类型,再定义结构体类型的变量。 (2)结构体变量的内存分布: 结构体变量的内存空间是各个成员按顺序相加,同时要满足字节对齐 "字节对齐问题": 字节对齐问题是从cpu的效率考虑的。在不同的CPU和编译器下字节对齐的方式不一样。 在x86的gcc编译器是4字节对齐。小于4字节的变量如char型,可以多个占一组4字节, 大于或等于4字节的变量如int型,单独占4字节,最后总大小是4的倍数。 整体对齐:成员的空间大小小于对齐系数,按最大的成员大小对齐,若有成员的空间>=对齐系数, 就按对齐系数对齐。 eg: struct test { char a; char b; int c; char d; }; printf("%d\n",sizeof(struct test)); (3)结构体变量的引用 访问结构体成员变量的方式有: a. 结构体变量名.成员变量名 struct student stu; stu.age ".":域操作符 成员变量与普通变量的用法及含义一致:即可作左值又可作右值,还可以取地址。 b, *(结构体指针).成员变量名 struct student *p = malloc(sizeof(*p)); (*p).age c, 结构体指针->成员变量名 ->:指向结构体的成员变量 struct student *p =malloc(sizeof(*p)); p->age (4)结构体变量的定义并初始化 结构体的初始化用{} struct date { int year; int month; int day; }; struct student { char name[32]; int age; struct date birthday; }; a. 按定义时的顺序依次初始化,用逗号隔开 struct student stu1={"liudehua",18,{2008,8,8}}; b. 不按顺序,可以指定对哪个成员进行初始化 struct student stu2={.age=18,.name="liudehua",.birthday={.day=8,.month=8,.year=2008}}; (5)结构体数组 struct student a[10]={ {"zhangsan",18,{2008,6,7}}, {"lisi",20,{2006,6,7}} }; 3,共用体 几个不同的变量共同占用一段内存的结构,在C语言中,被称为"共用体"类型结构, 简称共用体 union 共用体名 { 成员类型1 成员名1; 成员类型2 成员名2; ... 成员类型n 成员名n; }; eg: union Data { int i; char ch; float f; };//定义共用体数据类型 union Data a;//定义了一个共用体变量,其类型为union Data ★共用体的初始化只能赋值一个成员,因为共用体本身只表示一个变量, 共用体分配的内存空间为其成员中占字节最大的那个成员的大小。 eg: union Data b ={16}; union Data c ={.i=16}; 共用体变量的赋值也只能赋值一个成员,多次赋值则会覆盖掉原来的值 eg: union Data a; a.i = 16; a.ch = 'c'; printf("%d\n",a.i); 大小端模式: 不同的芯片在对把寄存器的数据存放到内存中的处理方式有两个流派。 小端模式: 低地址存放低字节数据 大端模式: 低地址存放高字节数据 如何验证处理器是大端模式还是小端模式 (1)int a=0x12345678; char *p = (char*)&a; printf("%x %x %x %x\n",p[0],p[1],p[2],p[3]); (2)union data { int a; char b; }; union data n; n.a=0x12345678; printf("%x\n",n.b); 4,枚举 枚举类型用于声明一组命令的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。 enum 枚举类型名{枚举元素列表}; eg: enum weekday{sun,mon,tue,wed,thur,fri,sat};//定义了一个枚举类型 enum weekday workday = mon;//定义了变量workday并初始化 (1)枚举变量的赋值只能是枚举元素之一。 (2)枚举元素为代表整数的常量,从左到右依次代表为0,1,2,3。。。 (3)我们也可以人为指定枚举元素的数值,未指定的元素依次按顺序加1(数值可以重复) eg: enum weekday{sun,mon=2,tue,wed=0,thur,fri,sat}; enum weekday workday=sun; printf("%d %d %d\n",workday,tue,sat); 5,typedef typedef 用来声明一个新类型 作用:给一个已经存在的类型取一个新名字,使新的名字更能表示它的含义 eg: typedef int size_t; void *malloc(size_t size); typedef 与 #define 的区别: #define只是简单的字符串替换而已,而typedef则是为一个类型起新名字(定义了新类型) eg: typedef char* pStr1; #define pStr2 char* pStr1 s1,s2; pStr2 s3,s4; printf("%d %d %d %d\n",sizeof(s1),sizeof(s2),sizeof(s3),sizeof(s4)); 给数组取新名字 typedef int[10] array; ==> typedef int array[10];//定义的新类型array,代表int[10] array a; 给函数指针取新名字 int (*p)(int,char);//定义了一个函数指针变量 typedef int(*pfunc)(int,char);//定义了一个新类型pfunc //它的类型跟p的类型一样 pfunc p2;//定义了一个函数指针变量p2
