lesson9 结构体
9. 复合类型(自定义类型)
9.1 结构体
定义结构体变量的方式:
- 先声明结构体类型再定义变量名
- 在声明类型的同时定义变量
- 直接定义结构体类型变量(无类型名)
#include <stdio.h>
struct student
{
char name[21];//10个有效地汉字,有一个\0
int age;
int score;
char addr[51];
};
int main()
{
////创造结构体变量
//struct student stu;
////stu.name = "张三"; 因为.name是数组的名,不可以被修改,所以不能直接进行赋值
//strcpy(stu.name, "张三");
//stu.age = 18;
//stu.score = 100;
////stu.addr = "安徽省合肥市蜀山区";
//strcpy(stu.addr, "安徽省合肥市蜀山区");
//快捷赋值方法:
struct student stu = { "张三",18,100,"安徽省合肥市蜀山区" };
//也可以在创建结构体的时候就直接在尾部赋值:stu = {"张三",18,100,"安徽省合肥市蜀山区"};
printf("姓名:%s\n", stu.name);
printf("年龄姓名:%d\n", stu.age);
printf("成绩:%d\n", stu.score);
printf("地址:%s\n", stu.addr);
return 0;
}
输出:
姓名:张三
年龄姓名:18
成绩:100
地址:安徽省合肥市蜀山区
通过输入方式给结构体赋值:
int main()
{
struct student stu;
scanf("%s%d%d%s", stu.name, &stu.age, &stu.score, stu.addr);//数组名本身就是地址,所以不用写&
printf("姓名:%s\n", stu.name);
printf("年龄姓名:%d\n", stu.age);
printf("成绩:%d\n", stu.score);
printf("地址:%s\n", stu.addr);
return 0;
}
Ctrl+H替换
struct student
{
//结构体成员需要偏移对齐,所以sizeof显示出来的占用内存空间大于实际的定义空间
char name[21];
int age;
char sex;
int score[3];
char addr[51];
};
int main()
{
struct student stu[3]=
{
{"大撒比",22,'m',88,99,0,"河北唐山"},
{"吴雅薇",18,'f',100,100,100,"安徽淮北"},
{"影流之主",30,'m',60,60,60,"艾欧尼亚"}
};
printf("结构体数组大小:%d\n", sizeof(stu));
printf("结构体数组元素大小:%d\n", sizeof(stu[0]));
printf("结构体数组大小:%d\n", sizeof(stu)/ sizeof(stu[0]));
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", stu[i].name);
printf("年龄姓名:%d\n", stu[i].age);
printf("性别:%d\n", stu[i].sex);
printf("成绩1:%d\n", stu[i].score[0]);
printf("成绩2:%d\n", stu[i].score[1]);
printf("成绩3:%d\n", stu[i].score[2]);
printf("地址:%s\n", stu[i].addr);
}
return 0;
}
输出:
结构体数组大小:288
结构体数组元素大小:96
结构体数组大小:3
姓名:大撒比
年龄姓名:22
性别:109
成绩1:88
成绩2:99
成绩3:0
地址:河北唐山
姓名:吴雅薇
年龄姓名:18
性别:102
成绩1:100
成绩2:100
成绩3:100
地址:安徽淮北
姓名:影流之主
年龄姓名:30
性别:109
成绩1:60
成绩2:60
成绩3:60
地址:艾欧尼亚
struct student 是一种数据类型,用冒泡排序的时候就可以直接定义temp类型为struct student temp,之后进行结构体的交换
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct student ss;
struct student
{
char name[21];
int age;
char sex;
int score[3];
char addr[51];
};
int main()
{
//struct student* p = (struct student*)malloc(sizeof(struct student) * 3);
ss* p = (ss*)malloc(sizeof(ss) * 3);
printf("结构体指针大小:%d\n", sizeof(ss*));
for (int i = 0; i < 3; i++)
{
scanf("%s%d,%c%d%d%d%s", p[i].name,&p[i].age,&p[i].sex,&p[i].score[0],
&p[i].score[1], &p[i].score[2],p[i].addr);
}
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", p[i].name);
printf("年龄:%d\n", p[i].age);
printf("性别:%d\n", p[i].sex);
printf("成绩1:%d\n", p[i].score[0]);
printf("成绩2:%d\n", p[i].score[1]);
printf("成绩3:%d\n", p[i].score[2]);
printf("地址:%s\n", p[i].addr);
}
return 0;
}
结构体指针大小:4
这是开辟堆空间对结构体进行存储
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct score
{
int cl;
int cpp;
int cs;
};
struct student
{
char name[21];
int age;
struct score ss;
char addr[51];
};
int main()
{
struct student stu = { "貂蝉",18,99,99,99,"徐州" };
printf("姓名:%s\n", stu.name);
printf("年龄:%d\n", stu.age);
printf("成绩1:%d\n", stu.ss.cl);
printf("成绩2:%d\n", stu.ss.cpp);
printf("成绩3:%d\n", stu.ss.cs);
printf("地址:%s\n", stu.addr);
return 0;
}
输出:
姓名:貂蝉
年龄:18
成绩1:99
成绩2:99
成绩3:99
地址:徐州
结构体内容有指针类型的:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//结构体成员为指针类型
struct student
{
char* name;
int age;
int* scores;
char* addr;
};
int main()
{
struct student stu;
stu.name = (char*)malloc(sizeof(char) * 21);
stu.scores = (int*)malloc(sizeof(int) * 3);
stu.addr = (char*)malloc(sizeof(char) * 51);
strcpy(stu.name, "孙尚香");
stu.age = 18;
stu.scores[0] = 88;
stu.scores[1] = 88;
stu.scores[2] = 88;
strcpy(stu.addr, "安徽合肥");
printf("姓名:%s\n", stu.name);
printf("年龄:%d\n", stu.age);
printf("成绩1:%d\n", stu.scores[0]);
printf("成绩2:%d\n", stu.scores[1]);
printf("成绩3:%d\n", stu.scores[2]);
printf("地址:%s\n", stu.addr);
free(stu.name);
free(stu.scores);
free(stu.addr);
return 0;
}
输出:
姓名:孙尚香
年龄:18
成绩1:88
成绩2:88
成绩3:88
地址:安徽合肥
struct stu
{
char name[21];
int age;
int scores[3];
char addr[51];
};
int main()
{
//结构体指针
struct stu ss = {"林冲",30,100,100,100,"汴京"};
struct stu* p = &ss;
//printf("%s\n", (*p).name);
//printf("%d\n", (*p).age);
printf("%s\n", p->name);
printf("%d\n", p->age);
printf("%d\n", p->scores[0]);
printf("%d\n", p->scores[1]);
printf("%d\n", p->scores[2]);
printf("%s\n", p->addr);
return 0;
}
输出:
林冲
30
100
100
100
汴京
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct student ss;
struct student
{
char* name;
int age;
int* scores;
char* addr;
};
int main()
{
ss* p = (ss*)malloc(sizeof(ss) * 3);
for (int i = 0; i < 3; i++)
{
//(p+i)->name
p[i].name = (char*)malloc(sizeof(char) * 21);
p[i].scores = (int*)malloc(sizeof(int) * 3);
p[i].addr = (char*)malloc(sizeof(char) * 51);
}
}

结构体和函数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct student ss;
struct student
{
char *name;
int age;
int scores;
char addr[51];
};
void fun01(ss stu)
{
strcpy(stu.name, "卢俊义");
printf("%s\n", stu.name);
}
int main()
{
struct student stu = { NULL,50,101,"水泊梁山" };
stu.name = (char*)malloc(sizeof(char) * 21);
strcpy(stu.name, "宋江");
fun01(stu);
printf("%s\n", stu.name);
return 0;
}
输出:卢俊义
卢俊义
可以通过地址传递改变ss的值
如果重新在fun01函数中开辟一块新的空间给形参赋值,就不会影响主函数中stu.name 的值了。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct student ss;
struct student
{
char *name;
int age;
int scores;
char addr[51];
};
void fun01(ss stu)
{
stu.name = (char*)malloc(21);
strcpy(stu.name, "卢俊义");
printf("%s\n", stu.name);
}
int main()
{
struct student stu = { NULL,50,101,"水泊梁山" };
stu.name = (char*)malloc(sizeof(char) * 21);
strcpy(stu.name, "宋江");
fun01(stu);
printf("%s\n", stu.name);
return 0;
}
输出:
卢俊义
宋江
通过地址传递改变main函数结构体值的方法2:
void fun02(ss * p)
{
strcpy(p->name, "公孙胜");
printf("%s\n", p->name);
}
int main()
{
//结构体作为指针函数
ss stu = { "武松",50,101,"水泊梁山" };
fun02(&stu);
printf("%s\n", stu.name);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct student ss;
struct student
{
char name[21];
int age;
int scores[3];
char addr[51];
};
//void fun01(ss stu)
//{
// stu.name = (char*)malloc(21);
// strcpy(stu.name, "卢俊义");
// printf("%s\n", stu.name);
//}
//int main0701()
//{
// struct student stu = { NULL,50,101,"水泊梁山" };
// stu.name = (char*)malloc(sizeof(char) * 21);
// strcpy(stu.name, "宋江");
// fun01(stu);
// printf("%s\n", stu.name);
//
// return 0;
//}
void fun02(ss * p)
{
strcpy(p->name, "公孙胜");
printf("%s\n", p->name);
}
int main0702()
{
//结构体作为指针函数
ss stu = { "武松",50,101,"水泊梁山" };
fun02(&stu);
printf("%s\n", stu.name);
return 0;
}
//数组作为函数参数退化为指针,丢失元素精度,需要传递元素个数 ,sizeof(stu)=4
void BubbleSort(ss * stu, int len)
{
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j < len-i-1; j++)
{
//if(stu[j].age>stu[j+1].age)
if ((stu+j)->age > (stu+j+1)->age)
{
ss temp = stu[j];//直接交换整相的ss
stu[j] = stu[j + 1];
stu[j + 1] = temp;
}
}
}
}
int main()
{
ss stu[3] =
{
{"鲁智深",30,33,33,33,"五台山"},
{"垂杨柳",45,13,31,32,"汴京"},
{"顾大嫂",35,32,53,73,"梁山"},
};
BubbleSort(stu, 3);
for (int i = 0; i < 3; i++)
{
printf("姓名:%s\n", stu[i].name);
printf("年龄姓名:%d\n", stu[i].age);
printf("成绩1:%d\n", stu[i].scores[0]);
printf("成绩2:%d\n", stu[i].scores[1]);
printf("成绩3:%d\n", stu[i].scores[2]);
printf("地址:%s\n", stu[i].addr);
}
}
输出:
姓名:鲁智深
年龄姓名:30
成绩1:33
成绩2:33
成绩3:33
地址:五台山
姓名:顾大嫂
年龄姓名:35
成绩1:32
成绩2:53
成绩3:73
地址:梁山
姓名:垂杨柳
年龄姓名:45
成绩1:13
成绩2:31
成绩3:32
地址:汴京
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct student ss;
struct student
{
char name[21];
int age;
int scores[3];
char addr[51];
};
int main()
{
ss stu1 = { "孙悟空",700,101,101,101,"花果山" };
ss stu2 = { "猪八戒",5000,10,11,1001,"高老庄" };
const ss* p = &stu1;//const 修饰结构体指针类型
//p = &stu2;//可以
//p->age = 888;//会报错,不可以修改
//(*p).age = 999;//也会报错,跟上一行一样的
return 0;
}
int main()
{
ss stu1 = { "孙悟空",700,101,101,101,"花果山" };
ss stu2 = { "猪八戒",5000,10,11,1001,"高老庄" };
ss* const p = &stu1;//const 修饰结构体指针变量
//p = &stu2;//err
//p->age = 888;
//p->name = "沙悟净";//err,p不可以修改
strcpy(p->name, "沙悟净");//可以修改
return 0;
}
9.2 共用体(联合体)
在c语言中使用较少,但是在其他语言中经常使用
联合union是一个能在同一个存储空间存储不同类型数据的类型;
联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体;
同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用;
共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖;
共用体变量的地址和它的各成员的地址都是同一地址。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
union Var
{
int a;
float b;
double c;
char d;
short e[6];
};
int main()
{
union Var var;
var.a = 100;
var.b = 3.14;
printf("%d\n", var.a);
printf("%f\n", var.b);//所有类型共用一个空间,当给b赋值的时候,a就成了乱码
printf("%d\n", sizeof(var));//var大小是其中最大的那个变量类型决定的,大小是最大的类型的倍数
printf("%p\n", &var);
printf("%p\n", &var.a);
printf("%p\n", &var.b);
printf("%p\n", &var.c);
return 0;
}
输出:
1078523331
3.140000
16
00FAFEC4
00FAFEC4
00FAFEC4
00FAFEC4

