9.18 数据结构

一、知识梳理与总结

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 中默认的值为 8
Linux 中没有默认对齐数,对齐数就是成员自身的大小
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;
}

 运行结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值