C语言结构体

目录

1、初识结构体

2、结构体数组

3、结构体指针

4、共用体/联合体

5、枚举类型

6、typedef关键字


 

1、初识结构体

(1)、为什么要使用结构体

在我们平常应用时我们会需要用和多类型数据表示一个整体,比如学生的信息。而我们平常使用的整型数,浮点型数,字符串都是分散的数据表示是。类比与数组的话,数组是元素类型一样的数据集合,如果是元素类型不同的数据集合,就需要用到结构体了

 (2)、定义一个结构体

struct Student{
    char name[32];
    int age;
    double score;
};//分号不能忘,不然会报错

 它算是一个模板,一般不给赋具体的值,因为每一项在实际应用中并不是都要使用,所以一般在使用时再给其赋具体的值

结构体中的每个成员都是结构体中的一个域,也称为域表或成员变量

我们可以在结构体声明的同时,定义结构体变量,但是尽量少用

结构体的使用示例:

#include <stdio.h>
#include <string.h>
struct Student{
    char name[32];
    int age;
    char gender;
    int student_number;
}stu2;
int main(){
    struct Student stu1;
    strcpy(stu1.name,"张三");//点运算符来访问结构体中的成员变量(域)
    stu1.age=21;
    stu1.gender='g';
    stu1.student_number=20230101;

    strcpy(stu2.name,"李四");
    stu2.age=22;
    stu2.gender='c';
    stu2.student_number=20230102;


    printf("姓名:%s  年龄:%d  性别:%c  学号:%d\n" ,stu1.name,stu1.age,stu1.gender,stu1.student_number);
    
    printf("姓名:%s  年龄:%d  性别:%c  学号:%d\n" ,stu2.name,stu2.age,stu2.gender,stu2.student_number);
    return 0;
}

 运行结果:

重点认知:结构体没什么特殊的,只是把变量藏在结构体里面,而内部的变量,以前学习的东西是通用的,只是“触达的方式”不同 

2、结构体数组

结构体数组其实和普通数组没区别,只是数组里存放的值是一个个结构体而已

接下来用代码来演示结构体数组的应用:

#include <stdio.h>
struct Student
{
	//姓名
	char name[24];
	//性别
	char gender[4];
	//年龄
	int age;
	//成绩
	int grade;
	//地址
	char address[24];
};
int main(){
	//结构体和数组的组合
	struct Student str[]={
		{"张三","男",19,78,"南昌"},
		{"李四","男",20,99,"赣州"},
		{"王二狗","女",18,38,"吉安"}
	};
	int len = sizeof(str)/sizeof(str[0]);
	for(int i=0;i<len;i++){
		printf("姓名:%s 性别:%s 年龄:%d成绩:%d 地址:%s\n",
		str[i].name,str[i].gender,str[i].age,str[i].grade,str[i].address);
	}
	
	return 0;
}

 运行结果

 案例:选民系统

#include <stdio.h>
#include <string.h>
struct Xuanmin{
	char name[32];
	int tickets;
};
int main(){
	//先统计现场人数
	int renshu =0;
	int value1=0;
	int value2=0;
	printf("请主持人确定一下现场人数");
	scanf("%d",&renshu);
	printf("现场参加投票的一共有%d人\n",renshu);
	//1初始化选民信息
	struct Xuanmin join[3];//参选人数
	int len = sizeof(join)/sizeof(join[0]);
	for(int i=0;i<len;i++){
		printf("请输入第%d位选民姓名:",i+1);
		scanf("%s",join[i].name);
	}

	//2、唱票环节
	printf("参选人已经确定,下面开始唱票环节\n");
	for(int i=0;i<len;i++){
		join[i].tickets=0;
	}
	char support[24];
	for(int i=0;i<renshu;i++){
		value1=0;
		memset(support,'\0',sizeof(support));
		printf("请输入你支持参选人的姓名:");
		scanf("%s",&support);

		for(int j=0;j<len;j++){	

		//printf("%s",join[j].name);
		if(strcmp(support,join[j].name)==0){
			join[j].tickets++;
			value1=1;
			//break;
		}
		}
		if(value1==0){
			printf("参选人中没有此人,系统认定您位弃票\n");
			value2++;
		}
	}
	printf("投票结束\n");
	//3、公布结果
	printf("现在公布结果\n");
	for(int i=0;i<len;i++){
		printf("姓名:%s  票数:%d\n",join[i].name,join[i].tickets);
	}
	
	struct Xuanmin max=join[0];
	if(join[0].tickets==join[1].tickets==join[2].tickets){
		printf("三人平票\n");
	}else{
	for(int i=1;i<len;i++){
		if(max.tickets<join[i].tickets){
			max=join[i];
		}
	}
	printf("票数最高的是:\n");
	printf("姓名:%s  票数:%d\n",max.name,max.tickets);
	}
	
	printf("有%d人弃票",value2);
	return 0;
}

