共用体、枚举介绍
1.1共用体
共用体是一个特殊的结构体,使用关键字“union”来表示一个共用体。共用体中的数据成员共用一个内存空间,成员变量的最新赋值会把之前的数据覆盖掉。共用体变量在存储器中占用的存储空间就是共用体最大成员变量占用的空间,并且是最大成员变量的数据类型所占空间的整数倍。使用“union 共用体类型{成员1,成员2,成员3…. 成员n};”的格式定义一个共用体
#include <stdio.h> #include <string.h> //对于共用体 占用一块内存空间 union Mem{ char data; short data0; int data1; float data2; double data3; }; int main() { printf("%d\n",sizeof(union Mem)); return 0; } |
#include <stdio.h> #include <string.h> union shortToTwoByte{ unsigned short ShortData; //短整型 unsigned char ByteBuff[2]; //字节 }; int main() { /***需要将短整型数据分割为2字节数据******/ //原始方法 ---举例: unsigned short data =0x1234; unsigned char dataH = data>>8;//高八位 unsigned char dataL = (unsigned char)data; printf("%x %x\n",dataH,dataL); //12 34 //现在方法 ---举例: printf("%d\n",sizeof(union shortToTwoByte));//2 union shortToTwoByte a; a.ShortData = 0x1234; printf("%x %x\n",a.ByteBuff[1],a.ByteBuff[0]); //12 34 return 0; } |
面试会有一个面试题:测量大小端 该设备为大端存储还是小端存储? 方法: 小端字节序存储:低字节放在低地址处;0x12 34 56 大端字节序存储:低字节放在高地址处; PC机或者单片机为小端存储 #include <stdio.h> #include <string.h> union shortToTwoByte{ unsigned short ShortData; //短整型 unsigned char ByteBuff[2]; //字节 }; int main() { //现在方法 ---举例: printf("%d\n",sizeof(union shortToTwoByte));//2 union shortToTwoByte a; a.ShortData = 0x1234; printf("%p:%x\n",&a.ByteBuff[1],a.ByteBuff[1]); printf("%p:%x\n",&a.ByteBuff[0],a.ByteBuff[0]); return 0; } |
共用体用途还有哪些呢? #include <stdio.h> #include <string.h> //提高 typedef struct { int id; int functionID; int data1; int data2; int data3; }Info; //有利于将整型数据分割为一个个字节 union InfoToByte{ Info info; char buff[20]; }; int main() { union InfoToByte a; a.info.id =10; a.info.functionID = 3; a.info.data1 =1; a.info.data2 =2; a.info.data3 =3; //单片机设备或者大部分设备都是字节发送 运算符进行转字节 a.buff// return 0; } |
1.2 共用体类型的数据特点
同一内存段可以用来存放几种不同类型的成员,但是每次只能存放其中一种,而不能同时存放所有的类型。也就是说在共用体中,只有一个成员起作用,其他成员不起作用
共用体变量中起作用的成员是最后一次存放的成员。在存入一个新成员后,原有的成员就失去作用
共用体变量的地址和它的各成员的地址是一样的
不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。
#include <stdio.h> #include <string.h> //提高 typedef struct { int id; int functionID; int data1; int data2; int data3; }Info; //有利于将整型数据分割为一个个字节 union InfoToByte{ Info info; char buff[20]; }; int main() { union InfoToByte b; b =10; × 不能这样赋值 不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。 return 0; } |
不能将所有成员进行赋值处理: #include <stdio.h> #include <string.h> union Data{ int data1; short data2; float data3; }; int main() { //union Data b={1,2,3.0}; //这种是错误的 C89中直接报错误 union Data b={1}; printf("%d\n",b.data2); return 0; } |
1.3枚举
枚举类型实际上是一组整型常量,使用关键字“enum”来表示一个枚举类型。使用“enum 枚举类型名{枚举常量1,枚举常量2,枚举常量3,….,枚举常量n};”的格式定义一个枚举变量。枚举变量默认从0开始,后面一个是前面的成员变量加1。
例:
#include <stdio.h> #include <string.h> enum TIMBUFF{TIM0=0,TIM1,TIM2,TIM3,TIM4}; //原来 void oldStart(int num) { switch(num) { case 0: printf("定时器0\n");break; case 1: printf("定时器1\n");break; case 2: printf("定时器2\n");break; } } //代码可读性增强 void newStart(enum TIMBUFF num) { switch(num) { case TIM0: printf("定时器0\n");break; case TIM1: printf("定时器1\n");break; case TIM2: printf("定时器2\n");break; } } int main() { oldStart(1); //底层源码才能获知1 2 意思 newStart(TIM1); return 0; } |
#include <stdio.h> #include <string.h> enum TIMBUFF{TIM0=10,TIM1=99,TIM2,TIM3,TIM4}; //原来 void oldStart(int num) { switch(num) { case 0: printf("定时器0\n");break; case 1: printf("定时器1\n");break; case 2: printf("定时器2\n");break; } } //代码可读性增强 void newStart(enum TIMBUFF num) { switch(num) { case TIM0: printf("定时器0\n");break; case TIM1: printf("定时器1\n");break; case TIM2: printf("定时器2\n");break; } } int main() { oldStart(1); //底层源码才能获知1 2 意思 newStart(TIM1); printf("TIM2:%d\n",TIM2); return 0; } |
1.4前期知识疑惑
1.函数的栈区、堆区、文本常量区、全局变量区、代码段还是存在疑惑?
栈区:函数内部定义变量(除static变量)、形参
2.为什么用结构体,不用结构体可以吗?还有结构体变量必须全局?
有三个变量xiaoming xiaohua xiaoxiao;描述他们的体重身高年龄名字
原有方式:
Int main() { //体重 Int xiaomingW, xiaohuaW,xiaoxiaoW; //身高 Int xiaomingH, xiaohuaH,xiaoxiaoH; //年龄 Int xiaomingAge, xiaohuaAge,xiaoxiaoAge; //名字 Char xiaomingName[30]={0}; Char xiaohuaName[30]={0}; Char xiaoxiaoName[30]={0}; } Void fun(int a,intb,intc,char*name)//需要几个参数4参数 需要在内存开辟空间 复制4份 {
} |
原有方式描述一个”对象”代码可读性比较差,传参烦多;效率不高(4份);
现有结构体方式:
Struct stu{ Int W; Int H; Int Age; Char Name[30]; }; Int main() { Struct stu xiaoming; Xiaoming.W =100; Xiaoming.H = 200; Xiaoming.Age =18; } Void fun(Struct stu a)//需要几个参数1参数 需要在内存开辟空间 复制1份 结构体为块操作对齐 会导致结构体变量值复制效率比较高 {
} |
现有方式描述一个”对象”代码可读性比较高,传参少;效率高(块对齐);
3.结构体对齐;需要思维改变
符合三条标准:
①数据对齐原则---内存按结构体成员的先后顺序排列,当排到该成员时,其前面已开辟的空间字节数必须是该成员类型所占字节数的整数倍,如果不够则补齐,依次向后类推。
②整体空间是占用空间最大的成员类型所占字节数的整数倍;
③系统对齐方式和结构体自身默认对齐方式,俩者取最小的。
Struct stu{char a; char b;};结构体自身默认对齐大小为1字节(最大成员char),系统32位默认为4字节,采用两者最小char1字节;
Struct stu{char a; char b;double c};结构体自身默认对齐大小为8字节,系统位数为32位默认采用4字节,采用4字节 4字节对齐; 把double进行切割为4字节的;
Struct stu{char a[10]; char b; };结构体自身默认对齐大小为1字节,系统位数为32位默认采用4字节,采用1字节 ;
4.共用体用途?
概念:共用体内部所有成员共用一块内存空间,其空间大小为最大成员空间大小;
用途1:节省内存;
2.可以实现类型转换 int 转换为字节
强制类型转换:(unsigned char)0x12345678将4字节数据进行强制转换为8位数据,只截取最低八位数据;
5.指针存放地址问题;
指针:存放的是地址 存放不合理即出现段错误;
线上/线下 本周六 本周天合理安排时间
链表:指针与结构体结构;
//printf 标准输出函数 需要加相关头文件stdio.h //printf输出标准:(由于内置缓存区 未达到条件是在缓存区中暂留,达到输出条件读取缓存区->到屏幕) //1.缓存区已满,标准输出会将缓存区中的数据进行输出; /******************************************* for(int i = 0;i <500;i++) printf("%03d",i); 通过以上实例得到printf内置缓存区1024字节 ********************************************/ //2.标准输出遇到\n即认为数据读取完成 /******************************************* printf("1234\n56789"); printf("\n"); ********************************************/ |
学生管理系统:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> //首先步骤: //1.确定使用结构体类型(学生); struct stu{ unsigned int ID; char Name[30]; int Age; unsigned int Sex; float chengji; }; //2.目录菜单 //3.选择类型 增加 删除 修改 查询 退出 //函数声明: enum Option{ADDSTUDENT=1,UPDATESTUDENT,DELETESTUDENT,SELECTSTUDENT,EXITSTUDENT}; void printfMenuInfo(void); int updateStudentInfo(struct stu * studentInfo); /******************************************** 函数功能:打印菜单信息 函数名称:void printfMenuInfo(void) 函数参数:无 返 回 值:无 *********************************************/ void printfMenuInfo(void) { printf("********欢迎使用信盈达学生管理系统*********\n"); printf("*************1.添加学生信息****************\n"); printf("*************2.修改学生信息****************\n"); printf("*************3.删除学生信息****************\n"); printf("*************4.查询学生信息****************\n"); printf("***********5.退出学生管理系统**************\n"); printf("*******************************************\n"); printf("请输入1-5的数字:\n"); } /******************************************** 函数功能:添加学生信息 函数名称:int addStudentInfo(struct stu & studentInfo) 函数参数:学生结构体数组 返 回 值:1为成功 0失败 *********************************************/ int addStudentInfo(struct stu * studentInfo) { struct stu tempStudentInfo; printf("请输入学号:\n"); scanf("%d",&tempStudentInfo.ID);//输入的学号信息//&studentInfo[*studentCount].ID getchar(); //吸收回车 printf("请输入名字:\n"); gets(tempStudentInfo.Name); //请输入名字 printf("请输入年龄:\n"); scanf("%d",&tempStudentInfo.Age);//输入的年龄信息 printf("请输入性别:\n"); scanf("%d",&tempStudentInfo.Sex);//输入的性别 printf("请输入成绩:\n"); scanf("%f",&tempStudentInfo.chengji);//输入的性别 printf("%d-%s-%d-%s-%f\n",tempStudentInfo.ID,tempStudentInfo.Name ,tempStudentInfo.Age,(tempStudentInfo.Sex?"男":"女"),tempStudentInfo.chengji); //遍历学生数组中学号为0 for(int i =0; i <100; i++) { if(studentInfo[i].ID==0) { studentInfo[i] = tempStudentInfo; return 1; } if(i == 99 &&studentInfo[99].ID!=tempStudentInfo.ID)return 0; } } /******************************************** 函数功能:修改学生信息 函数名称:int updateStudentInfo(struct stu * studentInfo) 函数参数: 返 回 值: *********************************************/ int updateStudentInfo(struct stu * studentInfo) { struct stu tempStudentInfo; printf("请输入学号:\n"); scanf("%d",&tempStudentInfo.ID);//输入的学号信息//&studentInfo[*studentCount].ID getchar(); //吸收回车 printf("请输入名字:\n"); gets(tempStudentInfo.Name); //请输入名字 printf("请输入年龄:\n"); scanf("%d",&tempStudentInfo.Age);//输入的年龄信息 printf("请输入性别:\n"); scanf("%d",&tempStudentInfo.Sex);//输入的性别 printf("请输入成绩:\n"); scanf("%f",&tempStudentInfo.chengji);//输入的性别 //遍历学生数组中学号为0 for(int i =0; i <100; i++) { if(studentInfo[i].ID==tempStudentInfo.ID) { studentInfo[i] = tempStudentInfo; return 1; } if(i == 99 &&studentInfo[99].ID!=tempStudentInfo.ID)return 0; } } /******************************************** 函数功能:删除学生信息 函数名称:int deleteStudentInfo(struct stu * studentInfo) 函数参数: 返 回 值: *********************************************/ int deleteStudentInfo(struct stu * studentInfo) { int delete; printf("请输入学号:\n"); scanf("%d",&delete);//输入的学号信息 //遍历学生数组中学号为0 for(int i =0; i <100; i++) { if(studentInfo[i].ID==delete) { studentInfo[i].ID = 0; return 1; } if(i == 100)return 0; } } //查询函数 /******************************************** 函数功能:查询学生信息 函数名称:int selectStudentInfo(struct stu * studentInfo) 函数参数: 返 回 值: *********************************************/ int selectStudentInfo(struct stu * studentInfo) { int count = 0; //遍历学生数组中学号为0 for(int i =0; i <100; i++) { if(studentInfo[i].ID !=0) { count++; printf("%d-%s-%d-%s-%f\n",studentInfo[i].ID,studentInfo[i].Name ,studentInfo[i].Age,(studentInfo[i].Sex?"男":"女"),studentInfo[i].chengji); } } return count; } int main() { struct stu studentsBuff[100]={0}; int inputSelectOption=0; int (*studentFunction)(struct stu *) =NULL; //函数指针 while(1) { printfMenuInfo(); scanf("%d",&inputSelectOption); switch(inputSelectOption) { case ADDSTUDENT:studentFunction = addStudentInfo;break; case UPDATESTUDENT: studentFunction = updateStudentInfo;break; case DELETESTUDENT:studentFunction = deleteStudentInfo;break; case SELECTSTUDENT:studentFunction = selectStudentInfo;break; case EXITSTUDENT:return 1;break; } if(inputSelectOption >=1 && inputSelectOption<=5) studentFunction(studentsBuff); } return 0; } |
1.5递归疑问
1.递归结束条件为啥等于1;
递归条件/递归结束条件的由来: 1 2 3 4 5 6 7 8 9 …n
递归条件是针对整个序列(顺序)之间的关系:1和2关系 2和3什么关系 3和4什么关系 4和5什么关系….n-1 和n什么关系;
递归结束条件:求n 第一个元素为结束,不要再使用函数关系;截止
题目:1 1 2 3 5 8 …n
规律能够看出递归条件: f(n) = f(n-1)+f(n-2);
通过开始位置可以看出集合下标最小为0: n-2 >= 0 n-1 >=0 综上两个条件 n>=2
n<2需要得出f(0) f(1)数值 f(0)=1 f(1)=1;
1.6选择排序
1.6.1什么是选择排序
选择排序是一种简单直观的排序算法。
1.6.2工作原理
第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
无序数组{4,6,8,5,9}
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> int main() { int buff[5]={4,6,8,5,9}; int minIndex=0; int len = sizeof(buff)/sizeof(int); for(int i =0;i < len -1;i++) { minIndex =i; //设定最小值下标 for(int j = i+1;j<len; j++) //每趟遍历未排序的数组 { if(buff[j] < buff[minIndex]) { minIndex = j; } } if(minIndex != i) //遍历结束以后完成置换 { int temp = buff[i] ; buff[i] = buff[minIndex]; buff[minIndex] =temp; } } for(int i = 0; i<5;i++)printf("%d\t",buff[i]); return 0; } |