C_结构体

结构体引入:

为什么要引入结构体?

如果没有结构体的话就只能 int char float 单独去定义,不是一个整体,利用结构体定义数据类型可以将这些数据都融合到一起(类似一个集合),就可以模拟实现多一的数据类型。(类比数组,数组是相同的数据类型集合到一起,结构体是不同的数据类型集合到一起)

定义一个结构体:

编程练习:如何定义一个结构体
#include <stdio.h>
//定义一个结构体

// struct 结构体函数
// 表示一个名为学生消息(student)的结构体
struct Student{
	
	int student_name;  //学号
	char mane{32];   // 学生名
	
	int age;         // 年龄
	double score;   // 成绩
	
};
// struct 结构体函数
// 定义了一个年月日的结构体
struct Day{
	
	int year;  // 年
	int month;  // 月
	int day;	// 日
};

int main(){
		
	return 0;
}
编程练习:结构体变量的定义和访问
#include <stdio.h>
#include <string.h>
//定义一个结构体

// struct 结构体函数
// 表示一个名为学生消息(student)的结构体
struct Student
	{
	
		int student_name;  //学号
		char mane[32];   // 学生名
		
		int age;         // 年龄
		double score;   // 成绩
	
	};


// struct 结构体函数
// 定义了一个年月日的结构体
struct Day
{
	
	int year;  // 年
	int month;  // 月
	int day;	// 日

};


int main(){
	
	
	
	struct Student stu1;    //struct Student就相当于int   stu1  相当于一个变量。
	struct Student stu2 = {2,"王二麻子",24,87.9};
	
	
	stu1.student_name = 1;  //学号
	
	strcpy(stu1.mane,"liu1xiaglong");    //给字符串赋值用字符串拷贝  姓名
	
	stu1.age = 10;              //点运算符来访问结构体中的成员变量(域)
	stu1.score=98.5;
	
	           
	
	printf("学生的学号是%d,学生姓名%s,学生的年龄%d,学生的成绩%lf\n",stu1.student_name,stu1.mane,stu1.age,stu1.score);
	
	printf("学生的学号是%d,学生姓名%s,学生的年龄%d,学生的成绩%lf\n",stu2.student_name,stu2.mane,stu2.age,stu2.score);
	 
	return 0;
}

编程练习:输入两个学生的名字,学号,成绩等输出成绩高的学生的信息

#include <stdio.h>
#include <string.h>

// 定义一个名为Student的结构体用于存储学生信息
struct Student {
    int student_number;     // 学号
    char student_name[32];  // 学生姓名
    char student_home[50];  // 家庭地址
    int age;                // 年龄
    double score;           // 成绩
};

int main() {
    // 声明两个Student结构体变量用于存储两个学生的信息
    struct Student stu1;
    struct Student stu2;
    
    // 声明一个Student结构体变量用于存储成绩较高的学生信息
    struct Student score1;

    // 提示用户输入第一个学生的详细信息
    printf("请输入学生1的:学号 ,姓名,家庭地址,年龄 ,成绩\n");

    // 获取第一个学生的数据
    scanf("%d%s%s%d%lf", &stu1.student_number, stu1.student_name, stu1.student_home, &stu1.age, &stu1.score);

    // 提示用户输入第二个学生的详细信息
    printf("请输入学生2的:学号 ,姓名,家庭地址,年龄 ,成绩\n");

    // 获取第二个学生的数据
    scanf("%d%s%s%d%lf", &stu2.student_number, stu2.student_name, stu2.student_home, &stu2.age, &stu2.score);

    // 输出第一个学生的详细信息
    printf("学生号%d,学生姓名%s,家庭地址%s,学生年龄%d,学生成绩%lf\n",
        stu1.student_number, stu1.student_name, stu1.student_home, stu1.age, stu1.score);

    // 输出第二个学生的详细信息
    printf("学生号%d,学生姓名%s,家庭地址%s,学生年龄%d,学生成绩%lf\n",
        stu2.student_number, stu2.student_name, stu2.student_home, stu2.age, stu2.score);

    // 比较两个学生的成绩
    if(stu1.score < stu2.score) {
        // 如果第二个学生的成绩较高,输出他们的详细信息
        printf("成绩好的学生是:学生号%d,学生姓名%s,家庭地址%s,学生年龄%d,学生成绩%lf\n",
            stu2.student_number, stu2.student_name, stu2.student_home, stu2.age, stu2.score);
    } else {
        // 如果第一个学生的成绩较高或相等,输出他们的详细信息
        printf("成绩好的学生是:学生号%d,学生姓名%s,家庭地址%s,学生年龄%d,学生成绩%lf\n",
            stu1.student_number, stu1.student_name, stu1.student_home, stu1.age, stu1.score);
    }

    // 初始将第一个学生的信息赋值给score1
    score1 = stu1;

    // 再次比较成绩以更新score1为成绩较高的学生
    if(stu1.score < stu2.score) {
        score1 = stu2;
    }

    // 输出存储在score1中的成绩较高的学生的详细信息
    printf("成绩好的学生是:学生号%d,学生姓名%s,家庭地址%s,学生年龄%d,学生成绩%lf\n",
        score1.student_number, score1.student_name, score1.student_home, score1.age, score1.score);

    return 0;
}