3、结构体指针

在这里我们先回忆一下之前学习的指针内容

指针就是地址,指针变量就是存放地址的变量,在这里可以发现结构体也是变量,而变量的访问方式有两种:1、变量名访问 2、地址访问 ,我们上面用到的都是用变量名访问。

通过结构体变量地址来访问该结构体需要一个变量来保持这个地址:这和之前说的指针其实是一样的只是指针类型是结构体

 通过结构体访问指针

#include <stdio.h>
struct Student
{
	//姓名
	char name[24];
	//性别
	char gender[4];
	//年龄
	int age;
	//成绩
	int grade;
	//地址
	char address[24];
};
int main(){
	//结构体和数组的组合
	struct Student str[]={
		{"张三","男",19,78,"南昌"},
		{"李四","男",20,99,"赣州"},
		{"王五","女",18,38,"吉安"}
	};
	struct Student *p;
	p=str;
	int len = sizeof(str)/sizeof(str[0]);
	
	for(int i=0;i<len;i++){
		printf("姓名:%s 性别:%s 年龄:%d成绩:%d 地址:%s\n",
		p->name,p->gender,p->age,p->grade,p->address);
		p++;//指针偏移到结构体数组中的下一个结构体
	}
	p=str;//指针回归到结构体数组首地址
	for(int i=0;i<len;i++){
		printf("姓名:%s 性别:%s 年龄:%d成绩:%d 地址:%s\n",
		p->name,p->gender,p->age,p->grade,p->address);
		p++;//指针偏移到结构体数组中的下一个结构体
	}
	p=str;//指针回归到结构体数组首地址
	for(int i=0;i<len;i++){
		
		printf("姓名:%s 性别:%s 年龄:%d成绩:%d 地址:%s\n",
		(p+i)->name,(p+i)->gender,(p+i)->age,(p+i)->grade,(p+i)->address);
		//指针偏移到结构体数组中的下一个结构体
	}
	p=str;//指针回归到结构体数组首地址
	for(int i=0;i<len;i++){
		
		printf("姓名:%s 性别:%s 年龄:%d成绩:%d 地址:%s\n",
		(p+i)->name,(p+i)->gender,(p+i)->age,(p+i)->grade,(p+i)->address);
		//指针偏移到结构体数组中的下一个结构体
	}
	return 0;
}

 运行结果

 选民系统改进->使用指针实现

#include <stdio.h>
#include <string.h>
struct Xuanmin{
	char name[32];
	int tickets;
};
int main(){
	//先统计现场人数
	int renshu =0;
	int value1=0;
	int value2=0;
	printf("请主持人确定一下现场人数");
	scanf("%d",&renshu);
	printf("现场参加投票的一共有%d人\n",renshu);
	//1初始化选民信息
	struct Xuanmin join[3];//参选人数
	struct Xuanmin *p;
	p=join;
	int len = sizeof(join)/sizeof(join[0]);
	for(int i=0;i<len;i++){
		printf("请输入第%d位选民姓名:",i+1);
		scanf("%s",p->name); 
		p++;
	}
	p=join;
	//2、唱票环节
	printf("参选人已经确定,下面开始唱票环节\n");
	for(int i=0;i<len;i++){
		p->tickets=0;
		p++;
	}
	p=join;
	char support[24];
	for(int i=0;i<renshu;i++){
		value1=0;
		memset(support,'\0',sizeof(support));
		printf("请输入你支持参选人的姓名:");
		scanf("%s",&support);

		for(int j=0;j<len;j++){	

		//printf("%s",join[j].name);
		if(strcmp(support,p->name)==0){
			p->tickets++;
			value1=1;
			//break;
		}
		p++;
		}
		p=join;
		if(value1==0){
			printf("参选人中没有此人,系统认定您位弃票\n");
			value2++;
		}
	}
	printf("投票结束\n");
	//3、公布结果
	printf("现在公布结果\n");
	p=join;
	for(int i=0;i<len;i++){
		printf("姓名:%s  票数:%d\n",p->name,p->tickets);
		p++;
	}
	p=join;
	struct Xuanmin *max=p;
	if((p+0)->tickets==(p+1)->tickets==(p+2)->tickets){
		printf("三人平票\n");
	}else{
	for(int i=1;i<len;i++){
		if(max->tickets<p->tickets){
			max=p;
		}
		p++;
	}
	p=join;
	printf("票数最高的是:\n");
	printf("姓名:%s  票数:%d\n",max->name,max->tickets);
	}
	printf("有%d人弃票",value2);
	return 0;
}

