一、知识梳理与总结
1结构体
1.1结构体变量的定义
第一种: struct student{ int id; char name[20]; float score; }a; //学生变量a
第二种: struct student{ int id; char name[20]; float score; }; struct student a; //学生变量a
1.2结构体变量初始化和赋值
第一种:定义并初始化 struct student{ int id; char name[20]; float score; }a={1001,"孙文雅",90.5};
第二种:定义并初始化 struct student{ int id; char name[20]; float score; }; struct student a={1001,"孙文雅",90.5};
第三种:先定义、再赋值 struct studen a;
//错误赋值 a={1001,"孙文雅",90}; //数组 和 结构体都是构造类型,能再分解,不能整体进行赋值、输入、输出。
//错误赋值 id = 1001; //原因:因为id在复合语句{}中,只能在{}中识别,不能在{}外直接识别 a.id = 1001; strcpy(a.name , "孙文雅"); a.score = 90.5;
第四种:先定义、再输入 struct student a; scanf("%d %s %f" , &a.id , a.name , &a.score);
1.3结构体数组初始化和赋值
//如果指针指向一个连续的内存空间,指针可以直接当作数组名来使用
struct zhangzhen *m = malloc(sizeof(struct zhangzhen)*3);//动态内存分配
m[0].age = 20; strcpy(m[0].name,"细狗");
m[0].weight = 99.5;
printf("年龄:%d\t姓名:%s\t体重:%.2lf\n",m[0].age,m[0].name,m[0].weight);
m++;
m->age = 100; strcpy(m->name,"黑狗"); m->weight = 100;
printf("年龄:%d\t姓名:%s\t体重:%.2lf\n",m->age,m->name,m->weight);
m++; (*m).age = 200; strcpy((*m).name,"添狗"); (*m).weight = 100;
printf("年龄:%d\t姓名:%s\t体重:%.2lf\n",(*m).age,(*m).name,(*m).weight);
1.4 typedef和结构体的结合使用
typedef struct student{
int id;
char name[20];
float score;
}Stu , *Stu_Ptr , Stu_Arr[3];
Stu a = {1001,"HQYJ",90.5}; //定义学生变量a
Stu_ptr p = &a; //定义学生指针变量p,指向学生变量a
Stu_Arr arr = {{1001,"HQYJ",90.5},{1001,"HQYJ",90.5},{1001,"HQYJ",90.5}}
printf("%d %s %.2f\n" , a.id , a.name , a.score);
printf("%d %s %.2f\n" , p->id , p->name , p->score);
for(int i=0; i<3; i++){
printf("%d %s %.2f\n" , arr[i].id , arr[i].name, arr[i].score);
}
1.5结构体的嵌套
eg: 定义一个人的信息:姓名,性别,2车(品牌,单价)
struct CAR{ char brand[20]; float price; }; //定义 车 数据类型
struct people{ char name[20]; char sex; struct CAR car[2]; };
struct people a = {"张三" , 'M' , {{"奔驰",19.5},{"本田",23.75}}};
printf("姓名:%s 性别%c 车的品牌:%s 车的价格:%.2f万元" , a.name, a.sex, \ a.car[0].brand, a.car[0].price, a.car[1].brand, a.car[1].price)
1.6结构体内部写动态函数
1.在c语言中,结构体中不可以有函数
2.在结构体中实现一个功能,则需要借助于函数指针
eg:定义一个学生:姓名,年纪,分数,爱好(唱歌)
void song(){
printf("苍茫的天涯是我的爱……\n");
}
int fun(){
return 10086;
}
struct student{
char name[20];
int age;
float score;
void (*hobby)();
int (*p)();
};
struct student a={"张三",18,90.5,song};
printf("姓名:%s" , a.name);
printf("年龄:%d" , a.age);
printf("分数:%.2f" , a.score);
a.hobby();
printf("积分:%d" , a.p());
1.7结构体大小
1. 第一个成员在与结构体变量偏移量为 0 的地址处。2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值 。VS 中默认的值为 8Linux 中没有默认对齐数,对齐数就是成员自身的大小3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
1.8位段
1. 位段的成员可以是 int short或者是 char (属于整形家族)类型2. 位段的空间上是按照需要以 4 个字节( int )或者 1 个字节( char )的方式来开辟的。3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
typedef struct { int a:2; short b:1; char c:1; }m1;typedef struct { char a:3; short b:7; int c:10; }m2;
2.共用体/联合体
联合也是一种特殊的自定义类型这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
2.1共用体大小
联合的大小至少是最大成员的大小。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍union Un1{char c [ 5 ];int i ;};union Un2{short c [ 7 ];int i ;};// 下面输出的结果是什么?printf ( "%d\n" , sizeof ( union Un1 ));printf ( "%d\n" , sizeof ( union Un2 ));
2.2结构体与共用体嵌套
eg:有若干个学校人员的信息,包括学生和教师。 其中学生的数据包括:姓名、性别、职业s/S、分数。 教师的数据包括:姓名、性别、职业t/T、职务。 1.定义指针指向堆区内存 2.循环输入 3.计算老师的个数 4.计算学生的平均值 5.循环输出 6.释放堆区空间
#include <myhead.h>
#define MAX 3
typedef struct//定义结构体
{
char name[20];
char sex[5];
char job;//s/S学生 t/T老师
union{//联合体
float score;
char position[20];
};
}person,*PPerson;
int main(int argc, const char *argv[])
{
PPerson per = malloc(sizeof(person)*MAX);//定义3个老师和学生结构体变量
int i;
for(i = 0;i<MAX;i++)
{
printf("请输入姓名:");
//fgets(per[i].name,sizeof(per[i].name),stdin);
scanf("%s",per[i].name);
printf("请输入性别:");
scanf("%s",per[i].sex);
getchar();//吸收enter(回车)
printf("请输入职业:");
scanf("%c",&per[i].job);
if(per[i].job=='T'||per[i].job=='t')//判断老师还是学生
{
printf("请输入职位:");
scanf("%s",per[i].position);
}
else
{
printf("请输入分数:");
scanf("%f",&per[i].score);
}
printf("\n");
}
int count=0,stu=0;
float sum=0;
for(i = 0;i<MAX;i++)
{
if(per[i].job=='T'||per[i].job=='t')//判断老师还是学生
{
count++;//计算老师个数
printf("%s\t%s\t%c\t%s\n",per[i].name,per[i].sex,per[i].job,per[i].position);//输出老师
}
else
{
sum+=per[i].score;//学生成绩求和
stu++;//计算学生个数
printf("%s\t%s\t%c\t%.2f\n",per[i].name,per[i].sex,per[i].job,per[i].score);//输出学生
}
}
printf("老师%d个,学生评价分数:%.2f\n",count,sum/stu);
free(per);//释放内存
per=NULL;
return 0;
}
3.枚举
枚举顾名思义就是一一列举。把可能的取值一一列举。比如我们现实生活中:一周的星期一到星期日是有限的 7 天,可以一一列举。性别有:男、女、保密,也可以一一列举。月份有 12 个月,也可以一一列举
3.1eg
定义的 enum Day , enum Sex , enum Color 都是枚举类型。
{} 中的内容是枚举类型的可能取值,也叫 枚举常量 。这些可能取值都是有值的,默认从 0 开始,依次递增 1 ,当然在声明枚举类型的时候也可以赋初值enum Color // 颜色{RED = 1 ,GREEN = 2 ,BLUE = 4};enum Color // 颜色{RED = 1 ,GREEN = 2 ,BLUE = 4};enum Color clr = GREEN ; // 只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
3.2枚举与#define区别
我们可以使用 #define 定义常量,为什么非要使用枚举?枚举的优点:1. 增加代码的可读性和可维护性2. 和 #define 定义的标识符比较枚举有类型检查,更加严谨。3. 便于调试4. 使用方便,一次可以定义多个常量
二、练习
题目1:
定义结构体数组存储5个学生的信息:姓名,年龄,性别
定义函数实现输入,要求形参使用结构体指针接收
函数实现5个学生年龄排序(注意对年龄排序时,交换的是所有信息)
定义函数实现输出,要求形参使用结构体指针接收
代码:
#include <myhead.h>
#define MAX 5//宏定义学生个数
typedef struct{
char name[20];
int age;
char sex[5];
}Stu,*PStu;
void Stu_Input(PStu p);
void Stu_Output(PStu p);
void Stu_Sort_Age(PStu p);
int main(int argc, const char *argv[])
{
PStu p=(PStu)malloc(sizeof(Stu)*MAX);
//调用输入学生信息函数
Stu_Input(p);
//调用输出学生信息函数
Stu_Output(p);
//调用对学生年龄排序函数
Stu_Sort_Age(p);
//调用输出函数输出排序后的学生信息
Stu_Output(p);
//用完释放内存,指针置空
free(p);
p=NULL;
return 0;
}
void Stu_Input(PStu p){
int i;
for(i=0;i<MAX;i++){
printf("请输入第%d个学生姓名:",i+1);
scanf("%s",(p+i)->name);
printf("请输入第%d个学生年龄:",i+1);
scanf("%d",&(p+i)->age);
printf("请输入第%d个学生性别:",i+1);
scanf("%s",(p+i)->sex);
}
}
void Stu_Output(PStu p){
int i;
printf("学生信息为:\n");
for(i=0;i<MAX;i++){
printf("%s\t%d\t%s\n",(p+i)->name,
(p+i)->age,(p+i)->sex);
}
}
void Stu_Sort_Age(PStu p){
int i,j;
//采用冒泡排序方式排序年龄
for(i=0;i<MAX-1;i++){
for(j=0;j<MAX-1-i;j++){
if((p+j)->age>(p+j+1)->age){//交换的是整个结构体变量
Stu t=*(p+j);
*(p+j)=*(p+j+1);
*(p+j+1)=t;
}
}
}
}
运行结果:
题目2:定义小车结构体,存储名称、价钱、颜色。定义两个变量a,b,初始化,实现ab互换。
代码:
#include <myhead.h>
typedef struct{
char name[20];
float money;
char color[5];
}Car;
int main(int argc, const char *argv[])
{
Car a={"丰田",13.5,"白"};
Car b={"大众",23.4,"红"};
printf("交换前a信息:名称:%s,价钱:%.2f万元,颜色:%s\n\
b信息:名称:%s,价钱:%.2f万元,颜色:%s\n",
a.name,a.money,a.color,b.name,b.money,b.color);
Car temp=a;//进行ab互换
a=b;
b=temp;
printf("交换后a信息:名称:%s,价钱:%.2f万元,颜色:%s\n\
b信息:名称:%s,价钱:%.2f万元,颜色:%s\n",
a.name,a.money,a.color,b.name,b.money,b.color);
return 0;
}
运行结果: