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);

    }
}

04结构体指针.png

结构体和函数

#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

image.png

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

posted @ 2021-12-22 19:24  Izereal  阅读(89)  评论(0)    收藏  举报