结构体数组:

它与前面讲的数值型数组基本上一模一样的,只不过需要注意的是,结构体数组的每一个元素都是一个结构体类型的变量,都包含结构体中所有的成员项。

定义结构体数组的方法很简单,同定义结构体变量是一样的,只不过将变量改成数组。或者说同前面介绍的普通数组的定义是一模一样的,如:

struct Student stu[10]; struct Student(结构体名) stu[10]; (数组名)

这就定义了一个结构体数组,共有 10 个元素,每个元素都是一个结构体变量,都包含所有的结构体成员。
结构体数组的引用与引用一个结构体变量在原理上是一样的。只不过结构体数组中有多个结构体变量,我们只需利用 for 循环来遍历结构体数组中的元素。

编程练习:结构体数组应用
#include <stdio.h>
#include <string.h>
//定义一个结构体数组

// struct 结构体函数
// 表示一个名为学生消息(student)的结构体
struct Student
	{
	
		int student_number;  //学号
		char student_mane[32];   // 学生名
		char student_home[50];    //家庭地址
		int age;         // 年龄
		double score;   // 成绩
	
	};
 
int main()
{ 

		// 定义结构体数组
	struct Student srry[3] = {
		{20140656,"玛卡巴卡","西安",18,98.5},
		{20140678,"唔西迪兮","成都",28,97.5},
		{20140690,"依古比古","北京",19,95.5}
		};
		
	int i;
	int len = sizeof(srry)/sizeof(srry[0]);   //获取大小
	
	// 下标法访问
	for(i = 0;i<len;i++){
		// 输出结构体
		printf("学生号%d,学生姓名%s,家庭地址%s,学生年龄%d,学生成绩%lf\n",
		srry[i].student_number,srry[i].student_mane,srry[i].student_home,srry[i].age,srry[i].score);
	
	}
	
	return 0;
}

编程练习:选票系统
#include <stdio.h>
#include <string.h>

struct XuanMin
{
	char name[32];//定义了姓名
	
	int tickets;   // 票数
};

int main()
{
	struct XuanMin xm[3];   // 结构体数组
	
	struct XuanMin max;   //记录最高票
	
	int feiPiao = 0;   // 记录废票数目
	int i;   // 定义循环变量 i;
	int len;      // 记录结构体数组xm的长度
	int j;  // 定义循环变量 j;
	int mark = 0;       //标记变量,判断是否投给了候选人。
	
	int total = 5;         // 共计5票
	char tmpName[32];       // 临时存储选民姓名的字符串
	
	//初始化选民信息
	len = sizeof(xm)/sizeof(xm[0]);    // 计算结构体数组xm的长度
	for(i = 0; i<len; i++){          // 初始化选民信息的循环
		xm[i].tickets = 0;         // 将每位候选人的票数初始化为0;
		printf("请输入第%d个选民的名字:\n",i+1);    
		scanf("%s",xm[i].name); //输入第`i+1`个选民的名字。
	}
	//唱票环节  投票环节的循环,共进行5次
	for(i=0;i<5;i++){
		
		mark = 0;  //重置标记变量为0
		printf("请输入你投给谁:\n");  
		//将全部字符赋值成\0;
		memset(tmpName,'\0',sizeof(tmpName)); //每次清空一下 临时姓名变量。
		scanf("%s",tmpName);//输入选中的选民名字,像拆开一个选票,看到名字一样
		for(j = 0;j<len; j++){ //遍历选民数组,查找是否有匹配的候选人。
			if(strcmp(tmpName, xm[j].name) == 0){  //如果输入的选民名字匹配候选人的名字
				xm[j].tickets++;  //该候选人得票数加1。
				mark  = 1;   //标记为投票成功。
			}
		}
		if(mark == 0){  //如果没有匹配的候选人。
			printf("没有此候选人,放弃\n");  //输出提示信息。
			feiPiao++;  //废票数目加1。
		}
	}
	//公布结果
	for(i=0;i<len;i++){  //遍历选民数组,打印每位候选人的名字和得票数。
		printf("名字:%s,票数:%d\n",xm[i].name,xm[i].tickets);
	}
	max = xm[0];  //默认第一位候选人为得票最多者。
	for(i=1;i<len;i++){ //遍历选民数组,比较得票数找出最终获胜者。
		if(max.tickets < xm[i].tickets){   //如果当前候选人的票数大于最高票数。

			max = xm[i]; //更新最高票数的候选人信息。
		}
	}
	printf("%s以%d票当选!!废票是%d\n",max.name,max.tickets,feiPiao);
}

结构体指针:

在C语言中,结构体(struct)的变量和普通变量一样,它们在内存中也是按照顺序存储的,因此它们的地址也是连续的。这与普通的指针概念密切相关,因为指针可以用来访问结构体变量的成员。

例如,考虑如下的结构体定义和变量声明:


struct Point {
    int x;
    int y;
};

struct Point pt1;
struct Point pt2;