9.3 枚举
枚举:将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。
枚举类型定义:
enum 枚举名
{
枚举值表
};
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
enum Color
{
red,green,blue,pink,yellow,black,white
};
int main()
{
enum Color color;
int value;
scanf("%d", & value);
switch (value)
{
case red:
printf("红色");
break;
case green:
printf("绿色");
break;
case blue:
printf("蓝色");
break;
case pink:
printf("粉色");
break;
case yellow:
printf("黄色");
break;
case black:
printf("黑色");
break;
case white:
printf("白色");
break;
default:
break;
}
}
输入:3 输出:粉色
通过枚举可以进行流程控制:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
enum Type
{
run,attack,skill,dance=10,showUI,frozen=20,dizzy,death,moti
}type;
int main()
{
int value;
while (1)
{
scanf("%d", &value);
switch (value)
{
case run:
printf("正在移动\n");
//value=30;
break;
case attack:
printf("正在攻击\n");
break;
case skill:
printf("正在释放技能\n");
break;
case dance:
printf("正在跳舞\n");
break;
case showUI:
break;
case frozen:
break;
case dizzy:
break;
case death:
printf("英雄死亡\n");
return 0;
break;
case moti:
break;
default:
break;
}
}
}
输入输出:
1
正在攻击
2
正在释放技能
0
正在移动
3
10
正在跳舞
20
10
正在跳舞
22
英雄死亡
F:\VC_practice file\day09\Debug\day09.exe (进程 19676)已退出,代码为 0。
按任意键关闭此窗口. . .
9.4 typedef
typedef为C语言的关键字,作用是为一种数据类型(基本类型或自定义数据类型)定义一个新名字,不能创建新类型。
与#define不同,typedef仅限于数据类型,而不是能是表达式或具体的值
define发生在预处理,typedef发生在编译阶段
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef unsigned int ui;
typedef unsigned long long ull;
int main()
{
ui a = 10;
printf("%d\n", a);
ull b = 123486123451;
printf("%lld\n", b);
return 0;
}
输出:
10
123486123451

浙公网安备 33010602011771号