结构体与函数的关系、共用体、枚举

主题1:结构体与函数

函数的形参类型可以为:int、double、float、char 或者数组或者指针,那么,结构体类型的变量、数组和指针当然也可以作为函数的形参,调用函数时,传递的实参类型要与形参对应即可。因为函数的形参我们前面已经讲过,采用结构体类型的变量、数组和指针作为函数的形参,操作方法及原理与前面所讲雷同,因此这里不再详细讲解,举一些实例大家练习下即可。

1.5.1结构体变量作为函数参数

一个学生的信息包括:学号、姓名和3门课成绩,要求计算并输出3门课的平均分及3门课中的成绩最大值。
采用子函数的方法来实现平均分和成绩最大值的计算。

#include<stdio.h>
#include<string.h>
struct StuScore{
    char xh[12];
    char name[12];
    double score[3];
};
double ave_score(struct StuScore t)
{
	double average;
	int i;
	for(i=0;i<3;i++)
		average+=t.score[i];
	average=average/3;
	return average;
}
double max_score(struct StuScore t)
{
	double max=t.score[0];
	int i;
	for(i=1;i<3;i++)
		if(max<t.score[i])
			max=t.score[i];
	return max;
}
int main()
{
    struct StuScore s;
    int i;
    gets(s.xh);
    gets(s.name);
    for(i=0;i<3;i++)
    	  scanf("%lf",&s.score[i]);
    printf("ave=%lf\n",ave_score(s));
    printf("max=%lf\n",max_score(s));
    return 0;
}

ave_score(s)将实参s的数据成员的值传递给形参t相对应的数据成员,也即t的xh的值和s的xh的值一样,t的name的值和s的name的值一样,当然,t的3门课的成绩也与s的3门课成绩一样。总之,t中数据成员的值来自s,这就是值传递方式。

1.5.2结构体数组作为函数参数

针对上述问题,假如咱班49个同学,要求出每个同学的3门课平均成绩,并输出平均成绩最大的那个学生的信息。

#include<stdio.h>
#include<string.h>
struct StuScore{
    char xh[12];
    char name[12];
    double score[3];
};
void input(struct StuScore t[],int n)
{
	int i,j;
	for(i=0;i<n;i++)
	{
		gets(t[i].xh);
		gets(t[i].name);
		for(j=0;j<3;j++)
			scanf("%lf",&t[i].score[j]);
		getchar();
	}
}
void ave_score(struct StuScore t[],int n,double ave[])
{
	int i,j;
	for(i=0;i<n;i++)
	{
		for(j=0;j<3;j++)
			ave[i]+=t[i].score[j];
		ave[i]=ave[i]/3;
	}
}
int max_score(double average[],int n)
{
	double ave_max=average[0];
	int i,flag=0;
	for(i=1;i<n;i++)
		if(average[i]>ave_max)
		{
			ave_max=average[i];
			flag=i;
		}
	printf("%d:ave_max=%lf\n",flag,ave_max);
	return flag;
}
int main()
{
    int n,i,j;
    scanf("%d",&n);
    getchar();
   struct StuScore s[n];
    double average[n];
   	input(s,n);
   	ave_score(s,n,average);
   	for(i=0;i<n;i++)
       printf("ave[%d]=%lf\n",i,average[i]);
    j=max_score(average,n);
    puts(s[j].xh);
    puts(s[j].name);
    for(i=0;i<3;i++)
    	printf("%lf\t",s[j].score[i]);
    printf("%lf\n",average[j]);
    return 0;
}

在这里插入图片描述

1.5.3 结构体指针作为函数形参