假设 pt1 和 pt2 是 struct Point 类型的变量,它们在内存中的布局可能如下所示(这里只是示意,并非真实的内存布局):

yaml

Memory:
Address   Variable  Value
    1000      pt1.x     0
    1004      pt1.y     0
    1008      pt2.x     0
    1012      pt2.y     0

在这个例子中,假设 pt1 和 pt2 分别占据了连续的内存空间,且每个成员变量也是按顺序存放的。因此,pt1 的地址是 1000,pt2 的地址是 1008。这表明结构体的变量地址是连续的,正如普通变量的地址是连续的一样。

在处理结构体时,可以使用指针来访问结构体变量的成员,例如:


struct Point *ptr = &pt1;

这里,ptr 是一个指向 struct Point 类型的指针,它指向了 pt1 的地址。通过指针 ptr 可以访问和修改 pt1 的成员变量 x 和 y:


ptr->x = 10;
ptr->y = 20;

这与直接使用 pt1.x 和 pt1.y 是等效的,因为指针 ptr 指向了 pt1 的地址,可以通过 ptr 来间接地访问 pt1 的成员。

结构体变量在内存中是连续存储的,这使得它们的地址也是连续的。指针可以用来访问结构体变量的成员,这种方式与普通变量和指针的操作是一致的。

变量的访问有两种方式:1.变量名访问;2.通过地址来访问,结构体也一样,可以通过变量名和地址来访问结构体变量,因此引入结构体指针。

编程练习:结构体指针的定义及访问
/*
	结构体指针的定义和应用
*/
 
#include <stdio.h>
 
struct Test
{
	int indata;
	char cdata;
};
 
int main()
{
	int idata = 10;
	int *pi = &idata;	//之前定义指针的方法
	
	char cdata = 'R';
	char *pc = &cdata;	//之前定义指针的方法
	
	
  //变量类型 变量名字 变量值
	struct Test T1 = {20,'E'};   //变量类型 变量名字 变量值 变量地址
	
	               //变量地址
	struct Test *pt = &T1;    //本质与普通指针无任何差别。结构体的变量地址也是连续的
	
	printf("indata = %d,cdata = %c\n",T1.indata,T1.cdata);	
					//之前学到的用变量名访问结构体变量方法
	
	printf("indata = %d,cdata = %c\n",pt->indata,pt->cdata);	
					//用结构体指针访问结构体变量的方法,用"->"取代点运算符
					
	 pt ->cdata = 'L' ;//通过指针改变结构体的内容
	 
	 
	printf("indata = %d,cdata = %c\n",T1.indata,T1.cdata);	
					//之前学到的用变量名访问结构体变量方法
	
	printf("indata = %d,cdata = %c\n",pt->indata,pt->cdata);	
					//用结构体指针访问结构体变量的方法,用"->"取代点运算符
	return 0;
}

/*
	用结构体指针来遍历数组
*/
 
#include <stdio.h>
 
struct Student
{
	int num;
	char name[32];
	char sex[4];
	char address[32];
	int age;
	double score;
};
 
int main()
{
	struct Student stu[3] = {   //定义一个结构体数组
		{20140656,"玛卡巴卡","男","山西",18,98.5},
		{20140678,"唔西迪兮","女","河北",18,97.5},
		{20140690,"依古比古","男","北京",18,95.5}
	};
	struct Student *p;   // 定义一个指针
	
	p = stu;   //指针赋值
	
	int i;
	int len = sizeof(stu)/sizeof(stu[0]);
	
	
	// 通过循环访问结构体
	for(i=0;i<len;i++)
		
	
	{/*      下标输出法
	
		printf("num:%d name:%s sex:%s address:%s age:%d score:%.1lf\n",
				stu[i].num,stu[i].name,stu[i].sex,stu[i].address,stu[i].age,stu[i].score);
				*/
				
		printf("num:%d name:%s sex:%s address:%s age:%d score:%.1lf\n",
				p->num,p->name,p->sex,p->address,p->age,p->score);
		p++;  // 看成父地址 ++向下移动
	}
	
	/*	使用指针遍历数组时,一次遍历指针会移到数组的尾巴,
		所以当要再一次遍历时,要重新指向数组的首地址。
		*/
	p = stu;	//一定要复位。
	
	for(i=0;i<len;i++)
	{
		printf("num:%d name:%s sex:%s address:%s age:%d score:%.1lf\n",
				p->num,p->name,p->sex,p->address,p->age,p->score);
		p++;
	}
	
	
	
	return 0;
}

注意:如果使用结构体指针遍历数组后想要再次遍历数组的时候,要把指针再次指向数组首地址!!!要不然就会出现以下等问题:

编程练习:结构体指针应用02
#include <stdio.h>
#include <string.h>

// 定义候选人结构体
struct XuanPiao
{
	char name[132]; // 姓名字段
	int piao; // 票数字段
};

