| 本帖最后由 黑暗天使 于 2020-8-1 15:48 编辑
大家好,又到了休闲放松的时间了。今天我想想做点什么好呢? 前几天发了项目图片,该写的文字写的,该调妹的也调了,是应该做点正事了,算是良心发现吧,不能就知道玩啊,呵呵。所以今天我们继续玩玩程序,为下一次的知识综合竞赛做准备(不好意思,可能要多等一段时间,还没构思好)
程序要求:
从键盘上输入一万名用户的信息(包括用户ID,组别,金币,精品值),要求分别输出在普通用户组(不含管理组,也不含会员组)中,金币前三位的用户ID和金币最后三位的用户ID,以及目前所有会员的总人数(包括月会员,半年会员,年会员)
为了不要太复杂,假设作以下规定:
1)规定所有用户的金币都不相等。
2)组别只有三种可能,其中用字母S表示普通用户组,字母M表示管理组,字母V表示VIP组即会员组。
正题开始之前还是说清楚,本程序纯属学习或娱乐之用,与论坛的运作毫无任何关系。不管你懂或不懂,或者是否为计算机专业都不重要,关键是有没有认真学的决心,为了照顾大家理解,我尽可能在重要地方写上注解。这个程序相对来说还是有点综合有点难度(至少对非计算机专业来说),你如果能达到我这水平,参加考试或毕业设计就根本不成问题,万一不行就要努力加油了。
下面程序开始,我们一起正式踏入C语言的苦海。如果你在学校学习别的语言或你对其它语言(如VB,JAVA等)有兴趣,可以自己试着实现。
#include<stdio.h>
#define MAXNUM 10000 //将MAXNUM定义为题目要求人数一万
struct userinfo
{
char userID[50]; //这表示用户的ID号,假设最大长度为50字符,如果是汉字就是25个字
char userTYPE; //这表示用户的组别,只能为一个字母。只能是S或M或V
int coins; //这表示金币,只能为整数
int values; //这表示精品值,只能为整数
}
// 上面四项合成起来构成了一个结构体,表示一个用户的完整记录,名称取名为userinfo。
typedef userinfo Uk; //这句话是将userinfo取一个简单的别名叫UK,因为每次都要写struct userifno就太麻烦了
Uk a[MAXNUM],b[MAXNUM]; //在这里定义两个全局变量,是两个全局数组,分别是a和b,其中数组a用来保存所有用户的记录,而数组b只保存普通用户组的记录(不含管理组和会员组)
int usernum=0,vipnum=0; //这也是两个全局变量,都是整型,usernum表示普通用户组的总人数,vipnum表示会员组的总人数。
void inputdata( ) //这是第一个子程序,它的功能是从键盘上输入一万名用户记录,并保存在数组a中
{
int k;
printf("请输入10000名用户的信息!");
for(k=0;k<MAXNUM;k++)
{
scanf("%s",a[k].userID); //这条语句保存用户的ID,%s是表示字符串
scanf("%c",&a[k].userTYPE); //这条语句保存用户的组别,%c是单个字母
scanf("%d",&a[k].coins); //这条语句保存用户的金币,%d是整型
scanf("%d",&a[k].values); //这条语句保存用户的精品值
}
}
void totaluserinfo( ) //这是第二个子程序,功能是将所有用户中组别为S(也就是普通用户组)的记录全部挑出来,并按顺序存放在数组b中
{
int k;
for(k=0;k<MAXNUM;k++)
if(a[k].userTYPE=='S') // 如果当前某用户的组别为字母S
b[usernum++]=a[k]; //则将它保存到数组b中,数组b中序号从0开始,每保存一条记录,序号就加1
if(a[k].userTYPE=='V')
vipnum++; //同理,如果当前某用户的组别为字母V,则将会员组人数加1,即vipnum++
}
Uk getmaxk(int k, Uk a[ ]) //这是第三个子程序,也是整个程序中非常重要的一个函数,它的功能是从所有普通用户中,挑选出第k大的用户记录并返回。例如,当k=3则表示找出金币排行第3的那条用户记录。
{
int k,j; //k和j用来处理循环,一般来说排序都是两个循环
Uk temp; //这是一个临时变量,用在交换变量时使用,这是程序基本功了
for(k=0;k<usernum;k++)
for(j=k+1;j<usernum;j++)
if(a[k].coins<a[j].coins) //a[k]表示前面的记录,a[j]表示后面的记录,如果前面记录的金币小于后面记录的金币,则说明当前是升序,而我们的目的是要降序,所以要将它们交换过来
{
temp=a[k];
a[k]=a[j];
a[j]=temp; //此处三行用于实现将a[k]和a[j]交换过来,程序基本功,不再解释。
}
return a[k-1]; //最后将满足的记录返回。例如,k=1则表示第1大的记录也就是金币最多的记录,还记得前面已经交换后,变成了降序,也就是说a[0]是最大的,将k=1代入刚好是a[0]
}
void outputdata( ) //这是最后一个子程序,用于输出结果
{
printf("在普通用户中,金币排行前三位的用户ID分别为:");
puts(getmaxk(1,b).userID);
puts(getmaxk(2,b).userID);
puts(getmaxk(3,b).userID); //这三条都是一样的,只要看懂一条即可。puts是用来输出字符串的,也就是为了在屏幕上显示用户的ID号,接着调用前面的子程序getmaxk,将参数k直接传入即可。这三条语句很明显,第一个参数分别为1,2,3,当然就表示第1大记录,第2大记录,第3大记录,后面的.userID是表示从记录中取出用户ID号。
printf("在普通用户中,金币排行最后三位的用户ID分别为:");
puts(getmaxk(usernum,b).userID);
puts(getmaxk(usernum-1,b).userID);
puts(getmaxk(usernum-2,b).userID); //这三条和上面三条同理,只是刚好反过来而已。最后三位记录,所以k就变成了usernum,usernum-1,usernum-2
printf("截止目前论坛所有会员的总人数为:%d",vipnum); //最后输出所有会员的总人数,在子程序totaluserinfo() 中的最后一条,已经统计了,就是vipnum
}
main( )
{
inputdata( );
totaluserinfo( );
outputdata( );
} //最后是我们的主程序。大家可以看到,只要前面的分工都到位了,这里什么也不用管,只往里面填就完事了,但要格外注意一点,这三条语句可千万不能颠倒啊
最后的反思:
学而不思则罔,思而不学则殆。思考是无限的,不要知其然不知其所以然。这个程序有以下几点值得我们思考:
1)程序中用MAXNUM表示最大人数一万(题目中明确假设就是一万人),但为什么要写MAXNUM,为什么不直接写10000?
2) scanf("%s",a[k].userID); //这条语句保存用户的ID,%s是表示字符串
scanf("%c",&a[k].userTYPE); //这条语句保存用户的组别,%c是单个字母
为什么上面一句没有&符号,而下面一句有&符号,这是为什么?
3)Uk a[MAXNUM],b[MAXNUM]; 这上面已经解释了,是两个全局数组。大家想想为什么要这样写,为什么不能将数组a和数组b直接写到子程序中?
4)本程序中是假设所有用户的金币不相等。其实如果考虑相等,这情况就有点差别了,稍稍有点麻烦了,这留给你们自己去改进去完善。
有能力有兴趣的朋友多多完善,既是放松心情也是温故而知新,一举两得。上面这四个疑问,很抱歉,我是不会回答的,这些问题有可能作为下一界知识综合竞赛的部分选题,请大家多多翻书,多多百度总有解决方法的。
| |