八、复合类型和结构体
1.从基本数据类型到抽象数据类型
-
类型本地不存在
-
内存里的内容,你认为它是什么,他就是什么
-
-
一般的CPU只支持两种类型
-
整数,浮点数
-
-
高级语言设计类基本数据类型
-
整形,浮点型,字符型等
-
不同语言会定义不同的基本类型
-
基本数据类型并不能方便地解决所有问题
-
2.数组的解决方法
-
分配内存不集中,寻址效率不高
-
对数组进行赋值时,容易发生错位
-
结构显得比较零散,不容易管理
int studentId[30] = {1, 2, 3, 4, 5, 6};/* 最多可以管理30个学生, 每个学生的学号用数组的下标表示*/
char studentName[30][10] = {{"令狐冲"}, {"林平之"},{"岳灵珊"}, {"任盈盈"}};
char studentSex[30][2] = {{"男"}, {"男"}, {"女"}, {"女"}};
int timeOfEnter[30] = {2016, 2016, 2016, 2016}; /*入学时间用int表示*/
int scoreComputer[30] = {90, 78, 89, 78}; /*计算机原理课的成绩*/
int scoreEnglish[30] = {83, 92, 72, 95}; /*英语课的成绩*/
int scoreMath[30] = {72, 88, 98, 87}; /*数学课的成绩*/
int scoreMusic[30] = {82, 78, 66, 90}; /*音乐课的成绩*/
3.结构体的解决方法
◼ 结构体:
把关系紧密且逻辑相关的多种不同类型的变量组织到统一的名字之下,也称复合数据类型
这种类型的变量占用相邻的一段内存单元
◼ 共用体:
把情形互斥但又逻辑相关的多种不同类型的变量组织在一起
这种类型的变量占用同一段内存单元,因此每一时刻只有一个数据起作用
struct STUDENT
{
int studentID; /*每个学生的序号*/
char studentName[10]; /*每个学生的姓名*/
char studentSex[4]; /*每个学生的性别*/
int timeOfEnter; /*每个学生的入学时间*/
int scoreComputer; /*每个学生的计算机原理成绩*/
int scoreEnglish; /*每个学生的英语成绩*/
int scoreMath; /*每个学生的数学成绩*/
int scoreMusic; /*每个学生的音乐成绩*/
};
struct STUDENT是一个类型
◼ struct STUDENT students[30];
◼ students[0].studentName
students[0].Sex
它们都是变量,一般称为结构的成员变量
4.结构体的定义
-
先定义结构体类型再定义变量名
struct student student1, student2
-
在定义类型的同时定义变量
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}student1,student2;
-
直接定义结构体变量(不出现结构体名)
struct
{
int num;
char name[30];
char sex;
int age;
float score;
char addr[30];
}student1,student2;
1)结构体定义
struct complex_struct
{
double x,y;
};
struct complex_struct
{
double x,y;
}z1,z3;
2)结构体变量初始化
struct complex_struct z = { 3.0, 4.0 };
double x = 3.0;
struct complex_struct z1 = { x, 4.0, }; /* z1.x=3.0, z1.y=4.0 */
struct complex_struct z2 = {, 3.0 }; /* 错误 */
struct complex_struct z3 = { 3 }; /* z3.x=3.0, z3.y=0.0 */
struct complex_struct z4 = { .y = 4.0 }; /* z1.x=0.0, z1.y=4.0 */
3)结构体变量的赋值
struct complex_struct z1 = { 3.0, 4.0 };
struct complex_struct z2 = z1;
z1 = z2;
4)结构体变量的定义
-
用typedef为已存在的类型定义新名字
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
typedef struct student STUD;
STUD student1, student2;
// 用STUD代替 struct student类型;
-
定义自己的类型名
struct student student1; /* It works */
student student1; /* Can this work? */
typedef struct
{
...;
...;
} student;
student student1; /* It works! */
-
typedef 为某一类型创造自己的名字
typedef unsigned char byte_t;
typedef struct rect
{
double x;
double y;
}rect;
-
结构体定义可以嵌套
struct date
{
int month;
int day;
int year;
};
typedef struct date DATE; //定义时间结构体并定义名字
struct student
{
int num;
char name[20];
char sex;
int age;
DATE birthday; //嵌套时间结构体
char addr[30];
}student1, student2;
5)结构体的内存占用
-
一个结构变量的成员变量在内存中是相邻的
-
整个结构变量的将占用多少内存呢?
-
事实上,所有数据类型在内存中都是从偶数地址开始存放的,且结构所占的实际空间一般是按照机器字长对齐的
-
不同的编译器、不同的平台,对齐方式会有变化,不过一般的编译器都可以设定按照多大对齐
-
-
我们可以用sizeof来获得结构的大小
-
sizeof到底是什么?
-
他是一个C语言关键字,并不是函数
-
他可以用两种形式使用
-
sizeof(表达式)
-
常使用sizeof(变量名)
-
-
sizeof(类型)
-
-
求出的结果为表达式值所属类型或者类型占用的字节数,类型size_t
6)struct类型的特点
-
一个普通的类型
-
所以可以定义该类型的变量,数组,指针......
-
他的成员可以是任意类型
-
基本类型,数组,指针,结构......
-
-
可以做函数的参数类型和返回值类型
-
-
struct类型的变量
-
可以互相赋值
-
可以&
-
不可以参与运算
-
-
它的成员各个也都是如假包换的变量
-
面向对象和数据库是struct的思想发展
7)结构体指针
struct point
{
int x;
int y;
};
struct point pt; /*定义结构体变量*/
struct point *ppt; /*定义结构体指针*/
ppt = &pt;
怎样通过pt访问pt的成员?
pt.x = 0; /*成员运算符*/
怎样通过ppt访问pt的成员?
(*ppt).x = 0;
ppt->x = 0; /*指向运算符*/
第二种更常用
8)结构体数组
struct STUDENT
{
int studentID;
char studentName[10];
char studentSex[4];
struct date timeOfEnter;
int scoreComputer;
int scoreEnglish;
int scoreMath;
int scoreMusic;
};
struct STUDENT stu[30];
//初始化
struct STUDENT stu[30] =
{
{1,"令狐冲","男",{2016,12,20},90,83,72,82},
{2,"林平之","男",{2016,07,06},78,92,88,78},
{3,"岳灵珊","女",{2016,07,06},89,72,98,66},
{4,"任盈盈","女",{2016,07,06},78,95,87,90}
};
9)结构体数组指针
struct STUDENT *pt;
pt = stu;
10)结构体与函数
◼ 向函数传递结构体的单个成员
单向值传递,函数内对结构内容的修改不影响原结构
◼ 向函数传递结构体的完整结构
单向值传递,函数内对结构内容的修改不影响原结构,开销大
◼ 向函数传递结构体的首地址
用结构体数组或者结构体指针做函数参数
除提高效率外,还可以修改结构体指针所指向的结构体的内容
11)结构体与位字段
◼ 位字段是C语言中一种存储结构,不同于一般结构体的是它在定义成员的时候需要指定成员所占的位数。
◼ 它主要用于一些使用空间很宝贵的程序设计中,如嵌入式程序设计。
struct bit_field
{
unsigned int a:5;
unsigned int b:3;
unsigned int c:20;
unsigned int d:4;
};
//在如上定义中,bit_field结构体只占用一个word的空间,即4个字节。
int main()
{
struct bit_field x;
x.a = 12;
x.b = 7;
x.c = 1024;
x.d = 13;
printf("%d\n",x.a);
printf("%d\n",sizeof (struct bit_field));
return 0;
}
//其中成员a占用5位,成员b占用3位,成员c占用20位,成员d占用4位。
//最好使用unsigned 类型//
例如:设置bits的5-9位为value
//位操作
unsigned int bits;
bits &= ~(0x1f << 5) /* 将5-9位设置为0 */
bits |= value << 5 /* 设置5-9位的值 */
//位字段
struct
{
unsigned int a : 5;
unsigned int b : 5;
unsigned int c : 22;
} bits;
bits.b = value;
12)union
在C语言中,union
是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。但是,在任何给定的时间,union
只能保存其成员中的一个值,因为所有的成员共享同一块内存空间。
union ss
{
int a;
char b[8];
};
共同体的特点:
◼ 同一内存单元在每一瞬时只能存放其中一种类型的成员;并非同时都起作用
◼ 起作用的成员是最后一次存放的成员
◼ 不能作为函数参数
共同体的应用:
struct person
{
char name[20];
char sex;
int age;
union
{
int single;
struct
{
char spouseName[20];
int child;
}married;
struct date divorcedDay;
}marital;
int marryFlag;
};
13)枚举类型enum
enum
(枚举)类型是一种用户定义的类型,它允许程序员为整数常量指定更易读的名字。
enum spectrum {red, orange, yellow, green, blue, violet};
enum spectrum color;//枚举类型声明代表常量的符号名称。
enum的默认值
enum kids{nippy, slats, skippy, nina, liz};
enum的指定值
enum levels {low = 100, medium = 500, high = 2000};
enum的用法
-
作为switch的标签