选民系统再改进 :结构体数组,指针,函数应用综合应用

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Xuanmin{
	char name[32];
	int tickets;
};
//确定选民人数,和投票人数,并初始化选民信息
struct Xuanmin* initXms(struct Xuanmin *p,int *len,int *lenshu){
	printf("请输入选民人数:");
	scanf("%d",len);
	p=(struct Xuanmin*)malloc(sizeof(struct Xuanmin)*(*len));
	printf("请主持人确定在场投票人数\n");
	printf("在场投票人数有:");
	scanf("%d",lenshu);
	printf("下面开始录入参选人姓名\n");
	for(int i=0;i<*len;i++){
		printf("第%d位参选人姓名是:",i+1);
		scanf("%s",p->name);
		p->tickets=0;
		p++;
	}
	return p-(*len);
}
//遍历选民信息
void Bianli(struct Xuanmin *p,int len){
	for(int i=0;i<len;i++){
		printf("姓名:%s  票数:%d\n",p->name,p->tickets);
		p++;
	}

}
//投票选举
struct Xuanmin* Toupiao(struct Xuanmin *p,int len,int lenshu ,int *value){
	char mz[32];
	memset(mz,'\0',sizeof(mz)); 
	int value2=0;
	for(int i=0;i<lenshu;i++){
		value2=0;
	printf("请输入你所支持的人的名字:");
	scanf("%s",mz);
	for(int j=0;j<len;j++){
		if(strcmp(p->name,mz)==0){
			p->tickets++;
			value2=1;
		}
		p++;
	}
	
	if(value2==0){
		printf("没有此人系统认定你为弃票!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
		(*value)++;
	}
	p=p-len;
	}
	printf("value==%d\n",*value);
	return p;
}
//公布结果
void XmMax(struct Xuanmin *p,int len){

	struct Xuanmin *max;
	max=p;
	for(int i=0;i<len;i++){
		if(max->tickets<p->tickets){
			max=p;
		}
		p++;
	}
	p=p-len;
	Bianli(max,1);
}
int main(){
	struct Xuanmin *join=NULL;
	int len=0;
	int lenshu=0;
	int value=0;//用来记录弃票数
	join=initXms(join,&len,&lenshu);
	Bianli(join,len);
	printf("信息录入成功接下来开始投票环节\n");
	Toupiao(join,len,lenshu,&value);
	printf("投票结束,公布结果\n");
	Bianli(join,len);
	printf("共有%d人参与投票,有%d人弃票\n",lenshu,value);
	printf("最终获选者是:\n");
	XmMax(join,len);
	
	return 0;
}

选民系统pro max版,使用二级指针

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Xuanmin{
	char name[32];
	int tickets;
};
//  
void  initXms(struct Xuanmin **p,int *len,int *lenshu){//二级指针保存的是指针变量的地址
	printf("请输入选民人数:");
	scanf("%d",len);
	*p=(struct Xuanmin*)malloc(sizeof(struct Xuanmin)*(*len));
	printf("请主持人确定在场投票人数\n");
	printf("在场投票人数有:");
	scanf("%d",lenshu);
	printf("下面开始录入参选人姓名\n");
	for(int i=0;i<*len;i++){
		printf("第%d位参选人姓名是:",i+1);
		scanf("%s",(*p)->name);
		(*p)->tickets=0;
		(*p)++;
	}
	*p= *p-(*len);
}
//遍历选民信息
void Bianli(struct Xuanmin *p,int len){
	for(int i=0;i<len;i++){
		printf("姓名:%s  票数:%d\n",p->name,p->tickets);
		p++;
	}
}
//投票选举
struct Xuanmin* Toupiao(struct Xuanmin *p,int len,int lenshu ,int *value){
	char mz[32];
	memset(mz,'\0',sizeof(mz)); 
	int value2=0;
	for(int i=0;i<lenshu;i++){
		value2=0;
	printf("请输入你所支持的人的名字:");
	scanf("%s",mz);
	for(int j=0;j<len;j++){
		if(strcmp(p->name,mz)==0){
			p->tickets++;
			value2=1;
		}
		p++;
	}
	
	if(value2==0){
		printf("没有此人系统认定你为弃票!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
		(*value)++;
	}
	p=p-len;
	}
	printf("value==%d\n",*value);
	return p;
}
//公布结果
void XmMax(struct Xuanmin *p,int len){

	struct Xuanmin *max;
	max=p;
	for(int i=0;i<len;i++){
		if(max->tickets<p->tickets){
			max=p;
		}
		p++;
	}
	p=p-len;
	Bianli(max,1);
}
int main(){
	struct Xuanmin *join=NULL;
	int len=0;
	int lenshu=0;
	int value=0;//用来记录弃票数
	initXms(&join,&len,&lenshu);
	Bianli(join,len);
	printf("信息录入成功接下来开始投票环节\n");
	Toupiao(join,len,lenshu,&value);
	printf("投票结束,公布结果\n");
	Bianli(join,len);
	printf("共有%d人参与投票,有%d人弃票\n",lenshu,value);
	printf("最终获选者是:\n");
	XmMax(join,len);
	
	return 0;
}

4、共用体/联合体