int main()
{   
	// 初始化变量
	struct XuanPiao stu1[3]; // 声明候选人结构体数组,包括3个候选人
	struct XuanPiao max; // 存储得票最高的候选人信息
	struct XuanPiao *p = stu1;  // 定义一个指针,指向结构体数组
	
	int i;
	int len;
	int total = 5; // 投票总人数
	int j;
	char newname[125]; // 存储投票人姓名
	int feipiao = 0; // 记录废票数
	len = sizeof(stu1)/sizeof(stu1[0]); // 计算候选人数组长度

	int bluck = 0; // 用于判断投票是否有效的标志
	
	// 初始化候选人信息
	for(i = 0; i < len; i++){ 
		p->piao = 0; // 初始化候选人票数为0
		printf("请输入第%d候选人姓名\n", i + 1); 
		scanf("%s", p->name); // 输入候选人姓名
		p++; // 指针移动到下一个候选人
	}
	
	p = stu1;  // 重置指针为数组首地址
	
	// 进行投票
	for(i = 0; i < total; i++){ 
		bluck = 0; // 重置投票有效标志
		printf("请输入候选人姓名\n"); 
		memset(newname, '\0', sizeof(newname)); // 清空投票人姓名缓冲区
		scanf("%s", newname); // 输入进行投票的候选人姓名
		p = stu1;  // 重置指针为数组首地址
		 
		for(j = 0; j < len; j++){ 
			if(strcmp(newname, p->name) == 0){ 
				p->piao++; // 对应候选人票数加一
				bluck = 1; // 标记投票有效
			}
			p++; // 指向下一个候选人
		}
		 
		if(bluck == 0){ 
			printf("此人不是候选人\n");
			feipiao++; // 统计废票数
		}
	}
	
	p = stu1; // 重置指针为数组首地址
	
	// 输出候选人得票情况
	for(i = 0; i < len; i++){ 
		printf("候选人%s,%d\n", p->name, p->piao); 
		p++; // 指向下一个候选人
	}

	max = stu1[0]; // 初始化得票最高的候选人为第一个候选人
	
	p = stu1; 
	for(i = 0; i < len; i++){
		if(max.piao < p->piao){ 
			max = stu1[i]; // 找出得票最高的候选人
		}
		p++; // 指向下一个候选人
	}
	printf("%s以%d票当选,是最高票数\n", max.name, max.piao); // 输出得票最多的候选人信息
	printf("废票有%d票\n", feipiao); // 输出废票数

	return 0;
}

编程练习:结构体指针数组函数综合应用改写选票系统
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//定义了一个结构体XuanMin,包含了一个名为name的是字符数组和一个整数piao。
struct XuanMin
{
	char name[132];
	
	int piao;
};


//定义了一个返回指向XuanMin结构体的函数指针的函数initXms。该函数用于动态分配内存以存储候选人信息。
struct  XuanMin* initXms(struct XuanMin *p,int *len)   //返回一个函数指针。
{
	
	
	int i;
	if(p == NULL){
	printf("请输入有几个人参选\n");
	scanf("%d",len);
	
	
	//       用来计算需要分配的内存空间大小,(n乘以结构体的大小{sizeof(sttuct XuanMin))  }  
	p = (struct XuanMin*)malloc(*len*sizeof(struct XuanMin));
	     //   (struct XuanMin*)   malloc返回的void类型指针转换为指向XuanMin结构体类型的指针
	}
	for(i = 0;i<*len;i++){
		 // for循环
		
		p->piao = 0; // 初始化候选人票数为0
		
		printf("请输入第%d候选人姓名\n", i + 1);  // 原样输出
		scanf("%s", p->name); // 输入候选人姓名
		
		p++; //父地址++,指针移动到下一个候选人
	
	}
	return p-*len;  //因为前面那个for循环 P++ 到尾巴了,需要重置指针为数组首地址
}

void printfXms(struct XuanMin *p,int len)
{
	int i;
	for(i = 0;i<len;i++){
		 // for循环
		
		// 初始化候选人票数为0
		
		printf("候选人%s,%d\n", p->name, p->piao); // 输出每位候选人得票情况
	
		p++; //父地址++,指针移动到下一个候选人
	
	}
}

int  doVot(struct XuanMin *p,int len)
{
	int i;
	int j;
	int bluck;
	int feipiao = 0;
	char newname[125];
	struct XuanMin *pp =p;

	for(i = 0; i < 5; i++){ //for循环  定义了5张票数
	
		bluck = 0;   // 用于判断投票是否有效的标志
		printf("请输入候选人姓名\n");   //原样输出
		
		memset(newname, '\0', sizeof(newname));   // 清空投票人姓名缓冲区
		
		scanf("%s", newname); // 输入进行投票的候选人姓名
		
		p = pp;  // 重置指针为数组首地址
		 
		for(j = 0; j < len; j++){   // for1循环
		
			if(strcmp(newname, p->name) == 0){   //通过strcmp函数进行比较,投票人和候选人姓名相等,就等于0
			
				p->piao++; // 对应候选人票数加一,就对当前候选人票数++
				
				bluck = 1; // 标记投票有效
			}
			p++;  //父地址++  指针移动到下一个候选人
		}
		 
		if(bluck == 0){   //如果投票人和候选人姓名不相等,就向下执行。
		
			printf("此人不是候选人\n");
			
			feipiao++; // 统计废票数
		}
	}
	return feipiao;  //返回废票数
}

