定义了一个 "数据类型" --- 用户自定义的数据类型
struct 结构体类型名
{
数据成员列表;
};
eg:
描述学生这种类型:
struct student
{
char name[20]; //成员变量 各个成员变量之间 用分号隔开
unsigned char age;//0~255 -128~127
float score;
//...
}; //注意: 最后这个分号(;) 表示 --- 结构体类型定义完成
struct student //学生数据类型 struct student s; //s这种类型的一个变量
eg:定义一位名叫张三的同学的信息
struct student s = {"zhangsan",23,134};
初始化:struct student s = {"zhangsan",23,134};
结构体变量赋值:结构体不能整体赋值
struct student s;
s = {"tom",20,89.5,100}; // error
struct student s1 = {"tom",20,89.5,100};
struct student s2;
s2 = s1; //true
类型一: 结构体变量名.成员变量名 // . 是结构体成员运算符 类型二: -> //用于结构体类型的指针变量的
结构体类型的变量.成员变量名
结构体类型的指针->成员变量名
eg: s.name //可访问到结构体中的name成员
struct student *s = &s1;
s->name
练习:
老师
struct
名字
工号
工资
练习:
定义学生类型的结构体
封装函数,从键盘输入3个学生的信息
封装函数,将三个学生的信息打印出来
练习:
找出 成绩最高的学生 ,输出它的信息
//函数
找最大值
//
练习:
排序
qsort
name sno score
分别
按照 名字,学号,分数排序输出
0.(有冲突1,2服从3,4)
1.在32位的平台上,起始默认都是按4字节对齐(地址能被4整除)的。 //64位的平台 默认是8字节
2.对于成员变量,各自在自己的自然边界上对齐。(地址能被自己自身所拥有的类型大小整除)
自然边界对齐
int -- 4字节 --- 能被4整除的地址编号上
short -- 2字节 --- 能被2整除的地址编号上
char -- 1字节 --- 能被1整除的地址编号上
//整个结构体的对齐
3.如果成员变量中有比4字节大。
此时 整个结构体按照4字节对齐。 //32位的平台
4.如果 成员变量中没有有比4字节大。
此时 整个结构体按照最大的那个成员对齐。
注意:
1.结构体类型,可以定义在函数里面,但是此时作用域就被限定在改函数中
2.结构体的定义的形式
//形式1 先定义类型,后定义变量
struct stu
{
...
};
struct stu s;
//形式2 定义类型的同时定义变量
struct stu
{
...
}s1,s2,*s3,s4[10];
struct stu s;
//形式3 省略了类型名 --如果只用一次,可以这样写
struct
{
...
}s1,s2,*s3,s4[10];
有时需要使几种不同类型的变址存放到同一段内存单元中。例如,可把一个整型变
量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中
union 共用体名
{
成员列表; //各个变量
}; //表示定义一个共用体类型
union emo s1; //s1就是共用体变量
a、共用体的初始化 --- 只能给一个值,默认是给到第一个成员变量的
union emo
{
int a;
char b;
};
int main()
{
union emo s = {1};
return 0;
}
b、共用体用的数据最终存储的 --- 应该是最后一次给到的值
但是只能影响到自己数据类型对应的空间中的数据
union emo
{
int a;
char b;
};
int main()
{
union emo s1 = {'a'};
s1.a = 0x12345678;
s1.b = 0x11;
printf("%#x\n",s1.a); //0x12345611 ,验证了存储方式,也验证了是大端存储还是小端存储,证明是小端存储
printf("%#x\n",s1.b); //0x11
return 0;
}
c、共用体的大小 --- 是成员变量中最大的那个成员的大小
d、小技巧,可以用共用体判断大小端
union emo
{
int a;
char b;
};
int main()
{
union emo s1 = {1};
s1.a = 1; //1在内存中的存储格式是0000 0000 0000 0001
printf("%d",s1.b); //1 证明是小端存储
return 0;
}
e、实际用途
a.节省空间
b.进行数据转换
192.168.1.169 //ip本质是个 32位的数值
f、共用体加结构体
struct stu
{
char name[20];
int sno;
float score;
}
struct teacher
{
char name[20];
int Tno;
float salary;
}
struct member
{
char name[20];
int no;
union
{
float score;
float salary;
}d;
}
g、共用体类型可以是函数参数,也可以是函数返回值类型
共用体,结构体类型定义出来之后,
a.定义变量
b.定义数组
c.定义指针
d.做函数参数,返回值类型
如果一个变量只有几种可能的值,则可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
emum
enum 枚举类型名
{
sun, //名字 --- 代表一个整形值,不做定义的时候默认是从0依次向后定义 --- 符号常量
mon,
tue,
wed,
thu,
fri,
sat
};
练习:
无人机的状态
0 --flying
1 --stop
2 --holding
从键盘输入0~2 打印无人机的状态
#include
enum plan
{
flaying,
// flaying = 1; //这里不是赋值,是指定他是什么整形常量,不写默认为0而后后边的依次按顺序默认定义,写了就按照此时定义好的值依次按顺序定义
stop,
holding
};
int main()
{
// falying = 1; //error flaying是整形常量,不能赋值
int i = 0;
scanf("%d",&i);
switch(i)
{
case flaying:
// case 0: //or
printf("自由飞行\n");
break;
case stop:
// case 1: //or
printf("降落\n");
break;
case holding:
// case 2: //or
printf("停滞\n");
break;
default:
printf("重新输入0-2以内的数字\n");
}
return 0;
}
1.枚举 提高了代码可读性
2.枚举 本质上是int类型
枚举 与 整型 类型兼容
3.不足
因为枚举类型 --- 本质上是个整型类型,
所以枚举类型的变量的值,并不能真正限定在指定的哪些值范围中
4.枚举类型
可以做函数 形参 和 返回值
定义数组也可以,本质上就是整型数据
数组:
int a[10] = {1,2,3,4,5,6,7,8,9,10}; //连续性,有序性,单一性
数组的优点:随机访问 方便
数组的缺点:增加数据 不方便
删除数据 不方便
链式的数据表
链表的优点:增加,删除数据很方便
链表的缺点:找数据不大方便
存放链式数据的结构:节点
节点的形式:[数据|另外一个节点指针] ---- [数据域|指针域]
节点举例:
struct Node
{
//数据域
struct stu s;
//指针域
struct Node *p; //指针类型
};
有头链表 -- 可以更方便的处理链表
无头链表
空链表的特点:
只有头节点
并且头节点的指针域为NULL //相当于是尾节点
strcut Node head = {0,NULL}; //创建了一个头节点
struct Node *p = &head; //取头结点的地址
插入: 创建一个新的节点,将节点链接起来
方式一:尾插
思路:
s1.创建一个新的节点
struct Node *pNew = malloc(sizeof(struct Node));
//放在了堆区
s2.找到尾节点
struct Node *p = &head; //此时p在头节点
while( p->next != NULL )
{
p = p->next; //让p指向下一个节点
}
s3.链接到尾节点后面
p->next = pNew;
pNew->next = NULL; //尾节点
代码:
void pushBack(struct Node *head)
{
s1.创建一个新的节点
struct Node *pNew = malloc(sizeof(struct Node));
//放在了堆区
//
s2.找到尾节点
struct Node *p = head; //此时p在头节点
while( p->next != NULL )
{
p = p->next; //让p指向下一个节点
}
s3.链接到尾节点后面
p->next = pNew;
pNew->next = NULL; //尾节点
}
方式二:头插
void pushFront(struc Node *head,int data)
{
//1.创建新节点
pNew
//2.链接
pNew->next = p->next;
p->next = pNew;
}
int length(struct Node *head)
{
//统计有效节点的个数
}
方式一:头删
void popFront(struct Node *head)
{
//1.p指针变量 指向首节点
//2.断开链表
head->next = p->next;
//3.释放p所在的节点
free(p);
}
方式二:尾删
void void popBack(struct Node *head)
{
//1.p定位到尾节点的前一个节点
while (p->next->next != NULL)
{
p = p->next;
}
//2.释放 p->next
//3.p所在节点成为了新的尾节点
p->next = NULL;
}
操作:
1.创建空链表
2.头插
3.尾插
4.链表遍历
5.链表的长度