 共用体就是不同类型变量共享同一块空间

结构体与共用体的区别:

1、结构体元素有各自单独空间,共用体元素共享空间,空间大小有最大类型确定

2、结构体元素互不影响而共用体赋值会导致覆盖

#include <stdio.h>
struct TestT
{
	double ddate;
	int idata;
	char cdata;
};
union TestU
{
	int idata;
	char cdata;
	double ddate;
};
int main(){
	struct TestT t1;
	union TestU u1;
	printf("结构体t1的大小%d\n",sizeof(t1));
	printf("结构体t1.idata的大小%d  ,地址是%p\n",sizeof(t1.idata),&t1.idata);
	printf("结构体t1.cdata的大小%d  ,地址是%p\n",sizeof(t1.cdata),&t1.cdata);
	printf("结构体t1.ddate的大小%d  ,地址是%p\n",sizeof(t1.ddate),&t1.ddate);
	
	//共用体中值的覆盖问题
	u1.idata=19;
	u1.cdata='c';
	
	printf("u1.idata=%d\n",u1.idata);
	printf("u1.cdata=%d\n",u1.cdata);
	printf("u1.ddate=%d\n",u1.ddate);
	printf("共用体u1的大小%d\n",sizeof(u1));
	printf("共用体u1.idata的大小%d  ,地址是%p\n",sizeof(u1.idata),&u1.idata);
	printf("共用体u1.cdata的大小%d  ,地址是%p\n",sizeof(u1.cdata),&u1.cdata);
	printf("共用体u1.ddate的大小%d  ,地址是%p\n",sizeof(u1.ddate),&u1.ddate);
	return 0;
}

