Day 1 — 4 : 结构体&共用体

结构体

结构体的意义

        问题引入:

        学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用C语言程序存储并处理一组学生的学籍。

结构体的定义和使用

        结构体的定义:结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据称为结构型数据的“成员”,其描述了一块内存区间的大小及解释意义。

        结构体的定义

        语法:

        struct 结构体名

{

        <结构体成员列表>

} ;

#include<stdio.h>
struct student
{
	char  name[16]; //姓名
	int   num;		//学号
	float score;	//成绩
};

        结构体的使用(赋值)方式之一

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct student
{
	char  name[16]; //姓名
	int   num;		//学号
	float score;	//成绩
//3.定义结构体时赋值
}stu4("王五",103,99);
int main()
{
//1.定义后赋值
	struct student stu1;
	stu1.num =   100;
	strcpy(stu1.name, "张三");
	stu1.score = 100;
	printf("name = %s , num = %d , score = %f\n", stu1.name, stu1.num, stu1.score);
//2.定义时赋值
	//a.全部赋值
	struct student stu2 = { "李四",101,98 };
	printf("name = %s , num = %d , score = %f\n", stu2.name, stu2.num, stu2.score);
	//a.部分赋值
	struct student stu3 = { 
		.name = "",
		.num = 102,
		.score = 99
	};
	printf("name = %s , num = %d , score = %f\n", stu3.name, stu3.num, stu3.score);
	return 0;
}

        结构体的使用(赋值)方式之二—结构体数组

        作用:将自定义的结构体放入到数组中方便维护。

        语法:

        struct 结构体名 数组名[元素个数] = {{},{},……{}} ;

        注意:在C语言中,数组初始化应该在声明时进行,或者通过逐个元素赋值。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct student
{
	char  name[16]; //姓名
	int   num;		//学号
	float score;	//成绩
};
int main()
{
	struct student stu[3] = { {"张三",100,100},{"李四",101,98},{"王五",103,99} };
	int i;
	for (i = 0; i < 3; i++)
	{
		printf("%s %d %f\n", stu[i].name, stu[i].num, stu[i].score);
	}
	return 0;
}

结构体的使用(赋值)方式之三 — 结构体指针

        作用:

        通过指针访问结构体中的成员。

        语法:

        struct 结构体名 * 指针名;

        利用操作符 ->可以通过结构体指针访问结构体。

        普通变量访问结构体用的是 

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct student
{
	char  name[16]; //姓名
	int   num;		//学号
	float score;	//成绩
};
int main()
{
	struct student stu1;
	//通过结构体变量去赋值
	strcpy(stu1.name, "李四");
	stu1.num   = 100;
	stu1.score = 101;
	//通过结构体指针去赋值
	struct student stu2;
	struct student* p = &stu2;
	strcpy(p->name,"李四");
	p->num   = 101;
	p->score = 98;
	printf("%s %d %f", p->name, p->num, p->score);
	return 0;
}

结构体嵌套结构体

        结构体中的成员可以是另一个结构体。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct person
{
	char name[16];
	char sex[5];
	int  age;
};
struct student
{
	struct person stu;
	int score;
};
struct teacher
{
	struct person tea;
	char phone[12];
};
int main()
{
	struct student stu1;
	strcpy(stu1.stu.name,"张三");
	//注意:有两个 .
	strcpy(stu1.stu.sex,"男");
	stu1.stu.age = 16;
	stu1.score = 100;
	printf("name = %s sex = %s age = %d score = %d\n", stu1.stu.name, stu1.stu.sex, stu1.stu.age, stu1.score);
	return 0;
}

结构体的大小

        问题引入:为什么会出现以下结果。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct A
{
	char a;
	int b;
	char c;
	char d;
};
struct B
{
	char a;
	short b;
	char c;
	char d;
};
int main()
{
	printf("%ld %ld\n", sizeof(int), sizeof(struct A));	 //4 12
	printf("%ld %ld\n", sizeof(short), sizeof(struct B));//2  6
	return 0;
}

字节对齐

        字节对齐主要是针对结构体而言的,通常编译器会自动对其成员变量进行对齐,以提高数据存取的效率

        问题引入:计算机每次读取数据都要对取多少字节数据进行判断,十分不便。

struct A
{
	char   a;//1byte
	int    b;//4byte
	double c;//8byte
};

        作用:

        平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

        性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

结构体大小的计算方法(重要)

        1.自身对齐 — 数据类型

        2.默认对齐 — 机器

        3.有效对齐 — 最终状态

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct A 
{			//		      自身对齐     默认对齐(32位机)     有效对齐				  存放地址(要能整除有效对齐)
	char a; //sizeof(char)= 1				   4				  1(1和4选最小)         0(补1,2,3)
	int b;	//			      4				   4                  4						  4(4,5,6,7)					
	char c;	//			      1                4				  1						  8	
	char d;	//			      1                4                  1						  9(补10,11)
};
//-----------整个字节按有效对齐方式中最大的(4字节)对齐,根据存放地址来看,一共需要12个字节大小-----------------
int main()
{
	printf("%d\n", sizeof(struct A));
	return 0;
}