// 获取得票最高的候选人
struct XuanMin* getMax(struct XuanMin *p, int len)
{
    struct XuanMin* max;
    max = p; // 初始化得票最高的候选人为第一个候选人

    for(int i = 0; i < len; i++)
    {
        if(max->piao < p->piao)
        {
            max = p; // 找出得票最高的候选人
        }
        p++; // 指针移动到下一个候选人
    }
    return max; // 返回得票最高的候选人
}


// 主函数
int main()
{
    struct XuanMin *Xm = NULL; // 定义候选人结构体指针并初始化为NULL
    struct XuanMin *final; // 定义最终当选候选人指针

    int total = 0; // 声明变量total用于存储候选人总数
    Xm = initXms(Xm, &total); // 初始化候选人信息

    printfXms(Xm, total); // 打印候选人信息

    int feipiao = doVot(Xm, total); // 模拟投票
    printfXms(Xm, total); // 再次打印候选人信息

    final = getMax(Xm, total); // 获取得票最高的候选人
    printf("%s以%d票当选,是最高票数\n", final->name, final->piao); // 输出当选候选人信息
    printf("废票有%d票\n", feipiao); // 输出废票数

    return 0; // 返回0表示程序正常结束
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct XuanPiao
{
	char name[132];
	
	int piao;
};


void inname(struct XuanPiao **pxm,int *pt)
{
	//*pt = 10;  //pt 指向的是toal的地址。  *pt就是把toal地址的值取出来
	//*pxm = NULL;    //pxm 保存的是xm的地址。  *pxm保存的是xm指针的指向的地址。
	int i;
	if(*pxm == NULL){   //pxm 保存的是xm的地址。  *pxm保存的是xm指针的指向的地址。
	printf("请输入有几个人参选\n");
	scanf("%d",pt);
	
	//pxm 保存的是xm的地址。  *pxm保存的是xm指针的指向的地址。
	*pxm =(struct XuanPiao*)malloc(*pt *sizeof(struct XuanPiao));
	}
	for(i = 0;i<*pt ;i++){
		(*pxm)->piao =0;//pxm 保存的是xm的地址。  *pxm保存的是xm指针的指向的地址。
		
		printf("请输入第%d候选人姓名\n", i + 1); // 提示用户输入第i位候选人姓名
        scanf("%s", (*pxm)->name);//pxm 保存的是xm的地址。  *pxm保存的是xm指针的指向的地址。
		(*pxm)++;
	}   //pxm 保存的是xm的地址。  *pxm保存的是xm指针的指向的地址。
	
	*pxm = *pxm - *pt;
  
}

void prname(struct XuanPiao *p,int len)
{
	for(int i = 0;i<len;i++){
		
		 printf("候选人%s,%d\n", p->name, p->piao); // 输出候选人姓名和得票情况
        p++; // 指针移动到下一个候选人
    }
}




int getname(struct XuanPiao *p,int len)
{	int i;
	int feipiao = 0;
	char newname[32];
	int bluck= 0;
	int j;
	struct XuanPiao *stu1=p;
	

       

	for(i = 0;i<5;i++){
		bluck = 0;   // 用于判断投票是否有效的标志
		
		 printf("投票人\n"); 
		 
		 memset(newname, '\0', sizeof(newname));   
		 
		 scanf("%s", newname);
		 
        
    p = stu1;  
	
	for(j = 0; j < len; j++){   // for1循环
		
			if(strcmp(newname, p->name) == 0){   //通过strcmp函数进行比较,投票人和候选人姓名相等,就等于0
			
				p->piao++; // 对应候选人票数加一,就对当前候选人票数++
				
				bluck = 1; // 标记投票有效
			}
		p++;  //父地址++
	}
		 
		if(bluck == 0){   //如果投票人和候选人姓名不相等,就向下执行。
		
			printf("此人不是候选人\n");
			
			feipiao++; // 统计废票数
		}
	}
	
	
	return feipiao;  //返回废票数
	
}
struct XuanPiao* Maxame(struct XuanPiao *p,int len){
	 
	 struct XuanPiao* max ;
	 max = p;
	  for(int i = 0; i < len; i++)
    {
        if(max->piao < p->piao)
        {
            max = p; // 找出得票最高的候选人
        }
        p++; // 指针移动到下一个候选人
    }
    return max; // 返回得票最高的候选人
}


int main()
{
	
	struct XuanPiao *Xm=NULL;
	struct XuanPiao *max;
	
	int toal = 0;
	
	//struct XuanPiao **pxm = &Xm ;// 这里保存的是一级指针的地址,就是二级指针。

	//	int *pt = &toal;
	
	//*pt = 10;  //pt 指向的是toal的地址。  *pt就是把toal地址的值取出来
	//*pxm = NULL;    //pxm 保存的是xm(一级指针)的地址。  *pxm保存的是xm一级指针所指向的地址。
	
	
    
	/*打个比方,这个一级指针 xm 保存的是一个整型数8的地址。
	那么这个*pxm   就等于是这个整型数8的地址。*/

	inname(&Xm,&toal);
	
	prname(Xm,toal);
	
	int feipiao = getname(Xm,toal);
	
	prname(Xm,toal);
	
	max = Maxame(Xm,toal);
	printf("%s以%d票当选,是最高票数\n", max->name, max->piao); // 输出当选候选人信息
	printf("废票有%d票\n", feipiao); // 输出废票数
	return 0;
}

共用体/联合体引入:

共用体和结构体十分相似,是一种构造类型或复杂类型,它也可以包含多个类型不同的成员。

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

注意:结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

编程练习:共用体定义和使用

// 结构体——共用体(联合体)

/*
	共用体的定义及其注意事项
*/
 
#include <stdio.h>
 
struct TestT
{
	int indata;
	char cdata;
	double ddata;
};
 
union TestU
{
	int indata;
	char cdata;
	double ddata;
};
 
int main()
{
	struct TestT ti;
	union  TestU ui;
	printf("结构体大小是sizeof = %d\n",sizeof(ti));		//内存大于或等于所有成员的内存
	printf("共用体大小是sizeof = %d\n",sizeof(ui));		//内存大小由最大成员的内存决定
	
	ti.indata = 10;
	ti.cdata = 'a';
	ti.ddata = 20;
	
	 //结构体正常输出  
	 
	 //结构体成员的每一个都有单独的地址
	printf("indata %p,%d\n",&ti.indata,ti.indata);   
	printf("indata %p,%c\n",&ti.cdata,ti.cdata);
	printf("indata %p,%lf\n",&ti.ddata,ti.ddata);
	
	printf("-------------");
	
	ui.indata = 10;
	ui.cdata = 'a';
	//ui.ddata = 20;
	// 共同体输出占用内存空间最大的,并且将其他直全部覆盖
	
	//共用体所有成员都共用一个地址
	printf("indata %p,%d\n",&ui.indata,ui.indata);   // 输出asic码表中a的值。
	printf("indata %p,%c\n",&ui.cdata,ui.cdata);   /// 正常输出。
	//printf("indata %p,%lf\n",&ui.ddata,ui.ddata);
	
	
				
	//因为结构体成员每一个都有独立的内存空间,所以它的每一个成员都可以打印出来。互不干扰;
	//因为共用体成员每一个都是公用同一个内存空间,所以它的值会被之后一个输入的成员覆盖掉。
	return 0;
}

共用体覆盖问题
// 结构体——共用体(联合体)

/*
	共用体的定义及其注意事项
*/
 
#include <stdio.h>
 
struct TestT
{
	int indata;
	char cdata;
	double ddata;
};
 
union TestU
{
	int indata;
	char cdata;
	double ddata;
};
 
int main()
{
	struct TestT ti;
	union  TestU ui;
	printf("结构体大小是sizeof = %d\n",sizeof(ti));		//内存大于或等于所有成员的内存
	printf("共用体大小是sizeof = %d\n",sizeof(ui));		//内存大小由最大成员的内存决定
	
	ti.indata = 10;
	ti.cdata = 'a';
	ti.ddata = 20;
	
	 //结构体正常输出  
	 
	 //结构体成员的每一个都有单独的地址
	printf("indata %p,%d\n",&ti.indata,ti.indata);   
	printf("indata %p,%c\n",&ti.cdata,ti.cdata);
	printf("indata %p,%lf\n",&ti.ddata,ti.ddata);
	
	printf("-------------");
	
	ui.indata = 10;
	ui.cdata = 'a';
	//ui.ddata = 20;
	
	// 共同体输出占用内存空间最大的,并且将其他值全部覆盖,只输出内存空间最大的值。
	
	//共用体所有成员都共用一个地址
	printf("indata %p,%d\n",&ui.indata,ui.indata);   // 输出asic码表中a的值。
	printf("indata %p,%c\n",&ui.cdata,ui.cdata);   /// 正常输出。
	//printf("indata %p,%lf\n",&ui.ddata,ui.ddata);
	
	
				
	//因为结构体成员每一个都有独立的内存空间,所以它的每一个成员都可以打印出来。互不干扰;
	//因为共用体成员每一个都是公用同一个内存空间,所以它的值会被之后一个输入的成员覆盖掉。
	return 0;
}
编程练习:共用体开发案例
#include <stdio.h>      // 包含标准输入输出函数库
#include <stdlib.h>     // 包含标准库函数,如 exit() 函数

struct Person
{
	char name[32];   // 姓名,用于存储用户输入的姓名,最大长度为 31 个字符加上结尾的空字符
	int num;         // 数字,未被使用
	char sex[4];     // 性别,未被使用
	char zhiYe;      // 职业信息,用于存储用户输入的职业信息 't' 或 's'
	union
	{
		char class[8];   // 共用体中的班级信息,用于存储学生的班级名称,最大长度为 7 个字符加上结尾的空字符
		char subject[4]; // 共用体中的科目信息,用于存储老师教授的科目名称,最大长度为 3 个字符加上结尾的空字符
	} mes;              // 共用体变量
};

int main()
{
	struct Person p[2]; //定义一个包含两个Person结构体对象的数组

	int len = sizeof(p)/sizeof(p[0]); // 计算数组p的长度,这里是2
	for(int i =0;i<len;i++ )
	{
		printf("请输出你的身份: t or s!!\n"); // 输出提示信息,要求用户输入职业信息 't' 表示老师, 's' 表示学生
		scanf("%c",&(p[i].zhiYe));           // 读取用户输入的职业信息到相应结构体成员变量zhiYe
		
		if(p[i].zhiYe == 't'){               // 如果职业信息是老师
			printf("你好,老师!,请说出你的姓名\n"); // 提示老师输入姓名
			scanf("%s",p[i].name);                  // 读取老师的名字到对应成员变量name
			printf("请老师输入所教的科目\n");          // 提示老师输入所教科目
			scanf("%s",p[i].mes.subject);           // 读取老师所教科目到共用体中的成员变量subject
		}
		else if(p[i].zhiYe =='s')            // 如果职业信息是学生
		{
			printf("请学生输入名字\n");           // 提示学生输入姓名
			scanf("%s",p[i].name);                // 读取学生的名字到对应成员变量name
			printf("请学生输入所在班级\n");         // 提示学生输入班级信息
			scanf("%s",&(p[i].mes.class));        // 读取学生班级信息到共用体中的成员变量class
		}
		else                                 // 如果职业信息既不是 't' 也不是 's'
		{
			printf("你的输入有误\n");         // 输出提示信息,输入有误
		}
		getchar();                            // 读取并丢弃输入缓冲中的一个字符,防止影响后续的输入
	}
	
	for(int i=0;i<len;i++)                   // 遍历结构体数组,根据职业类型输出相应的信息
	{
		if(p[i].zhiYe == 't')               // 如果职业类型是老师
		{
			printf("老师的名字是%s,所教的科目是%s\n",p[i].name,p[i].mes.subject); // 输出老师的姓名和所教科目
		}
		else if(p[i].zhiYe =='s')           // 如果职业类型是学生
		{
			printf("学生的名字是%s,所在班级是%s\n",p[i].name,p[i].mes.class); // 输出学生的姓名和所在班级
		}
		else
		{
			exit(-1);                        // 如果职业信息既不是 't' 也不是 's',异常退出程序
		}
	}
	
	return 0;                                // 主函数返回结束
}

这段代码的功能是让用户输入老师或学生的信息,包括姓名、职业类型(老师或学生)、所在班级或所教科目,并最终将这些信息输出显示出来。共用体mes在不同情况下可以存储不同类型的数据,在本例中用来区分老师和学生的附加信息。

枚举类型

在实际编程中,有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便在后续代码中使用,比如一个星期只有七天,一年只有十二个月,一个班每周有六门课程,这时候就要用到枚举类型

编程练习:如何定义枚举类型且使用
/*
	枚举类型 如果一个变量只有几种可能的值,比如星期几,就可以用枚举
*/

#include <stdio.h>

// 1.值默认从0开始,枚举元素不能被赋值,虽然看着象变量名
enum Month
{
	Feb, Mar, Apr, May, Jun, Jul, Aug, Sept, Oct, Nov, Dec
};

// 2.可以指定列表中枚举数的值
enum Month1
{
	Jan = 5, Feb1, Mar2, Apr3, May4, Jun5, Jul6, Aug7, Sept8, Oct9, Nov0
};

// 3.可以直接忽略枚举类型名,直接定义枚举变量
enum
{
	Jan1 = 3, Feb11, Mar22, Apr33, May44, Jun55, Jul66, Aug77, Sept88, Oct99, Nov00
} m1, m2;

int main()
{
	// 1.值默认从0开始
	enum Month w;
	w = Feb;
	printf("w = %d \n", w);  // 输出0;

	// 2.可以指定列表中枚举数的值
	enum Month1 w1;
	w1 = Feb1;
	printf("w = %d \n", w1);  // 输出6;

	// 3.可以直接忽略枚举类型名,直接定义枚举变量
	m1 = Feb11;  // 4
	m2 = Nov00;   //13
	
	if (m1 < m2) // 可以进行比较
	{
		printf("我看你是钵钵鸡\n");
	}
	
	printf("m1 = %d m2 = %d\n", m1, m2);
	
	return  0;

	/*
		1.值默认从0开始,枚举元素不能被赋值,虽然瞅着象变量名
		2.可以指定列表中枚举数的值
		3.可以直接忽略枚举类型名,直接定义枚举变量
	*/
}

这段代码演示了枚举类型的基本用法,包括默认从0开始的枚举值、指定枚举数的值、以及直接定义枚举变量。枚举类型能够更直观地表示一系列相关的常量,并且可以进行比较操作。

typedef 关键字

C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,来替代系统默认的基本类型名称、数组类型名称、指针类型名称与用户自定义的结构型名称、共用型名称、枚举型名称等。一旦用户在程序中定义了自己的数据类型名称,就可以在该程序中用自己的数据类型名称来定义变量的类型、数组的类型、指针变量的类型与函数的类型等。(方便用户使用)

#include <stdio.h>

// 为基本数据类型定义别名
// 给已有的变量类型重新起一个名字。

typedef int zhengshu;   // 定义 int 的别名 zhengshu
typedef char zifu;      // 定义 char 的别名 zifu
typedef double xiaoshu; // 定义 double 的别名 xiaoshu

int main()
{
    zhengshu a = 10;  // 使用 zhengshu 定义变量 a,并赋值为 10
    printf("输出整数: a = %d \n", a);  // 输出变量 a 的值,格式为整数

    zifu c = 'H';  // 使用 zifu 定义变量 c,并赋值为 'H'
    printf("输出字符: c = %c \n", c);  // 输出变量 c 的值,格式为字符

    xiaoshu X = 99.87;  // 使用 xiaoshu 定义变量 X,并赋值为 99.87
    printf("输出小数: X = %.2lf \n", X);  // 输出变量 X 的值,格式为保留两位小数的浮点数

    return 0;  // 返回 0,表示程序正常结束
}

编程练习:typedef 使用

定义了一些基本数据类型的别名,以及结构体的别名,并展示了如何使用这些别名来声明变量和访问结构体的成员变量。

#include <stdio.h>


// 为结构体定义别名
struct Test {  
    int date;  
    int date2;  
};  
 
typedef struct Test T;   // 给 struct Test 定义别名 T

// 定义一个函数 printIndo,参数为 T 类型的结构体变量 t
void printIndo(T t){
	printf("%d\n",t.date2);
}


// 定义一个匿名结构体并给它定义别名 Demo
typedef struct
{
	int data1;
	int data2;
} Demo;

int main()
{
    /* 正常输出 */
    struct Test t1; // 声明一个名为t1的结构体变量
	
    t1.date = 10; // 为结构体变量t1的成员变量x赋值为10
    printf("%d\n", t1.date);  // 输出结构体变量 t 的成员变量 date2 的值

    T p1; // 等同于 struct Point p1;
	
    p1.date2 = 100; // 为结构体变量p1的成员变量date2赋值为100
    printIndo(p1); // 调用函数printIndo,并传入结构体变量p1


    Demo d; // 声明一个名为d的结构体变量
	
    d.data1 = 33; // 为结构体变量d的成员变量data1赋值为33
    d.data2 = 44; // 为结构体变量d的成员变量data2赋值为44
	
    printf("%d\n", d.data1); // 输出结构体变量d的成员变量data1的值


	
    return 0;
}

typedef和结构体的案列。

#include <stdio.h> // 包含标准输入输出库

// 定义一个名为Person的结构体以及一个指向Person结构体的指针类型pPerson
typedef struct
{
	int num;           // 学号
	char name[32];     // 名字,最多31个字符加上一个终止符
	char sex;          // 性别,'b'表示男,'g'表示女
} Person, *pPerson;

// 定义一个函数print1,传入一个Person结构体变量
void print1(Person p)  // 传入一个名为p的结构体变量
{
	printf("num:%d name:%s sex:%c\n", p.num, p.name, p.sex); // 打印结构体的字段
}

// 定义一个函数print3,传入一个Person结构体指针
void print3(Person *p)  // 传入一个名为p的指针,指向Person结构体
{
	printf("num:%d name:%s sex:%c\n", p->num, p->name, p->sex); // 打印结构体的字段
}

// 定义另一个函数print2,传入一个pPerson类型的指针
void print2(pPerson pp)  // 传入一个名为pp的指针,类型为pPerson(即Person*)
{
	printf("num:%d name:%s sex:%c\n", pp->num, pp->name, pp->sex); // 打印结构体的字段
}

int main()
{
	// 初始化两个Person结构体变量
	Person p1 = {2024001, "张三", 'b'};   // 定义并初始化结构体变量p1
	Person p2 = {2024005, "李四", 'g'};   // 定义并初始化结构体变量p2
	
	// 调用函数print1,传入结构体变量p1作为参数
	print1(p1);  // 打印p1的字段
	// 调用函数print1,传入结构体变量p2作为参数
	print1(p2);  // 打印p2的字段

	// 声明并初始化指向结构体的指针
	pPerson pp1 = &p1;  // 声明并初始化指针pp1,使其指向结构体变量p1
	pPerson pp2 = &p2;  // 声明并初始化指针pp2,使其指向结构体变量p2
	
	// 调用函数print2,传入指向结构体p1的指针pp1作为参数
	print2(pp1);  // 打印pp1指向的结构体p1的字段
	// 调用函数print2,传入指向结构体p2的指针pp2作为参数
	print2(pp2);  // 打印pp2指向的结构体p2的字段
	
	// 声明并初始化指向结构体的指针(使用标准指针类型)
	Person *pp3 = &p1;  // 声明并初始化指针pp3,使其指向结构体变量p1
	Person *pp4 = &p2;  // 声明并初始化指针pp4,使其指向结构体变量p2
	
	// 调用函数print3,传入指向结构体p1的指针pp3作为参数
	print3(pp3);  // 打印pp3指向的结构体p1的字段
	// 调用函数print3,传入指向结构体p2的指针pp4作为参数
	print3(pp4);  // 打印pp4指向的结构体p2的字段

	return 0; // 返回0表示程序成功执行
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值