结构体共用体补充
一.结构体
1.typedef和结构体
- 定义一个别名
typedef struct studnet
{
char name[10];
int age;
char sex;
}stu; //把struct student 起别名为stu struct studnet===》stu
stu a;
- 定义多个别名
typedef struct studnet
{
char name[10];
int age;
char sex;
} stu, *stu_p, stu_arr[3];
// stu: 是结构体类型 等价 struct student
// stu_p: 是结构体指针类型 等价struct studnet *
// stu_arr:是结构体数组的类型 等价struct studnet arr[3];
2.结构体嵌套
- 结构体嵌套普通结构体
//定义人的信息:姓名、生日(年月日),年龄
typedef struct Date
{
int year;
int moth;
int day;
}date;
typedef struct person
{
char name[10];
//
date birthday;
int age;
}person;//struct person===》person
person a={"张三",{2000,12,30},23};
printf("姓名:%s",a.name);
printf("%d年%d月%d日\n",a.birthday.year,a.birthday.month,a.birthday.day);
//注意a是person的变量名,只能调用person中的成员变量
printf("年龄:%d",a.age);
- 结构嵌套结构体数组
// 定义人的信息:姓名,年龄,车(可以有多个)
typedef struct // 当使用typedef是结构体名可以省略不写,无名结构体
{
char name[20];
float price;
} car;
typedef struct
{
char name[10];
int age;
car car_arr[2];
} person;
int main(int argc, const char *argv[])
{
person a = {"张三", 45, {"大众", 120000, "五菱宏光", 5000}};
printf("姓名:%s\n", a.name);
printf("年龄:%d\n", a.age);
printf("车辆信息是\n");
for (int i = 0; i < 2; i++)
{
printf("%s\t%.2f\n", a.car_arr[i].name, a.car_arr[i].price);
}
return 0;
}
3. 结构体大小
- 结构体变量的地址表示结构体第一个成员的地址
typedef struct
{
char name[10];
int age;
}stu;
stu a;
&a = &a.name
- 结构体地址是连续
- 结构体的大小是每个成员字节大小的总和
- 满足字节对齐原则:
- 结构体的首地址是最宽成员的整数倍,否则使用空字节填充
- 结构体的总字节数,是最宽成员字节的整除倍,否则使用空字节填充
- 结构体每个成员的偏移量,是该成员字节大小的整数倍,否则使用空字节填充
typedef struct
{
char name[10];
int a;
int b;
int age;
}stu;
typedef struct
{
int a;
float b;
}A;
typedef struct{
double a;
char b;
int c;
char *p;
char d;
double k;
}C;
typedef struct{
int a;
char b;
float *p;
}B;
typedef struct{
char a;//0x00
B k;//0x01
}D;
int main(int argc, const char *argv[])
{
stu a;//a表示变量名
printf("&a=%p \n&a.name=%p \n&a.age=%p\n",&a,a.name,&a.age);
printf("&a.a=%p\n&a.b=%p\n",&a.a,&a.b);
printf("A=%ld\n",sizeof(A));
printf("stu=%ld\n",sizeof(stu));
B b;
printf("&b.a=%p\n&b.b=%p\n&b.p=%p\n",&b.a,&b.b,&b.p);
printf("B=%ld\n",sizeof(B));
C c;
printf("&c.a=%p\n&c.b=%p\n&c.c=%p\n&c.p=%p\n&c.d=%p\n&c.k=%p\n",&c.a,&c.b,&c.c,&c.p,&c.d,&c.k);
printf("C=%ld\n",sizeof(C));
D d;
printf("&d.a=%p\n&d.k.a=%p\n&d.k.b=%p\n&d.k.p=%p\n",&d.a,&d.k.a,&d.k.b,&d.k.p);
printf("D=%ld\n",sizeof(D));
return 0;
}
二.共用体union
共用体:公用同一块空间存储的构造类型
1. 定义格式
格式 :
union 公用体名
{
数据类型 成员1;
数据类型 成员2;
....
数据类型 成员n;
};
- union:共用体关键字
- 共用体名:满足命名规范,可有可无,当没有共用体名时,称为无名共用体
- {}: 必须存在
- ; 必须存在
- 成员的数据类型:基本类型、构造类型、空类型、指针类型
- 成员:成员的个数任意
- 共用体名位置任意,但是建议全局
- 共用体名描述,计算机不分配空间,当存在共用体名变量时,计算机分配空间
2. 共用体引用
普通共用体使用 “.” 调用
3. 共用体初始化
注意:共用体公用同一块存储空间,共用体的大小是最宽成员的字节大小
union A
{
int a;
char b;
double c;
} a = {100, 20}; // 总字节字节是8字节
union A
{
int a;
char b;
double c;
} a = {100}; // 默认是初始化的是第一个成员
union A b = {.b = 'a'};
int main(int argc, const char *argv[])
{
printf("&a=%p\na.a=%p\na.b=%p\na.c=%p\n", &a, &a.a, &a.b, &a.c);
printf("a.b=%c\n", a.b);
printf("b.b=%c\n", b.b);
return 0;
}
4. 共用体和结构体结合
- 在struct里面
typedef struct
{
int a;
union
{
float b;
char c;
};
} A;
// A person = {100, .c = 'K'};
// person.a = 100;
// person.c = 'K';
- 在struct外面
union AA
{
float b;
char c;
};
typedef struct
{
int a;
union AA s;
} A;
// A person = {200, .s.c = 'A'}
作业
作业1:有若干个学校人员的信息,包括学生和教师。其中学生的数据包括:姓名、性别、职业s/S、分数。教师的数据包括:姓名、性别、职业t/T、职务。要求用同一个表格来处理以上数据。
1,定义函数在堆区申请空间n
struct B p= (struct B * )malloc(sizeof(struct B) n );
2,定义函数实现录入学校人员信息
3,定义函数输出学校人员信息
4,定义函数计算学生平均成绩
5,定义函数计算老师的个数
6,释放存储空间
main.c
#include "head.h"
int main()
{
int n;
printf("请输入人数:\t");
scanf("%d", &n);
personnel *per;
per = Create(n); // 申请空间
Input(per, n); // 输入信息
Output(per, n); // 输出信息
float average; // 平均成绩
int num; // 老师数目
average = average_scores(per, n); // 平均数目
num = techer_num(per, n); // 教师数目
printf("学生的平均分为%.2f\n", average);
printf("老师的个数为%d\n", num);
free_fun(per);
system("pause");
return 0;
}
1.c
#include "head.h"
personnel *Create(int n) // 申请空间
{
personnel *p = (personnel *)malloc(sizeof(personnel) * n);
if (p == NULL)
return NULL;
return p;
}
void Input(personnel *p, int n) // 定义函数实现录入学校人员信息
{
for (int i = 0; i < n; i++)
{
printf("请输入姓名:\t");
scanf("%s", (p + i)->name);
printf("请输入性别:\t");
scanf(" %c", &(p + i)->sex);
printf("请输入职业:\t");
scanf(" %c", &(p + i)->occupation);
if ((p + i)->occupation == 's' || (p + i)->occupation == 'S')
{
printf("请输入分数\t");
scanf("%f", (p + i)->score);
}
else if ((p + i)->occupation == 'T' || (p + i)->occupation == 't')
{
printf("请输入职务\t");
scanf("%s", (p + i)->post);
}
}
}
void Output(personnel *p, int n) // 定义函数,输出学校人员信息
{
printf("姓名\t性别\t职业\t分数/职务\n");
for (int i = 0; i < n; i++)
{
printf("%s\t%c\t%c\t", (p + i)->name, (p + i)->sex, (p + i)->occupation);
if ((p + i)->occupation == 's' || (p + i)->occupation == 'S')
{
printf("%f\n", (p + i)->score);
}
else if ((p + i)->occupation == 'T' || (p + i)->occupation == 't')
{
printf("%s\n", (p + i)->post);
}
}
}
float average_scores(personnel *p, int n) // 定义函数计算学生平均成绩
{
float sum = 0;
int count = 0;
for (int i = 0; i < n; i++)
{
if ((p + i)->occupation == 's' || (p + i)->occupation == 'S')
{
sum += (p + i)->score;
count++;
}
}
return sum / count;
}
int techer_num(personnel *p, int n) // 定义函数计算老师的个数
{
int count = 0;
for (int i = 0; i < n; i++)
{
if ((p + i)->occupation == 't' || (p + i)->occupation == 'T')
count++;
}
return count;
}
personnel *free_fun(personnel *p) // 释放空间;
{
if (p != NULL)
{
free(p);
p = NULL;
}
return p;
}
}
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char name[20]; // 姓名
char sex; // 性别
char occupation; // 职业
union
{
float score; // 分数
char post[10]; // 职务
};
} personnel;
personnel *Create(int n); // 定义函数在堆区申请空间n
void Input(personnel *p, int n); // 定义函数实现录入学校人员信息
void Output(personnel *p, int n); // 定义函数,输出学校人员信息
float average_scores(personnel *p, int n); // 定义函数计算学生平均成绩
int techer_num(personnel *p, int n); // 定义函数计算老师的个数
char *free_fun(personnel *p); // 释放空间;
#endif
作业2:在堆区申请5个连续的存储空间,实现车辆信息的输入(品牌,颜色,价格)
1>调用函数在堆区申请空间
2>调用函数实现输入
3>调用函数对价格排序
思路:和正常的冒泡是一样的
注意点:
1>if(条件) 条件是价格的比较 (p+j)->price (p+j+1)->price
2> 交换的是整个车的信息
例如: (p+j)表示整个车的地址
(p+j)表示整个车的信息
交换的是(p+j) 和*(p+j+1) 对应的整体信息
3> 注意中间变量t的类型,应该是结构体类型
4>调用函数输出
5>释放堆区空间
main.c
#include "head.h"
int main()
{
CAR *car;
car = Create(5); // 申请堆区空间
Input(car, 5); // 输入数据
bubbling(car, 5); // 冒泡排序
Output(car, 5); // 输出排序后的结果
free_fun(car); // 释放空间
system("pause");
return 0;
}
1.c
#include "head.h"
CAR *Create(int n)
{
CAR *p = (CAR *)malloc(sizeof(CAR) * n);
if (p == NULL)
return NULL;
return p;
}
void Input(CAR *p, int n) // 实现输入
{
for (int i = 0; i < n; i++)
{
printf("请输入第%d辆车信息\n", i + 1);
printf("品牌\t");
scanf("%s", p[i].brand);
printf("颜色\t");
scanf("%s", p[i].colour);
printf("价格\t");
scanf("%d", &p[i].price);
}
}
void bubbling(CAR *p, int n) // 实现冒泡排序
{
for (int i = 0; i < n - 1; i++)
{
int count = 0;
CAR t;
for (int j = 0; j < n - i - 1; j++)
{
if ((p + j)->price > (p + j + 1)->price)
{
t = *(p + j); // 此处为交换值,整体交换结构体数据
*(p + j) = *(p + j + 1);
*(p + j + 1) = t;
count++;
}
}
if (count == 0)
break;
}
}
void Output(CAR *p, int n) // 输出结果
{
printf("排序后的结果为\n");
printf("品牌\t颜色\t价格\n");
for (int i = 0; i < n; i++)
{
printf("%s\t%s\t%d\n", (p + i)->brand, (p + i)->colour, (p + i)->price);
}
}
CAR *free_fun(CAR *p) // 释放空间
{
if (p != NULL)
{
free(p);
p = NULL;
}
return p;
}
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char brand[20];
char colour[20];
int price;
} CAR;
CAR *Create(int n); // 申请堆区空间
void Input(CAR *P, int n); // 实现输入
void bubbling(CAR *p, int n); // 实现冒泡排序
void Output(CAR *p, int n); // 输出结果
CAR *free_fun(CAR *p); // 释放空间
#endif