 运行结果

 
结构体struct 的空间计算遵循的2个原则:
1:整体空间是占用空间最大的成员(的类型)所占字节数的整数倍,但是在32位Linix + gcc环境下,若最大成员类型所占字节数超过4,如double是8,则整体空间是4的倍数即可。
2:数据对齐原则。内存按结构体成员的先后顺序排列,当排到该成员变量时,其前面已摆放的空间大小必须是该成员类型大小的整数倍, 如果不够则补齐,依次向后类推。但在Linux + gcc环境下,某成员类型所占字节数超过4,如double是8,则前面已摆放的空间大小是4的整数倍即可,不够则补齐

共用体union元素是共享一个空间,空间大小有最大类型确定  

结构体的应用:有若干个人员的数据其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。要求用同一个表格来处理

#include <stdio.h>
#include <string.h>
struct Tset
{
	char name[24];
	char gender;
	char zhiye;
	union C{//这里的c可写可不写
		int class_and_grade;
		char post[32];
	}mes;//在声明时定义变量
};
int main(){
	struct Tset ts[2];
	struct Tset *p=NULL;
	p=ts;
	
	for(int i=0;i<2;){
		printf("请输入你的职业:学生输入s,教师输入t\n");
		scanf("%c",&(p->zhiye));//这里zhiye表示的是字符变量不是地址,所以p指向他的时候得取地址才能输入值
		if(p->zhiye == 's'){
			printf("同学你好请输入你的班级:\n");
			scanf("%d",&(p->mes.class_and_grade));//这里和上面同理
			printf("同学你好请输入你的姓名\n");
			scanf("%s",p->name);//这里指向的是字符串数组,数组名就是地址,所以指向的就是name的地址
			p++;
			i++;
		}else if(p->zhiye == 't'){
			printf("老师您好请输入你的职务:\n");
			scanf("%s",p->mes.post);
			printf("老师你好请输入你的姓名\n");
			scanf("%s",p->name);
			p++;
			i++;
		}else{
			printf("输入错误请输入正确的职业代码,谢谢!!!\n");
		}
		getchar();//吸收上面的回车
	}
	p=ts;
	
	for(int i=0;i<2;i++){
	if(p->zhiye == 's'){
		printf("姓名:%s  职业:%c  班级:%d\n",p->name,p->zhiye,p->mes.class_and_grade);
			p++;

	}else{
		printf("姓名:%s  职业:%c  职务:%s\n",p->name,p->zhiye,p->mes.post);
			p++;

	}
		
	}
	return 0;
	
}

 运行结构

当然这个代码也可以和上面一样进行改进,将步骤封装成函数 

5、枚举类型

 

枚举是 C 语言中的一种基本数据类型,用于定义一组具有离散值的常量。,它可以让数据更简洁,更易读。枚举类型通常用于为程序中的一组相关的常量取名字,以便于程序的可读性和维护性。定义一个枚举类型,需要使用 enum 关键字,后面跟着枚举类型的名称,以及用大括号 {} 括起来的一组枚举常量。每个枚举常量可以用一个标识符来表示,也可以为它们指定一个整数值,如果没有指定,那么默认从 0 开始递增。

枚举语法定义格式为:enum 枚举名 {枚举元素1,枚举元素2,……};

比如一周有七天我们用枚举的方式

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

 注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。枚举里面的值不能重复

 枚举变量的定义

1、先定义枚举类型,在定义枚举变量

2、定义枚举类型的同时定义枚举变量

3、省略枚举名称,直接定义枚举变量        

枚举在 switch 中的使用:

#include <stdio.h>
#include <stdlib.h>
enum color { red=1, green, blue };
int main()
{
 
  
 
    enum  color favorite_color;
 
    /* 用户输入数字来选择颜色 */
    printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): ");
    scanf("%u", &favorite_color);
 
    /* 输出结果 */
    switch (favorite_color)
    {
    case red:
        printf("你喜欢的颜色是红色");
        break;
    case green:
        printf("你喜欢的颜色是绿色");
        break;
    case blue:
        printf("你喜欢的颜色是蓝色");
        break;
    default:
        printf("你没有选择你喜欢的颜色");
    }
 
    return 0;
}

 运行结果

6、typedef关键字

typedef的用途定义一种类型的别名

如:

#include <stdio.h>
typedef int zhenxin;
typedef char zifu;
int main(){
	zhenxin i=20;
	zifu str='c';
	printf("%d   %c\n",i,str);
	return 0;
}

运行结果

 typedef一般配合结构体用,方便嘛,不要每次都要struct开头

#include <stdio.h>
#include <string.h>
typedef struct{
	int age;
	char name[32];
	
}Mei;
void initMei(Mei p[],int len){
	for(int i=0;i<len;i++){
		printf("年龄:%d  姓名:%s \n",p[i].age,p[i].name);
	}	
}
void initMei2(Mei *p,int len){
	for(int i=0;i<len;i++){
		printf("年龄:%d  姓名:%s \n",p->age,p->name);
		p++;
	}	
}
int main(){
	Mei p[2];
	p[0].age=21;
	strcpy(p[0].name,"小美");
	p[1].age=20;
	strcpy(p[1].name,"大漂亮");
	Mei *mei;
	mei=p;
	initMei(p,(sizeof(p)/sizeof(p[0])));
	initMei2(mei,(sizeof(p)/sizeof(p[0])));
	initMei2(p,(sizeof(p)/sizeof(p[0])));
	return 0;
}

运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值