#include<stdio.h>
#include<string.h>
struct StuScore{
    char xh[12];
    char name[12];
    double score[3];
};
void input(struct StuScore* t,int n)
{
	int i,j;
	struct StuScore *p;
	for(p=t;p<t+n;p++)
	{
		gets(p->xh);
		gets(p->name);
		for(j=0;j<3;j++)
			scanf("%lf",&p->score[j]);
		getchar();
	}
}
void ave_score(struct StuScore *t,int n,double ave[])
{
	int i,j;
	struct StuScore *p;
	for(p=t,i=0;p<t+n;p++,i++)
	{
		for(j=0;j<3;j++)
			ave[i]+=p->score[j];
		ave[i]=ave[i]/n;
	}
}
int max_score(double average[],int n)
{
	double ave_max=average[0];
	int i,flag=0;
	for(i=1;i<n;i++)
		if(average[i]>ave_max)
		{
			ave_max=average[i];
			flag=i;
		}
	printf("%d:ave_max=%lf\n",flag,ave_max);
	return flag;
}
int main()
{
    int n,i,j;
    scanf("%d",&n);
    getchar();
    struct StuScore s[n];
    double average[n];
   	input(s,n);
   	ave_score(s,n,average);
   	for(i=0;i<n;i++)
       printf("ave[%d]=%lf\n",i,average[i]);
    j=max_score(average,n);
    puts(s[j].xh);
    puts(s[j].name);
    for(i=0;i<3;i++)
    	printf("%lf\t",s[j].score[i]);
    printf("%lf\n",average[j]);
    return 0;
}

主题2:共用体上课简记

实际问题:学生和老师共同使用这样的表格:姓名、年龄、职业和单位。在“单位”一项,学生需要填入班级号,老师需要填入某教研室名。假设班级号用整型来表示,教研室名用字符串来表示,单位这一项需要填入两种不同类型,采用结构体是无法解决该问题的,可以采用共用体,即把单位定义为包含整型和字符数组这两种类型的“共用”。
共用体也是一种构造数据类型,是用户自定义的一种数据类型,是把不同的数据项存放于同一段内存单元中。

#include<stdio.h>
union data
{
	int i;
	char j;
};
int main()
{
	union data d;
	d.i=12;
	printf("d.i=%d\n",d.i);
	printf("d.j=%d\n",d.j);
	printf("d=%d\n",d);
	d.j='A';
	printf("d.i=%c\n",d.i);
	printf("d.j=%c\n",d.j);
	printf("d=%c\n",d);
	printf("Address of d.i=%x\n",&d.i);
	printf("Address of d.j=%x\n",&d.j);
	printf("Address of d=%x\n",&d);
	return 0;
}

在这里插入图片描述
从该程序的运行结果可知,d.i、d.j和d的地址完全相同,因而共用体也就意味着内存空间在某些时刻只有一个数据成员的值。d有两个数据成员,当d.i=12;也即d的内存空间中存放的值为12,此时输出d.j的值也为12。当d.j=’A’时,d.i的类型由于是int,因而d.i的值为’A’的ASCII值。d的内存空间被数据成员i和j共同拥有,这就是共用体。
生活中的实例:
学生和老师共同使用这样的表格:姓名、年龄、职业和单位。在“单位”一项,学生需要填入班级号,老师需要填入某教研室名。假设班级号用整型来表示,教研室名用字符串来表示。单位一项,有两种不同类型的数据成员,因而可采用共用体来表示。

#include<stdio.h>
#include<string.h>
union data
{
	int class1;
	char position[20];
};
struct info
{
	char name[20];
	int age;
	char job;
	union data dept;
};
int main()
{
	struct info person[2];
	int i;
	char temp[20];
	for(i=0;i<2;i++)
	{
		gets(person[i].name);
		gets(temp);
		person[i].age=atoi(temp);
		person[i].job=getchar();
		getchar();
		if(person[i].job=='s')
		{
			printf("input class_number:");
			gets(temp);
			person[i].dept.class1=atoi(temp);
		}
		else if(person[i].job=='t')
		{
			printf("input position:");
			gets(person[i].dept.position);
		}
		else  printf("input error!\n");
	}
	printf("name   age    job   class1/position \n");
	for(i=0;i<2;i++)
		if(person[i].job=='s')
	printf("%-10s%d%6c%10d\n",person[i].name,person[i].age,person[i].job,person[i].dept.class1);
		else
	 printf("%-10s%d%6c%10s\n",person[i].name,person[i].age,person[i].job,person[i].dept.position);
	return 0;
}

**注意:**printf("%-10s%d%6c%10d\n",person[i].name,person[i].age,person[i].job,person[i].dept.class1);这种形式,可对输出内容进行格式控制,推荐大家采用。

在这里插入图片描述

主题3:用typedef给数据类型取别名

(1)为基本数据类型取别名

typedef int hehe;
hehe i;

(2)为数组取别名

typedef char name[10];
name a,b;

等价于char a[10],b[10];