位域

        位域是把一个字节中的二进制位分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

        语法:struct 位域结构体名

        {

        位域列表

        };

        位域列表:类型说明符 位域名:位域长度

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct a
{
	unsigned char a ;
	unsigned char b ;
	unsigned char c ;
};
struct A
{
	unsigned char a : 2;//两个比特位,最大值11,最大值为3
	unsigned char b : 3;
	unsigned char c : 3;
};
int main()
{
	printf("%d\n", sizeof(struct a));//3
	printf("%d\n", sizeof(struct A));//1(节省了两个字节的空间)
	//1.先定义再赋值
	struct A t;
	t.a = 1;//可以把a改成4试试
	t.b = 2;
	t.c = 3;
	printf("%d %d %d\n", t.a, t.b, t.c);
	//2.定义变量时进行赋值
	struct A t = { 1,2,3 };
	printf("%d %d %d\n", t.a, t.b, t.c);
	return 0;
}

共用体

引入

        问题引入:老师和学生能否应用相同的管理系统?

共用体的定义和使用

        在C语言中,不同数据类型的数据可以使用共同的存储区域,这种数据构造类型称为共用体,简称共用,又称联合体。

        共用体的定义

        union 共用体名

        {

        共用体成员列表

        };

struct person
{
	char name[16];
	int  age;
	char sex;
	char phone[12];
};
union un
{
	int num;
	struct person stu;
	struct person tea;
};

        共用体的使用

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct person
{
	char name[16];
	int  age;
	char sex;
	char phone[12];
};
union un
{
	int num;
	char ch;
	struct person stu;
	struct person tea;
};
int main()
{
	//1.定义完赋值
		union un u;
		u.num = 67;
		printf("num = %d ch = %c\n", u.num,u.ch);  //num = 67 ch = C (因为C的ASCII码值是67)。ch和num共用一个空间。
	//2.定义时赋值
	union un u1 = {.stu.name = "张三",.stu.age = 18, };
	printf("name = %s age = %d \n",u1.stu.name, u1.stu.age);
	return 0;
}

        和结构体的区别

        共用体三个变量用一个内存空间,结构体分别用三个内存空间。

共用体的大小

        问题引入:

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
union A
{
	char   a;	//1字节
	int    b;	//4字节
	double c;	//8字节
};
//找最大值:8字节(因为union变量共用一个空间)
union B
{
	int  a;		//4字节
	char s[7];	//7字节
};
//7不能被4整除,所以是8字节。(字节对齐)
union C
{
	char a;
	char s[7];
};
//找最大值:7字节
int main()
{
	printf("%ld\n", sizeof(union A));
	printf("%ld\n", sizeof(union B));
	printf("%ld\n", sizeof(union C));
	return 0;
}

枚举

枚举的意义

        在开发中,有些变量只有几种可能的取值,比如:一周有七天、一年有四季、在枚举的定义中,会将变量一一列出来。

枚举的定义

        语法:

        enum 枚举名

        {

        枚举成员列表,

        枚举成员列表...

        };   

        注意:不同枚举,成员名不可以一样。

枚举的使用

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
enum week
{
	Monday,
	Tuesday = 4 ,
	Wednesday,
	Thursday,
	Friday,
	Saturday,
	Sunday
};
int main()
{
	enum e t;
	t = Monday;
	printf("%d\n", t);//值从0开始
	t = Tuesday;      //已经对Tuesday进行赋值
	printf("%d\n", t);//4
	t = Wednesday;
	printf("%d\n", t);//5


	return 0;
}
//结论:枚举成员从0开始,依次加一,可以对成员进行赋值,后面的成员在其基础上依次加1。

typedef关键字

作用

        typedef 是在计算机编程语言中用来为复杂的声明定义简单的别名。

意义

        给变量一个易记且意义明确的新名字。

使用

        语法:

        typedef <已有数据类型> <新数据类型>;

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996);
struct person
{
	char name[16];
	int  age;
	char sex;
	char phone[12];
};
//1.定义结构体后重命名
typedef struct person sp;
//2.定义结构体时直接重命名
typedef union un
{
	int num;
	char ch;
	sp stu;
	sp tea;
}a;
int main()
{
	a u;
	u.num = 67;
	printf("num = %d ch = %c\n", u.num, u.ch); 
	a u1 = { .stu.name = "张三",.stu.age = 18, };
	printf("name = %s age = %d \n", u1.stu.name, u1.stu.age);
	return 0;
}

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值