前言
本篇博文是本人在学习嵌入式软件C语言中结构体章节的笔记,适用于小白入门C语言的同学。希望能帮到大家。有什么不足可以评论告诉我。
在阅读本篇博文时,想学习的同学可以打打博文中的代码,甚至默写代码,改写代码,有助于你的学习。C语言注重多打代码,多练习,才能学得扎实。
1.初识结构体
1.什么是结构体
C语言结构体是一种用户自定义的数据类型,它允许你将不同类型的数据项组合在一起,形成一个新的复合类型。结构体可以包含多个成员变量,每个成员可以是不同的数据类型,如整型、浮点型、字符型、数组等。
结构体的定义使用关键字"struct",后面跟着结构体的名称,然后是结构体的成员列表,成员列表由成员类型和成员名称组成,多个成员之间使用逗号分隔,在结构体末尾需要加上分号。
struct Person {
char name[20];
int age;
float height;
};
在上面的示例中,我们定义了一个名为Person的结构体,它包含三个成员变量:一个字符数组name,一个整型变量age,一个浮点型变量height。
2.为什么要用结构体
1.整型数,浮点型,字符串是分散的数据表示有时候我们需要用很多类型数据表示一个整体,比如学生信息。
2.类比于数组:数组是元素类型一样的数据集合,如何是元素类型不同的数据集合,就要用到结构体了
3.定义一个结构体
它算是一个模版,一般不给赋值,每一项在实际应用中并不是都要使用。
结构体示意图如下:
结构体示例代码如下
#include <stdio.h>
/*
时间: 2023年7月9日16:58:37
程序功能:定义一个结构体
*/
struct Student //
{
int mum;
char name[32];
char sex;
int age;
double score;
char addr[32];
};
struct Day
{
int year;
int month;
int day;
};
struct Voter
{
char name[32];
int tickets;
};
int main()
{
return 0;
}
4.什么是成员列表
1.结构体成员列表指的是在结构体定义中,用于描述结构体包含的各个成员的部分。它由结构体的成员类型和成员名称组成,多个成员之间使用逗号进行分隔。
2.在C语言中,每个结构体成员都有其类型和名称。类型可以是基本数据类型(如整型、浮点型、字符型等),也可以是其他结构体类型、指针类型等。名称是用来标识该成员的唯一标识符。
3.示例代码
struct Person {
char name[20]; // 成员1:字符数组类型的name
int age; // 成员2:整型类型的age
float height; // 成员3:浮点型类型的height
};
4.成员列表也称域表,每个成员都是结构体的一个域。
5.特殊定义方式之在声明的同时,定义变量,尽量少用
struct Student
{
char name[32];
int age;
int StudentID;
char sex[32];
},Student1,Student2; //Student1,Student2 就是在定义变量
6.初始化一个结构体变量并引用
1.初始化
struct Student stu2 = {"李白",99,1024,"男"};
2.引用
scanf("%s",&stu1.name); //点运算符用来访问结构体的成员变量(域) 字符串可以输入汉字
7.重点知识
结构体没什么特殊的,只是把变量藏在结构体里面,而内部的变量,以前学习的东西是通用的,只是“触达的方式”不同。
8.例题:输入两个学生的名字,学号,成绩,输出成绩高的学生的信息
#include <stdio.h>
/*
时间: 2023年7月9日23:00:54
程序功能:例题:输入两个学生的名字,学号,成绩,输出成绩高的学生的信息
*/
struct Student
{
char name[32];
int age;
int StudentID;
double score;
char sex[32];
};
struct Student stu1;
struct Student stu2;
struct Student max;
void initStuct()
{
puts("请输入第一个学生的信息\n");
puts("姓名");
scanf("%s",&stu1.name);
puts("年龄");
scanf("%d",&stu1.age);
puts("学号");
scanf("%d",&stu1.StudentID);
puts("成绩");
scanf("%lf",&stu1.score);
puts("性别");
scanf("%s",&stu1.sex);
puts("请输入第二个学生的信息\n");
puts("姓名");
scanf("%s",&stu2.name);
puts("年龄");
scanf("%d",&stu2.age);
puts("学号");
scanf("%d",&stu2.StudentID);
puts("成绩");
scanf("%lf",&stu2.score);
puts("性别");
scanf("%s",&stu2.sex);
}
void compare()
{
if(stu1.score > stu2.score)
{
max = stu1;
}else
{
max = stu2;
}
}
void outPut()
{
printf("姓名\t年龄\t学号\t成绩\t性别 \n");
printf("%s\t%d\t%d\t%.2lf\t%s\t \n",
max.name,max.age,max.StudentID,max.score,max.sex);
}
void introduce()
{
puts("程序功能:例题:输入两个学生的名字,学号,成绩,输出成绩高的学生的信息");
}
int main()
{
char yesOrNoc;
introduce();
do
{
initStuct();
compare();
outPut();
puts("是否继续判断 y/n");
getchar();
scanf("%c",&yesOrNoc);
}while(yesOrNoc=='y' || yesOrNoc=='Y');
puts("程序退出!!!");
return 0;
}
2.结构体数组
1.什么是结构体数组
1.C语言结构体数组是一种由结构体元素组成的数组。它允许你在同一个数组中存储多个结构体对象,并且每个对象都包含了多个成员变量。
2.结构体数组的定义方式与普通数组类似,只是需要在数组元素的类型上加上结构体的定义。例如,假设有一个表示人员信息的结构体Person,包含成员变量name和age,那么可以定义一个存储多个人员信息的结构体数组如下:
struct Person {
char name[20];
int age;
};
struct Person people[5]; // 定义一个包含5个Person结构体元素的数组
上述代码中,我们定义了一个名为people的结构体数组,该数组的元素类型为struct Person,并且数组的大小为5,即可以存储5个人的信息。
3.结构体数组的元素可以通过索引来访问和修改,索引从0开始计数,例如:
people[0].age = 25; // 对数组中的第一个结构体元素的age成员进行赋值
people[1].age = 30; // 对数组中的第二个结构体元素的age成员进行赋值
你还可以使用循环语句来遍历整个结构体数组,访问或修改每个结构体元素的成员变量。
4.通过结构体数组,你可以方便地存储和处理多个结构体对象,例如存储学生信息、员工信息等。它在C语言中提供了一种灵活的方式来组织和处理结构化的数据。
2.结构体数组输入
int i;
for(i=0; i<3; i++)
{
printf("请输入第%d个同学的信息\n",i+1);
puts("姓名:");
scanf("%s",&arr[i].name);
puts("年龄:");
scanf("%d",&arr[i].age);
puts("学号:");
scanf("%d",&arr[i].StudentID);
puts("成绩:");
scanf("%lf",&arr[i].score);
puts("性别:");
scanf("%s",&arr[i].sex);
}
3.结构体数组输出
int i;
for(i=0; i<3; i++)
{
printf("%s\t%d\t%d\t%0.2lf\t%s \n",
arr[i].name,arr[i].age,arr[i].StudentID,arr[i].score,arr[i].sex);
}
4.结构体数组完成输入输出
#include <stdio.h>
/*
时间: 2023年7月10日14:44:56
程序功能:结构体数组
*/
struct Student
{
char name[32];
int age;
int StudentID;
double score;
char sex[32];
};
struct Student arr[3]; //定义一个结构体数组
void initStruct()
{
int i;
puts("开始输入程序!!!\n");
for(i=0; i<3; i++)
{
printf("请输入第%d个同学的信息\n",i+1);
puts("姓名:");
scanf("%s",&arr[i].name);
puts("年龄:");
scanf("%d",&arr[i].age);
puts("学号:");
scanf("%d",&arr[i].StudentID);
puts("成绩:");
scanf("%lf",&arr[i].score);
puts("性别:");
scanf("%s",&arr[i].sex);
}
}
void outputStruct()
{
int i;
puts("开始输出程序!!!\n");
printf("姓名\t年龄\t学号\t成绩\t性别 \n");
for(i=0; i<3; i++)
{
printf("%s\t%d\t%d\t%0.2lf\t%s \n",
arr[i].name,arr[i].age,arr[i].StudentID,arr[i].score,arr[i].sex);
}
}
int main()
{
char yesOrNoC;
puts("程序功能:结构体数组\n\n");
puts("struct Student arr[3]; //定义一个结构体数组\n\n");
do
{
initStruct();
outputStruct();
getchar();
puts("是否继续输入输出 y/n");
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='Y' || yesOrNoC=='y');
puts("程序结束!!!");
return 0;
}
5.结构体数组应用——选票系统
1.选票系统主要功能为:
第一步登记候选人姓名——第二步进行投票和唱票环节——第三步公布选票结果。
2.判断最高得票数同票算法
代码如下:
if(xm[0].tickets == xm[1].tickets && xm[1].tickets > xm[2].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
xm[0].name,xm[1].name);
return 0;
}else if(xm[1].tickets == xm[2].tickets && xm[2].tickets > xm[0].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
xm[1].name,xm[2].name);
return 0;
}else if(xm[0].tickets == xm[2].tickets && xm[2].tickets > xm[1].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
xm[0].name,xm[2].name);
return 0;
}else
{
printf("%s以%d票当选!!废票%d\n",max.name,max.tickets,wasteTickets);
}
3.结构体指针
1.什么是结构体指针
1.C语言结构体指针是指向结构体的指针变量。它可以用于访问和操作结构体的成员变量,而不需要使用结构体变量本身。
2.结构体指针的定义方式和普通指针类似,只是需要在指针变量的类型上加上结构体的名称。例如,假设有一个表示人员信息的结构体Person,包含成员变量name和age,那么可以定义一个指向该结构体的指针如下:
struct Person {
char name[20];
int age;
};
struct Person person1;
struct Person *personPtr; // 定义一个指向Person结构体的指针变量
上述代码中,我们定义了一个名为personPtr的指针变量,它的类型是struct Person ,表示一个指向Person结构体的指针。
3.通过结构体指针,可以通过两种方式来访问和操作结构体的成员变量:
1.使用->操作符:结构体指针和成员变量之间使用->操作符来访问成员变量。例如:personPtr->age,表示访问指针personPtr所指向的结构体的age成员变量。
2.使用( )操作符:可以先通过指针解引用得到结构体对象,然后再使用.操作符来访问成员变量。例如:(*personPtr).age,表示访问指针personPtr所指向的结构体的age成员变量。
4.下面是一个示例,展示如何使用结构体指针来访问和修改结构体的成员变量:
struct Person {
char name[20];
int age;
};
struct Person person1;
struct Person *personPtr; // 定义一个指向Person结构体的指针变量
personPtr = &person1; // 将指针变量指向某个结构体对象
(*personPtr).age = 25; // 使用指针解引用,然后通过`.`操作符访问成员变量
personPtr->age = 25; // 使用指针和`->`操作符访问成员变量
5.通过结构体指针,你可以更灵活地操作结构体对象,特别是在函数传参或动态内存分配等场景下。它允许你直接访问和修改结构体的成员变量,而无需创建额外的结构体变量。
2.知识回顾
1.指针就是地址;指针变量就是存放地址的变量
2.结构体也是变量。
3.变量访问有两种方式:1.变量名 2.地址
4通过结构体变量地址来访问该结构体需要一个变量来保存这个地址:这和之前说的指针,其实是一样的只是指针类型是结构体。
5.知识回顾代码
#include <stdio.h>
/*
时间: 2023年7月10日23:26:28
程序功能:初识结构体指针
*/
struct pointer //定义一个名为指针的结构体
{
int data;
char cdata;
};
int main()
{
//变量的4要素:1、名 2、值 3、类型 4、地址
int a = 10; //定义一个整型变量a = 10
int *p = &a; //定义一个整型指针变量指向整型变量a
char c = 'a'; //定义一个字符型变量c = 'a';
char *pc = &c; //定义一个字符型指针变量指向字符型变量c
struct pointer data; //定义一个名为指针的结构体变量data
struct pointer *pdata = &data; //定义一个名为指针的结构体指针变量pdata指向
//名为指针的结构体变量data
return 0;
}
3.通过结构体指针来访问结构体
以下代码是通过结构体指针来访问结构体示例
#include <stdio.h>
/*
时间: 2023年7月11日00:10:18
程序功能:通过结构体指针来访问结构体
*/
struct pointer //定义一个名为指针的结构体
{
int idata;
char cdata;
};
void introduce()
{
puts("程序功能:通过结构体指针来访问结构体\n\n");
puts("struct pointer //定义一个名为指针的结构体\n");
puts("struct pointer data = {10,'c'}; //定义一个名为指针的结构体变量data = {10,'c'};\n");
puts("struct pointer *pdata = &data; //定义一个名为指针的结构体指针变量pdata指向");
puts("//名为指针的结构体变量data\n");
puts("printf(“data的idata = %d\n”,data.idata); //变量名访问,用点运算符\n");
puts("printf(“data的idata = %d\n”,pdata->idata); //指针变量名访问,用“->”运算符\n");
puts("pdata->cdata = 'R'; //通过结构体指针变量来修改结构体中cdata的值\n\n");
}
int main()
{
//变量的4要素:1、名 2、值 3、类型 4、地址
int a = 10; //定义一个整型变量a = 10
int *p = &a; //定义一个整型指针变量指向整型变量a
char c = 'a'; //定义一个字符型变量c = 'a';
char *pc = &c; //定义一个字符型指针变量指向字符型变量c
introduce();
struct pointer data = {10,'c'}; //定义一个名为指针的结构体变量data = {10,'c'};
struct pointer *pdata = &data; //定义一个名为指针的结构体指针变量pdata指向
//名为指针的结构体变量data
printf("data的idata = %d\n",data.idata); //变量名访问,用点运算符
printf("data的idata = %d\n",pdata->idata); //指针变量名访问,用“->”运算符
pdata->cdata = 'R'; //通过结构体指针变量来修改结构体中cdata的值
printf("data的cdata = %c\n",data.cdata); //变量名访问,用点运算符
printf("data的cdata = %c\n",pdata->cdata); //指针变量名访问,用“->”运算符
return 0;
}
4.结构体指针应用1——输入输出人员信息
1.程序功能:
第一步输入人员信息——第二步输出人员信息
2.程序代码:
#include <stdio.h>
/*
时间: 2023年7月11日21:55:16
程序功能:结构体指针练习
*/
struct Test
{
char name[32];
int age;
char sex[32];
};
struct Test arr[3];
void initTest()
{
struct Test *p; //结构体指针变量p不能定义成为全局结构体指针变量,定义后会报错。
p = arr; //结构体指针变量p指向全局结构体数组变量arr
puts("第一步输入人员信息\n\n");
int i;
for(i=0; i<3; i++)
{
printf("请输入第%d个人的信息。\n",i+1);
puts("姓名:");
scanf("%s",&p->name); //结构体指针变量用于scanf输入函数时要加‘&’符号,
puts("年龄:");
scanf("%d",&p->age); //不然会出现段错误
puts("性别:");
scanf("%s",&p->sex);
p++; //指针偏移应用在后面,不能用在scanf printf函数内,
//不然会出现偏移后输出结果错误。
}
}
void outputTest()
{
struct Test *p;
p = arr;
puts("第二步输出人员信息\n\n");
int i;
puts("姓名\t年龄\t性别 ");
for(i=0; i<3; i++)
{
printf("%s\t%d\t%s \n",
p->name,p->age,p->sex);
p++;
}
}
void introduce()
{
puts("程序功能:结构体指针练习\n\n");
puts("struct Test *p; //结构体指针变量p不能定义成为全局结构体指针变量,定义后会报错。\n");
puts("p = arr; //结构体指针变量p指向全局结构体数组变量arr\n");
puts("scanf(“%s”,&p->name); //结构体指针变量用于scanf输入函数时要加‘&’符号,");
puts("scanf(“%d”,&p->age); //不然会出现段错误\n");
puts("p++; //指针偏移应用在后面,不能用在scanf printf函数内,");
puts(" //不然会出现偏移后输出结果错误。\n\n");
}
int main()
{
char yesOrNoC;
introduce();
do
{
initTest();
outputTest();
puts("是否继续程序!y/n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("程序退出!!!");
return 0;
}
5.结构体指针应用2——改写选票系统
程序代码如下:
#include <stdio.h>
#include <string.h>
/*
时间: 2023年7月12日00:26:53
程序功能:结构体指针应用2_改写选票系统
*/
struct Voter //定义一个选票结构体
{
char name[32];
int tickets;
};
struct Voter xm[3];//定义一个选票结构体数组变量xm[3]
struct Voter max; //定义一个选票结构体变量max
int len; //数组长度变量
int wasteTickets = 0; //废票变量
void initVoter() //初识化选票,输入每个候选人的名字
{
int i;
struct Voter *p = xm;
puts("第一步登记候选人姓名。\n\n");
len = sizeof(xm)/sizeof(xm[0]);
for(i=0; i<len; i++)
{
p->tickets = 0;
printf("请输入第%d个候选人的名字。\n",i+1);
scanf("%s",&p->name);
p++;
}
}
void singTickets() //唱票
{
char tmpName[32];
int i;
int j;
int person;
int mark; //废票判断变量
struct Voter *p = xm;
puts("第二步进行投票和唱票环节。\n\n");
puts("请输入参与投票的人数。");
scanf("%d",&person);
for(i=0; i<person; i++)
{
mark = 0; //mark不能在定义时赋值0,如果赋值0,后面的废票判别永远不会执行
memset(tmpName,'\0',sizeof(tmpName));
puts("请输入你支持谁。");
scanf("%s",tmpName);
p = xm;
for(j=0; j<len; j++)
{
if(strcmp(tmpName,p->name) == 0)
{
p->tickets++;
mark = 1;
}
p++;
}
if(mark == 0) //废票判断
{
puts("候选人无此人,选票无效");
wasteTickets++;
}
}
}
int ticketsResult() //选票结果
{
int i;
struct Voter *p = xm;
puts("第三步公布选票结果。\n\n");
puts("姓名\t得票数\t");
for(i=0; i<len; i++)
{
printf("%s\t%d \n",p->name,p->tickets);
p++;
}
p = xm;
max = xm[0];
for(i=1; i<len; i++)
{
p++;
if(max.tickets<p->tickets)
{
max = xm[i]; //把xm[i]结构体赋给max结构体,实现替代关系
}
}
if(xm[0].tickets == xm[1].tickets && xm[1].tickets > xm[2].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
xm[0].name,xm[1].name);
return 0;
}else if(xm[1].tickets == xm[2].tickets && xm[2].tickets > xm[0].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
xm[1].name,xm[2].name);
return 0;
}else if(xm[0].tickets == xm[2].tickets && xm[2].tickets > xm[1].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
xm[0].name,xm[2].name);
return 0;
}else
{
printf("%s以%d票当选!!废票%d\n",max.name,max.tickets,wasteTickets);
}
return 0;
}
void introduce()
{
puts("程序功能:结构体指针应用2_改写选票系统\n\n");
puts("1.把以前的普通变量名,或者下标访问的.运算符,改成结构体指针的->\n");
puts("2.指针++,每次遍历会到数组尾巴,下次遍历之前记得回来(重新指向数组首地址)");
puts("但在单独的函数中单独定义结构体指针变量,有些时候不用回到数组首地址。\n\n");
}
int main()
{
char yesOrNoC;
int empty; //定义一个空变量用于承接选票结果函数返回值。
introduce();
do
{
initVoter();
singTickets();
empty = ticketsResult();
puts("是否继续选举?y/n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("程序结束!!!");
return 0;
}
/*
补充知识:
for(i=0; i<len+1; i++)
{
if(xm[i].tickets == xm[i+1].tickets) //当xm[i]>xm[2]时,超出定义的结构体数组元素个数
//系统会为超出的元素变量xm[i]赋0。因此,判断时
//其实没有对前面有效结构体数组元素进行判断,只
//是为后面的无效元素系统赋0后进行判断。此逻辑
//算法可以全覆盖判断最大票数值相同的情况。但认
//真看此算法不严谨,并未判断出有效结构体数组元
//素谁和谁相同。
{
puts("候选人最大得票数相同,此次选举失效,下次选举请听通知!!!");
return 0;
}
}
*/
6.结构体指针,函数,数组综合应用1——选民系统
1.课程代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
时间: 2023年7月13日20:21:32
程序功能:结构体指针数组函数综合应用改写选票系统
*/
struct Voter //定义一个选票结构体
{
char name[32];
int tickets;
};
struct Voter* initVoter(struct Voter *p,int *pn)
{
int i;
if(p == NULL)
{
puts("请输入有几个候选人。");
scanf("%d",pn);
p = (struct Voter*)malloc(*pn*sizeof(struct Voter));
}
for(i=0; i<*pn; i++)
{
p->tickets = 0;
printf("请输入第%d个候选人的名字。\n",i+1);
scanf("%s",&p->name);
p++;
}
return p-*pn;
}
void outputVoter(struct Voter *p,int len)
{
int i;
puts("姓名\t得票数\t");
for(i=0; i<len; i++)
{
printf("%s\t%d \n",p->name,p->tickets);
p++;
}
}
int singTickets(struct Voter *p,int len)
{
char tmpName[32];
int i;
int j;
int person;
int mark; //废票判断变量
int wasteTickets = 0;
struct Voter *pbak = p; //定义一个结构体指针变量pbak指向结构体指针p的首地址。
//puts("第二步进行投票和唱票环节。\n\n");
puts("请输入参与投票的人数。");
scanf("%d",&person);
for(i=0; i<person; i++)
{
mark = 0; //mark不能在定义时赋值0,如果赋值0,后面的废票判别永远不会执行
memset(tmpName,'\0',sizeof(tmpName));
puts("请输入你支持谁。");
scanf("%s",tmpName);
p = pbak;
for(j=0; j<len; j++)
{
if(strcmp(tmpName,p->name) == 0)
{
p->tickets++;
mark = 1;
}
p++;
}
if(mark == 0) //废票判断
{
puts("候选人无此人,选票无效");
wasteTickets++;
}
}
return wasteTickets;
}
struct Voter* getMax(struct Voter *p,int len)
{
int i;
struct Voter* max;
max = p;
for(i=0; i<len; i++)
{
if(max->tickets<p->tickets)
{
max = p; //把xm[i]结构体赋给max结构体,实现替代关系
}
p++;
}
return max;
}
int main()
{
struct Voter *xm = NULL;
struct Voter *result;
int total = 0;
int wasteTickets;
xm = initVoter(xm,&total);
printf("total = %d\n",total);
wasteTickets = singTickets(xm,total);
outputVoter(xm,total);
printf("废票为%d\n",wasteTickets);
result = getMax(xm,total)
printf("%s以%d票当选!!废票%d\n",result->name,result->tickets,wasteTickets);
return 0;
}
2.自己实现代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
时间: 2023年7月13日21:55:07
程序功能:结构体指针数组函数综合应用改写选票系统_自己实现
*/
struct Voter //定义一个选票结构体
{
char name[32];
int tickets;
};
struct Voter *initVoter(struct Voter *p, int *pn)
{
int i;
getchar();
if(p == NULL)
{
puts("请输入候选人有几位。");
scanf("%d",pn);
p = (struct Voter*)malloc(*pn * sizeof(struct Voter));//(struct Voter*)将void型的
//malloc函数强制转换成struct Voter*型
}
for(i=0; i<*pn; i++)
{
p->tickets = 0;
printf("请输入第%d个候选人的名字。\n",i+1);
scanf("%s",p->name);
p++;
}
return p-*pn; //回归到指针初始位置
}
int singTickets(struct Voter *p,int len)
{
int i;
int j;
char tmpName[32];
int person;
int mark; //废票判断变量
int wasteTickets = 0;
struct Voter *pbak = p; //定义一个结构体指针变量pbak指向形参结构体指针变量p的首地址
puts("请输入参见投票的人数");
scanf("%d",&person);
for(i=0; i<person; i++)
{
mark = 0;
memset(tmpName,'\n',sizeof(tmpName));
puts("你支持谁!");
scanf("%s",tmpName);
p = pbak; //每次进行外层循环时回归结构体指针变量p的首地址。
for(j=0; j<len; j++)
{
if(strcmp(p->name,tmpName)== 0)
{
p->tickets++;
mark = 1;
}
p++; //结构体指针变量p发生了偏移。
}
if(mark == 0)
{
puts("没有此候选人,本张选票报废");
wasteTickets++;
}
}
return wasteTickets;
}
struct Voter* ticketsResult(struct Voter *p,int len) //选票结果
{
int i;
int j;
int tmp;
struct Voter *max; //定义一个结构体指针变量max指向形参结构体指针变量p的首地址
max = p;
for(i=0; i<len; i++)
{
if(max->tickets < p->tickets) //把max内的tickets与p内的tickets进行比较,若小于,则
{ //把当前p赋给max。
max = p;
}
p++;
}
return max;
}
void outputVoter(struct Voter *p,int len)
{
int i;
puts("姓名\t得票数\t");
for(i=0; i<len; i++)
{
printf("%s\t%d \n",p->name,p->tickets);
p++;
}
}
int main()
{
struct Voter *xm = NULL;
struct Voter *result;
int total = 0;
int wasteTickets;
char yesOrNoC;
puts("程序功能:结构体指针数组函数综合应用改写选票系统_自己实现\n\n");
puts("程序启动成功!按回车键开始运行。");
do
{
xm = NULL;
puts("第一步进行候选人信息登记\n");
xm = initVoter(xm,&total);
puts("第二步进行投票\n");
wasteTickets = singTickets(xm,total);
puts("第三步投票结果公示\n");
result = ticketsResult(xm,total);
outputVoter(xm,total);
printf("%s以%d票当选!!废票%d\n",result->name,result->tickets,wasteTickets);
puts("是否继续选举?y/n");
getchar();
scanf("%c",&yesOrNoC);
}while(yesOrNoC=='y' || yesOrNoC=='Y');
puts("程序退出!!!");
return 0;
}
/*
if(max[0].tickets == max[1].tickets && max[1].tickets > max[2].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
max[0].name,max[1].name);
exit(-1);
}else if(max[1].tickets == max[2].tickets && max[2].tickets > max[0].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
max[1].name,max[2].name);
exit(-1);
}else if(max[0].tickets == max[2].tickets && max[2].tickets > max[1].tickets)
{
printf("候选人%s和%s是最大得票数相同,此次选举失效,下次选举请听通知!!!\n",
max[0].name,max[2].name);
exit(-1);
}
else
{
return max;
}
*/
7.结构体指针,函数,数组综合应用2——结构体二级指针
1.什么是结构体二级指针
1.C语言结构体二级指针是指向结构体指针的指针。它可以用于指向存储结构体指针的变量,或者用于指向结构体指针数组的指针。
2.结构体二级指针的定义方式和普通指针的指针类似,只是需要在指针变量的类型前加上一个(芯)符号来表示二级指针。例如,假设有一个表示人员信息的结构体Person以及一个结构体指针struct Person 芯,那么可以定义一个指向该指针的二级指针如下:
struct Person {
char name[20];
int age;
};
struct Person *personPtr; // 结构体指针
struct Person **personPtrPtr; // 结构体二级指针
上述代码中,我们定义了一个名为personPtrPtr的结构体二级指针,它可以存储指向struct Person芯类型的指针变量的地址。
3.通过结构体二级指针,可以通过两次解引用操作来访问和操作结构体的成员变量。例如:
struct Person {
char name[20];
int age;
};
struct Person person1;
struct Person *personPtr = &person1; // 结构体指针
struct Person **personPtrPtr = &personPtr; // 结构体二级指针
(*personPtrPtr)->age = 25; // 第一层解引用得到结构体指针,第二层解引用访问成员变量
在上述代码中,(芯personPtrPtr)->age 表示通过结构体二级指针 personPtrPtr,首先解引用得到结构体指针 personPtr,然后再解引用结构体指针 personPtr 来访问 age 成员变量。
4.结构体二级指针通常在需要修改指向指针的地址的情况下使用,例如在函数中通过指针参数修改结构体指针的内容或者创建动态的结构体指针数组。它提供了更灵活的方式来操作结构体指针和结构体指针数组。
2.用结构体二级指针完成选民系统
1.内存指向图
2.程序代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
时间: 2023年7月14日22:57:08
程序功能:结构体二级指针
*/
struct Voter //定义一个选票结构体
{
char name[32];
int tickets;
};
void initVoter(struct Voter **pxm,int *pn)
{
int i;
if(*pxm == NULL)
{
puts("请输入有几个候选人。");
scanf("%d",pn);
*pxm = (struct Voter*)malloc(*pn * sizeof(struct Voter));
}
for(i=0; i<*pn; i++)
{
(*pxm)->tickets = 0;
printf("请输入第%d个候选人的名字。\n",i+1);
scanf("%s",(*pxm)->name); //注意*pxm加括号,不用挑战编译器的优先级和主管看代码的优先
(*pxm)++; //级
}
*pxm = *pxm - *pn;
}
void outputVoter(struct Voter *p,int len)
{
int i;
puts("姓名\t得票数\t");
for(i=0; i<len; i++)
{
printf("%s\t%d \n",p->name,p->tickets);
p++;
}
}
int singTickets(struct Voter *p,int len)
{
char tmpName[32];
int i;
int j;
int person;
int mark; //废票判断变量
int wasteTickets = 0;
struct Voter *pbak = p; //定义一个结构体指针变量pbak指向结构体指针p的首地址。
//puts("第二步进行投票和唱票环节。\n\n");
puts("请输入参与投票的人数。");
scanf("%d",&person);
for(i=0; i<person; i++)
{
mark = 0; //mark不能在定义时赋值0,如果赋值0,后面的废票判别永远不会执行
memset(tmpName,'\0',sizeof(tmpName));
puts("请输入你支持谁。");
scanf("%s",tmpName);
p = pbak;
for(j=0; j<len; j++)
{
if(strcmp(tmpName,p->name) == 0)
{
p->tickets++;
mark = 1;
}
p++;
}
if(mark == 0) //废票判断
{
puts("候选人无此人,选票无效");
wasteTickets++;
}
}
return wasteTickets;
}
struct Voter* getMax(struct Voter *p,int len)
{
int i;
struct Voter* max;
max = p;
for(i=0; i<len; i++)
{
if(max->tickets < p->tickets)
{
max = p; //把xm[i]结构体赋给max结构体,实现替代关系
}
p++; //***注意p++不能乱加,不然会出错***
}
return max;
}
int main()
{
struct Voter *xm = NULL;
struct Voter *result;
int total = 0;
int wasteTickets;
initVoter(&xm,&total);
printf("total = %d\n",total);
wasteTickets = singTickets(xm,total);
outputVoter(xm,total);
printf("废票为%d\n",wasteTickets);
result = getMax(xm,total);
printf("%s以%d票当选!!废票%d\n",result->name,result->tickets,wasteTickets);
return 0;
}
/*
int *pt = &total; //定义一个指针变量pt指向变量tatal
struct Voter **pxm = &xm; //定义一个结构体二级指针变量pxm指向结构体指针变量xm
//二级指针:是否是存放指针变量地址
int i;
if(*pxm == NULL)
{
puts("请输入有几个候选人。");
scanf("%d",pt);
*pxm = (struct Voter*)malloc(*pt * sizeof(struct Voter));
}
for(i=0; i<*pt; i++)
{
(*pxm)->tickets = 0;
printf("请输入第%d个候选人的名字。\n",i+1);
scanf("%s",(*pxm)->name); //注意*pxm加括号,不用挑战编译器的优先级和主管看代码的优先
(*pxm)++; //级
}
*pxm = *pxm - *pt; //记得指针偏移后回来。
*/
4.联合体和共用体
1.什么是共用体
C语言中的共用体(Union)是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。共用体可以包含多个成员变量,但任何给定时间只能保存其中的一个成员变量的值。
2.内存空间
共用体的内存分配是基于其最大成员的大小。这是因为共用体的多个成员共享同一块内存空间。因此,共用体的大小等于最大成员的大小。
3.与结构体的区别
1.结构体元素有各自单独空间共用体元素共享空间,空间大小有最大类型确定
2.结构体元素互不影响共用体赋值会导致覆盖
3.程序代码
#include <stdio.h>
/*
时间: 2023年7月15日23:25:55
程序功能:初识联合体共用体
*/
struct TestS
{
int idata;
char cdata;
double ddata;
};
union TestU //定义一个联合体共用体TestU
{
int idata;
char cdata;
double ddata;
};
int main()
{
struct TestS t1;
union TestU u1;
puts("程序功能:初识联合体共合体\n\n");
printf("结构体t1的大小为 %d字节\n",sizeof(t1));
printf("联合体u1的大小为 %d字节\n",sizeof(u1));
puts("\n");
puts("下面输出结构体变量的地址。\n");
printf("idata的地址为:0x%p\n",&t1.idata);
printf("cdata的地址为:0x%p\n",&t1.cdata);
printf("ddata的地址为:0x%p\n",&t1.ddata);
puts("\n");
puts("下面输出联合体变量的地址。\n");
printf("idata的地址为:0x%p\n",&u1.idata);
printf("cdata的地址为:0x%p\n",&u1.cdata);
printf("ddata的地址为:0x%p\n\n",&u1.ddata);
puts("结论如下:");
puts("联合体:同一个内存空间存放类型不同,不同类型的变量共享一块空间。\n");
puts("结构体元素有各自单独空间,共用体元素共享空间,空间大小有最大类型确定。\n");
puts("union TestU //定义一个联合体共用体TestU\n");
return 0;
}
4.使用时注意数据覆盖
以下代码是使用共用体数据覆盖示例
#include <stdio.h>
/*
时间: 2023年7月16日00:54:05
程序功能:共用体数据覆盖问题
*/
struct TestS
{
int idata;
char cdata;
double ddata;
};
union TestU //定义一个联合体共用体TestU
{
int idata;
char cdata;
double ddata;
};
int main()
{
struct TestS t1;
union TestU u1;
t1.idata = 10;
t1.cdata = 'c';
t1.ddata = 15.69;
u1.idata = 10;
u1.cdata = 'c';
u1.ddata = 15.69;
puts("程序功能:共用体数据覆盖问题\n\n");
printf("结构体t1的大小为 %d字节\n",sizeof(t1));
printf("联合体u1的大小为 %d字节\n",sizeof(u1));
puts("\n");
puts("下面输出结构体变量的地址。\n");
printf("idata的地址为:0x%p\n",&t1.idata);
printf("cdata的地址为:0x%p\n",&t1.cdata);
printf("ddata的地址为:0x%p\n",&t1.ddata);
puts("\n");
puts("下面输出联合体变量的地址。\n");
printf("idata的地址为:0x%p\n",&u1.idata);
printf("cdata的地址为:0x%p\n",&u1.cdata);
printf("ddata的地址为:0x%p\n\n",&u1.ddata);
puts("\n");
puts("下面输出结构体变量的值。\n");
printf("idata的值为:%d\n",t1.idata);
printf("cdata的值为:%c\n",t1.cdata);
printf("ddata的值为:%lf\n\n",t1.ddata);
puts("\n");
puts("下面输出共用体变量的值。\n");
printf("idata的值为:%d\n",u1.idata);
printf("cdata的值为:%c\n",u1.cdata);
printf("ddata的值为:%lf\n\n",u1.ddata);
puts("\n问题分析:");
puts("1.共用体元素共享空间,空间大小有最大类型确定。");
puts("2.数据赋值会出现覆盖,输出乱码。");
return 0;
}
5.联合体/共用体应用
1.使用共用体完成如下题目:
有若干个人员的数据,其中有学生和老师。学生的数据包括姓名,号码,性别,职业,班级。教师的数据包括姓名,号码,性别,职业,职务要求用同一个表格来处理。
2.程序代码
#include <stdio.h>
/*
时间: 2023年7月16日01:47:37
程序功能:有若干个人员的数据,其中有学生和老师。学生的数据包括姓名,号码,性别,职业,班级。
教师的数据包括姓名,号码,性别,职业,职务要求用同一个表格来处理。
*/
struct Information //结构体联合体结合定义
{
char name[32];
int age;
char career; //职业
int number; //号码
union
{
int calss;
char subject[32]; //学科
}mes;
};
int main()
{
struct Information in[2];
int i;
puts("程序功能:有若干个人员的数据,其中有学生和老师。学生的数据包括姓名,号码,性别,");
puts("职业,班级。教师的数据包括姓名,号码,性别,职业,职务要求用同一个表格来处理。\n");
for(i=0; i<2; i++)
{
puts("请输入你的职业。s——学生,t——老师");
scanf("%c",&in[i].career);
if(in[i].career == 's')
{
puts("请输入学生的姓名");
scanf("%s",in[i].name);
puts("请输入学生的年龄");
scanf("%d",&in[i].age);
puts("请输入学生的号码");
scanf("%d",&in[i].number);
puts("请输入学生的班级");
scanf("%d",&in[i].mes.calss);
}
else
{
puts("请输入老师的姓名");
scanf("%s",in[i].name);
puts("请输入老师的年龄");
scanf("%d",&in[i].age);
puts("请输入老师的号码");
scanf("%d",&in[i].number);
puts("请输入老师的学科");
scanf("%s",in[i].mes.subject);
}
getchar(); //吸收多余的回车
}
puts("姓名\t年龄\t职业(s/t)\t号码\t班级/学科 ");
for(i=0; i<2; i++)
{
if(in[i].career == 's')
{
printf("%s\t%d\t%c\t\t%d\t%d \n",
in[i].name,in[i].age,in[i].career,in[i].number,in[i].mes.calss);
}
else
{
printf("%s\t%d\t%c\t\t%d\t%s \n",
in[i].name,in[i].age,in[i].career,in[i].number,in[i].mes.subject);
}
}
return 0;
}
5.枚举类型
1.什么是枚举类型
1.C语言中的枚举类型(Enum)是一种用于定义命名常量的特殊数据类型。枚举类型允许你定义一组具有特定含义的符号常量,以提高代码的可读性和可维护性。
2.枚举类型的定义使用关键字 enum,后跟一个标识符以及一对花括号括起来的枚举常量列表。每个枚举常量表示一个特定的取值,称为枚举成员。
3.以下是一个示例,展示如何定义和使用枚举类型:
enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER
};
enum Season currentSeason; // 声明一个枚举类型的变量
currentSeason = SUMMER; // 赋值为枚举成员SUMMER
在上述示例中,我们定义了一个枚举类型Season,包含四个枚举成员:SPRING、SUMMER、AUTUMN和WINTER。然后,我们声明了一个枚举类型的变量currentSeason,并将其赋值为枚举成员SUMMER。
4.通过使用枚举类型,你可以在代码中使用有意义的符号常量来表示各种状态、选项、标志或其他相关值。这使得代码更易读、更易理解,减少了出错的可能性。
2.怎么定义枚举类型
1.列表中的名字,可以自己定义,无需像变量一样,去申请。C编译器把它当成常量处理,也称枚举常量
enum WeekDay {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
//enum :枚举类型关键字。WeekDay为枚举名,{}内为枚举元素,元素之间用逗号隔开。括号后记得加分号
3.枚举变量
1.只限列表中的集中情况,但底层像整型数,可以赋字符,数值。下面是演示代码
#include <stdio.h>
/*
时间: 2023年7月16日22:31:21
程序功能:枚举类型
*/
enum WeekDay {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
//enum :枚举类型关键字。WeekDay为枚举名,{}内为枚举元素,元素之间用逗号隔开。
int main()
{
enum WeekDay w;
w = kkk;
printf("w = %d\n",w);
return 0;
}
2.报错类型
Enumeration_Type.c:11:6: error: 'kkk' undeclared (first use in this function)
w = kkk;
^~~
Enumeration_Type.c:11:6: note: each undeclared identifier is reported only once for each function it appears in
Enumeration_Type.c:11:6:错误:未声明“kkk”(首次在此函数中使用)
w=kkk;
Enumeration_Type.c:11:6:注意:每个未声明的标识符对于它出现在中的每个函数只报告一次
3.值默认从0开始,枚举元素不能被赋值,虽然瞅着像变量名。下面是演示代码
#include <stdio.h>
/*
时间: 2023年7月16日22:31:21
程序功能:枚举类型
*/
enum WeekDay {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
//enum :枚举类型关键字。WeekDay为枚举名,{}内为枚举元素,元素之间用逗号隔开。
int main()
{
enum WeekDay w;
Monday = 10;
w = Monday;
printf("w = %d\n",w);
return 0;
}
4.报错类型
Enumeration_Type.c: In function 'main':
Enumeration_Type.c:11:9: error: lvalue required as left operand of assignment
Monday = 10;
Enumeration_Type.c:在函数“main”中:
Enumeration_Type.c:11:9:错误:赋值的左操作数需要左值
Monday=10;
5.可以指定列表中枚举的值。以下是代码演示
#include <stdio.h>
/*
时间: 2023年7月16日22:31:21
程序功能:枚举类型
*/
enum WeekDay {Monday=10,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
//enum :枚举类型关键字。WeekDay为枚举名,{}内为枚举元素,元素之间用逗号隔开。
int main()
{
enum WeekDay w;
w = Monday;
printf("w = %d\n",w);
return 0;
}
4.可以直接忽略枚举类型名,直接定义枚举变量
代码演示
#include <stdio.h>
/*
时间: 2023年7月16日22:31:21
程序功能:枚举类型
*/
enum {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday}w1,w2;
//enum :枚举类型关键字。WeekDay为枚举名,{}内为枚举元素,元素之间用逗号隔开。
int main()
{
w1 = Monday;
w2 = Tuesday;
printf("w1 = %d\n",w1);
printf("w2 = %d\n",w2);
return 0;
}
6.typedef关键字
1.什么是typedef关键字
1.C语言中的typedef关键字是一个用于为已有数据类型创建新的名称(别名)的关键字。通过typedef,你可以定义一种自定义的数据类型,使得代码更加可读和易于维护。
2typedef的基本语法如下:
typedef type newname;
其中,type是已有的数据类型,newname是你定义的新类型名称。通过这种方式,你可以为已有的数据类型创建一个别名,从而使用新的名称来代替原始类型名称。
3.以下是一些示例,展示如何使用typedef关键字:
typedef int Length; // 定义一个新的类型名称Length,表示int类型
Length x, y, z; // 使用新类型名称Length声明变量
typedef struct {
char name[20];
int age;
} Person; // 定义一个新的类型名称Person,表示某个结构体类型
Person person1; // 使用新类型名称Person声明结构体变量
typedef int* IntPtr; // 定义一个新的类型名称IntPtr,表示int指针类型
IntPtr p1; // 使用新类型名称IntPtr声明指针变量
4.通过typedef关键字,你可以更直观地表示数据类型的含义,简化代码的可读性。它可以用于任何数据类型,包括基本数据类型、结构体类型、指针类型等。在编写复杂的代码时,typedef能够减少拼写错误和提高代码的可维护性。
2.typedef关键字作用——给已有的变量类型起名字
以下是代码演示
#include <stdio.h>
/*
时间: 2023年7月16日23:24:01
程序功能:初识typedef
*/
//1.在单片机中常这样定义
typedef unsigned int u8;
typedef int u16;
typedef int arr[10];
int main()
{
u8 a;
a = 10;
arr b;
b[0] = 100;
printf("a = %d\n",a);
printf("b[0] = %d\n",b[0]);
return 0;
}
3.typedef关键字作用——用于结构体中
1.一般配合结构体使用,方便嘛,不要每次都要struct开头。以下是代码元素
#include <stdio.h>
/*
时间: 2023年7月16日23:24:01
程序功能:初识typedef
*/
//2.用于与结构体结合
struct Test
{
int data;
int data2;
};
typedef struct Test T; //少用
typedef struct //一般用这种形式。
{
int idata;
int idata2;
}Demo;
int main()
{
T c;
c.data = 1000;
Demo d;
d.idata = 10000;
printf("c.data = %d\n",c.data);
printf("d.idata = %d\n",d.idata);
return 0;
}
4.typedef关键字应用——输出人员信息
以下是程序代码
#include <stdio.h>
/*
时间: 2023年7月17日00:15:46
程序功能:typedef应用
*/
typedef struct
{
char name[32];
int num;
char sex[32];
}people,*Ppeople; //people普通变量,*Ppeople指针变量。
void printInfo(people p) //形参为普通结构体变量
{
printf("%s\t%d\t%s \n",p.name,p.num,p.sex);
}
void printInfo2(Ppeople p) //形参为结构体指针变量类型1
{
printf("%s\t%d\t%s \n",p->name,p->num,p->sex);
}
void printInfo3(people *p) //形参为结构体指针变量类型2
{
printf("%s\t%d\t%s \n",p->name,p->num,p->sex);
}
int main()
{
people p1 = {"小美",1,"女"};
people p2 = {"小刚",2,"男"};
puts("\n程序功能:typedef应用\n");
puts("\n姓名\t编号\t性别");
printInfo(p1);
printInfo(p2);
Ppeople pp1 = &p1;
Ppeople pp2 = &p2;
printInfo2(pp1);
printInfo2(pp2);
people *pp3 = &p1;
people *pp4 = &p2;
printInfo3(pp3);
printInfo3(pp4);
return 0;
}
结束语
您能在百忙之中抽出时间看到这里,我很感谢,也很高兴。结构体的难点在于指针章节指针函数,指针传参。只要指针章节学得懂,其实是很简单的。