#include<stdio.h>
int main()
{
	typedef int hehe[2];
	hehe i;
	int j;
	for(j=0;j<2;j++)
	{
	    scanf("%d",&i[j]);
        printf("%d\n",i[j]);
	}
	return 0;
}

(3)为结构体取别名,个人认为这个最实用

typedef struct student
{
	char xh[20];
	int age;
	char *name;
}STU;

将结构体类型取别名为STU,然后可以用这个别名来进行定义。STU s;等价于 struct student s;

主题4:枚举类型

实际生活中,有些量的取值被限定在一个有限的范围内,例如,

一年有12个月:1~12;一周有七天:周一~周日;把这些量说明为整型、字符型或其它类型是不妥当的。例如定义表示月份的变量month,假如采用int month; month的值可以是任意的整型量,但实际上它的取值是1~12。其它的整数还不合适。
enum weekday{sun,mou,tue,wed,thu,fri,sat};
enum weekday s,t;
通常称sun,mou,tue,wed,thu,fri,sat为枚举元素。
直观感觉,变量s和t应该从sun, mou, tue, wed, thu, fri和sat 中取值,或者除了这些之外,还可不可以取其它的值呢?依照该思路,我们编写了一个简单的程序:
#include<stdio.h>
int main()
{
    enum weekday{sun,mou,tue,wed,thu,fri,sat};
    enum weekday s,t;
    s=sun;
    t=wed;
    printf("s=sun:%s\n",s);
    printf("t=wed:%s\n",t);
    printf("s:%d\n",s);
    printf("t:%d\n",t);
	return 0;
}

运行时弹出如下对话框。
在这里插入图片描述
究竟该如何对枚举变量进行操作呢??
试着去掉语句:

  printf("s=sun:%s\n",s);
    printf("t=wed:%s\n",t);

再运行下如下程序:

#include<stdio.h>
int main()
{
    enum weekday{sun,mou,tue,wed,thu,fri,sat};
    enum weekday s,t;
    s=sun;
    t=wed;
    printf("s:%d\n",s);
    printf("t:%d\n",t);
	return 0;
}

在这里插入图片描述

原因在于:

(1)枚举元素,也即sun,mou,tue,wed,thu,fri,sat本身由系统定义了一个表示序号的数值,从0开始顺序定义,sun的值为0,mou的值为1,以此类推。。。
(2)枚举元素不是字符串常量也不是字符常量,因而不能用%s输出。
(3)可以为枚举常量指定一个整型值。

举例:袋子里有红、黄、蓝三种颜色的球,编程求出取出三个不同颜色球的组合顺序。

#include<stdio.h>
int main()
{
    enum ballco{red,yellow,blue};
    enum ballco i,j,k;
    for(i=red;i<=blue;i++)
        for(j=red;j<=blue;j++)
            for(k=red;k<=blue;k++)
            if(i!=j&&i!=k&&j!=k)
            {
                switch(i)
                {
                    case 0:printf("red ");break;
                    case 1:printf("yellow ");break;
                    case 2:printf("blue ");break;
                }
                switch(j)
                {
                    case 0:printf("red ");break;
                    case 1:printf("yellow ");break;
                    case 2:printf("blue ");break;
                }
                switch(k)
                {
                    case 0:printf("red ");break;
                    case 1:printf("yellow ");break;
                    case 2:printf("blue ");break;
                }
                printf("\n");
            }
	return 0;
}

在这里插入图片描述
因为i,j,k为枚举变量,采用了switch来分别处理, 感觉那么多switch有点麻烦,换个思路。

#include<stdio.h>
int main()
{
    enum ballco {red,yellow,blue};
    enum ballco i,j,k;
    for(i=red; i<=blue; i++)
        for(j=red; j<=blue; j++)
            for(k=red; k<=blue; k++)
                if(i!=j&&i!=k&&j!=k)
                {
                    int a[3]={i,j,k},m;
                    for(m=0; m<3; m++)
                        switch(a[m])
                        {
                        case 0:printf("red ");break;
                        case 1:printf("yellow ");break;
                        case 2:printf("blue ");break;
                        }
                    printf("\n");
                }
    return 0;
}

稍微好一点。感觉15计科陈久森同学友情提示。

猜你喜欢

转载自blog.csdn.net/lvcongying0601/article/details/84579686