学生成绩管理系统的排序无法解决

weixin_39275663 2017-06-27 10:14:44
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define Length sizeof(struct student) //用来开辟空间
int n=0;
struct student
{
char name[20]; //名字
char sex[20]; //性别
char Class[20]; //班级
char major[20]; //专业
int age; //年龄
int cgrade; //C语言成绩
int mgrade; //数学成绩
int egrade; //英语成绩
int pgrade; //体育成绩
int lgrade; //语文成绩
int avg; //平均分
struct student *next;
}*head,*p,*p1,*p2; //head表示开头 p表示不同位置的数据
void add( ) //添加
{ p1=(struct student *)malloc(Length); //开辟存储空间
if(n==0) //判断链表开头
head=p1; //n=0代表输入的是第一个数据 //p2的结尾所指向的地址是p1
else p2->next=p1; //n!=0 就它们连接起来
system("cls");
printf("请输入学生基本信息:\n姓名:");
scanf("%s",&p1->name);
printf("性别:");
scanf("%s",&p1->sex);
printf("年龄:");
scanf("%d",&p1->age);
printf("班级:");
scanf("%s",&p1->Class);
printf("专业:");
scanf("%s",&p1->major);
printf("C语言成绩: ");
scanf("%d",&p1->cgrade);
printf("数学成绩:");
scanf("%d",&p1->mgrade);
printf("英语成绩:");
scanf("%d",&p1->egrade);
printf("体育成绩:");
scanf("%d",&p1->pgrade);
printf("语文成绩:");
scanf("%d",&p1->lgrade);
p2=p1; //p2指向p1所在的地址
p2->next=NULL; //链表结束标志
n+=1; //n判断是不是第一个数据
system("pause"); //等待命令
system("cls");
}
void print()
{
if(n!=0)
{
p=head; //p先指向开头
system("cls");
printf("姓名\t性别\t\t班级\t年龄\t专业\tC语言成绩 数学成绩 英语成绩 体育成绩 语文成绩 平均分\n");
do
{ p1->avg=(p1->cgrade+p1->mgrade+p1->egrade+p1->pgrade+p1->lgrade)/5;
printf("%-8s%-16s%-8s%-8d%-16s%-8d%-8d%-8d%-8d%-8d%5.2d\n",p->name,p->sex,p->Class,p->age,p->major,p->cgrade,p->mgrade,p->egrade,p->pgrade,p->lgrade,p->avg);
p=p->next; //p打印结束 把p指向next以判断下一个区域有没有内容
}while(p!=NULL);//只要p指向的内存区域有数据 就打印内容
}
else
printf("******您还没有添加数据哟!\n");
system("pause");
system("cls");
}
void find() //查找
{
char a[20];
printf("请输入要查找的姓名:");
scanf("%s",&a);
p=head;
do
{
if(strcmp(a,p->name)==0)
{ p1->avg=(p1->cgrade+p1->mgrade+p1->egrade+p1->pgrade+p1->lgrade)/5;
printf("\n信息已被找到:\n姓名\t性别\t\t班级\t年龄\t专业\tC语言成绩 数学成绩 英语成绩 体育成绩 语文成绩 平均分\n");
printf("%-8s%-16s%-8s%-8d%-16s%-8d%-8d%-8d%-8d%-8d%5.2d\n\n",p->name,p->sex,p->Class,p->age,p->major,p->cgrade,p->mgrade,p->egrade,p->pgrade,p->lgrade,p->avg);

}p=p->next; //指针指向下一个节点
}while(p!=NULL);
printf("******您还没有添加数据哟!\n");
system("pause");
system("cls");
}
void Delete()
{
if(n!=0)
{
struct student *f,*l; //定义新的指针 f使用来指向要删除的数据用来释放内存!
char a[20];
printf("请输入要删除的姓名:");
scanf("%s",&a);
p=head;
if(strcmp(head->name,a)==0)
{f=head;head=head->next;free(f);}
else
{
do
{
if(strcmp(p->name,a)==0)
{f=p;l->next=p->next;free(f);break;}
l=p; //不满足if表示这不是要删除的那一个节点,l暂时指向p 之后p再指向下一个节点,如果这个是要删除的节点那么l指向这个节点的next的地址
p=p->next;
}while(p!=NULL);
}
}
else
printf("******您还没有添加数据哟!\n");
printf("数据已经被删除\n");
system("pause"); //等待命令
system("cls");
}
void amend()
{
if(n!=0)
{
int c;
char a[20];
printf("请输入要修改的姓名:");
scanf("%s",&a);
p=head;
do
{
if(strcmp(a,p->name)==0)
{p1->avg=(p1->cgrade+p1->mgrade+p1->egrade+p1->pgrade+p1->lgrade)/5;
printf("\n被修改人信息如下:\n姓名\t性别\t\t班级\t年龄\t专业\tC语言成绩 数学成绩 英语成绩 体育成绩 语文成绩 平均分\n");
printf("%-8s%-16s%-8s%-8d%-16s%-8d%-8d%-8d%-8d%-8d%5.2d\n",p->name,p->sex,p->Class,p->age,p->major,p->cgrade,p->mgrade,p->egrade,p->pgrade,p->lgrade,p->avg);
break;
}
p=p->next; ////指针指向下一个节点
}while(p!=NULL);
printf("\n\n1.修改姓名\n2.修改性别\n3.修改班级\n4.修改年龄\n5.修改专业\n6.修改C语言成绩\n7.修改数学成绩\n8.修改英语成绩\n9.修改体育成绩\n10.修改语文成绩\n11.退出修改\n\n");
scanf("%d",&c);
switch(c)
{
case 1:
printf("姓名修改为:");
scanf("%s",&p->name);break;
case 2:
printf("性别修改为:");
scanf("%s",&p->sex);break;
case 3:
printf("班级修改为:");
scanf("%s",&p->Class);break;
case 4:
printf("年龄修改为:");
scanf("%d",&p->age);break;
case 5:
printf("专业修改为:");
scanf("%s",&p->major);break;
case 6:
printf("C语言成绩修改为:");
scanf("%d",&p->cgrade);break;
case 7:
printf("数学成绩修改为:");
scanf("%d",&p->mgrade);break;
case 8:
printf("英语成绩修改为:");
scanf("%d",&p->egrade);break;
case 9:
printf("体育成绩修改为:");
scanf("%d",&p->pgrade);break;
case 10:
printf("语文成绩修改为:");
scanf("%d",&p->lgrade);break;
case 11:
break;
}
printf("\n\n操作成功!\n\n");
}
else
printf("******您还没有添加数据哟!\n");
system("pause");
system("cls");
}

void sort()
{
struct student *p; /*为原链表剩下用于直接插入排序的节点头指针*/
struct student *t; /*临时指针变量:插入节点*/
struct student *first; /*临时指针变量*/
struct student *q; /*临时指针变量*/
p=head->next;
head->next = NULL;
while (p!= NULL)
{
for (t=p,q=head;((q!=NULL)&&(q->avg<t->avg));first=q,q=q->next); /*无序节点在有序链表中找插入的位置*/
/*退出for循环,就是找到了插入的位置*/
/*注意:按道理来说,这句话可以放到下面注释了的那个位置也应该对的,但是就是不能。*/
p=p->next; /*无序链表中的节点离开,以便它插入到有序链表中。*/

if (q==head) /*插在第一个节点之前*/
{
head=t;
}
else /*p是first的前驱*/
{
p->next=t;
}
t->next=q; /*完成插入动作*/
/*first = first->next;*/
}while(t!=NULL);
printf("******您还没有添加数据哟!\n");
system("pause");
system("cls");
}

void main() //主函数
{
int a=1;
while(a!=0)
{
system("cls");
printf("—————————* 学 生 成 绩 管 理 系 统 *—————————\n");
printf("—————————* ( 1.输入学生信息 ) *—————————\n");
printf("—————————* ( 2.显示全部信息 ) *—————————\n");
printf("—————————* ( 3.查询学生信息 ) *—————————\n");
printf("—————————* ( 4.删除学生信息 ) *—————————\n");
printf("—————————* ( 5.修改学生信息 ) *—————————\n");
printf("—————————* ( 6.排序学生成绩 ) *—————————\n");
printf("—————————* ( 0. 退出系统 ) *—————————\n");
printf("请选择:");
scanf("%d",&a);
if(a>=0&&a<=9)
{
switch(a)
{
case 1:
add();
break;
case 2:
print();
break;
case 3:
find();
break;
case 4:
Delete();
break;
case 5:
amend();
break;
case 6:
sort();
break;
case 7:
break;

}
}
else
{
printf(" 您输入的不符合要求,将返回主菜单!\n");
system("pause");
}
}
}

...全文
722 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
c学生成绩管理系统.rar
这次的课程设计和以往写的程序比起来,无论是在篇幅和复杂度上都提高了不少,我在写这个程序的过程中,遇到了不少的困难,也积累了不少的知识和经验,特别是在以前的时候我倍感头疼的文件部分,我也有了一定的了解,我想这对我今后的学习和工作是十分有益的。在这里我特意将在我在写程序过程中的体验和要注意的问题总结如下:
一. 基础知识一定要牢固。
在调试程序的过程中,有时候程序出了错误,找了半天找不到在哪里。这个时候往往会感觉十分不耐烦,但往往越是一些很小的小错误,越是往往容易被人疏漏,诸如“print”啦,注释引号括号不成对出现,遗漏scanf函数中的&符号等等,而这些却可能导致整个程序不运行,从而浪费了不少的时间。等到发现时,只会郁闷不已。因此,对于一个合格的程序员来说,牢固的基础知识是十分重要的。我们虽然没有必要达到那么高的要求,但牢固的基础知识对于程序的熟练编写和时间的节省也是大有裨益的。
二.调试程序的过程中,经验的积累和技巧的掌握是必要的。
在这次的课程设计中,由于要编写的程序的篇幅较大,因此不可避免地出现了相当多的错误,调试程序花了我不少的时间。我发现调试程序是有规律和技巧可寻的。/**/注释符号的灵活运用提供了较大的空间。通过程序的分块屏蔽可以很容易地找出错误的所在。函数的运用也是很自然的。因为有时一个临时的功能函数可以让我们很直观地知道一段程序是否正确。当然,有时,错误提示信息可以直接提供错误的所在,但是C语言自动查找错误的功能毕竟是有限的,大多数情况之下,我们还是必须要依靠自己。这时,经验就显的很重要了,我们在平时编写程序时,应多注意有意识地积累一些,会有好处的。
三.务求简单
我在编写程序的过程中发现,在某一个功能多个算法可以实现的时候,最好采用最简单的方案,这样可以减少出错的几率,也可以省去不少的麻烦。在我的程序中,有一个例子,可以很好地说明这个问题:在编写score_research()函数的时候,有一个地方可以用排序算法实现,也可以用一个标志变量加101然后在函数的末尾处再减101,这样大大地简化了程序,但是运算量也明显地加大了。然而计算机硬件已经发展到今天这个地步,对于我们写的这种小程序,计算速度已经不是问题,因此,务求简单,减少出错率才是正确的选择。
四.函数的运用和程序的模块化。
在这次课程设计里,我终于体会到了模块化带来的方便和优越。通过模块化处理,将最初的程序的功能构想以函数的形式划分成几个模块,模块下再设子模块,一层一层直到程序的功能实现为止。这样,不仅程序易于编写,还易于维护。最重要的是,如果程序出错,还易于查找和修改。
以上是我在程序的编写过程中的一点心得和体会,虽然很肤浅,但毕竟是通过自己的亲身实践得来的,感受较深。

另外,在程序的操作中还有一些需要注意的问题,主要有以下几点:
一.输入数据时,也就是在执行input()和input_2()函数的时候,一定要注意按照程序提供的输入顺序输入数据,否则极有可能导致文件的输入错误;还有,由于学生基本情况文件和成绩文件是由input()和input_2()两个函数先后完成的,所以在输入时一定要注意前后相同学生的姓名一定要相应地一致。如果输入了不同的姓名,虽然不会导致程序出错,但对于程序的结果来说,却是逻辑上的一个大大的错误。
二.为了使程序的操作更加简便,人性,我在程序中有加进了一个view_two()函数,目的是为了使程序每执行完一项功能之后,都能出现菜单以供选择,可以非常方便地执行下一个功能。另外,在view_two()函数和view()函数中,我还设置了exit()子函数。执行这个函数,便可以直接返回原代码界面。操作者若是在操作中注意到了这些,将会使操作简单不少。
三.当然,不可避免地,由于我的程序大部分是在机房编写和调试完成,时间相对较紧张,再加上我本来就对C语言没有精深的钻研和琢磨,因此程序写得相当粗糙,在有些功能的实现上,只是将其功能大致完成,并未考虑到操作的简便化等问题。例如在input()和input_2()函数的执行中,本来每个学生的基本情况和成绩应该是在一起输入的,这样才符合一般人的正常思路,但由于学生的基本情况和成绩是由两个函数分别执行完成的,姓名需要输入两次才能将学生的姓名输入到两个结构体中,因为姓名是存储在字符数组里面的,所以用一般的赋值语句是解决不了的。我只好采用了一个原始的办法,把两个结构体里的姓名分别用两个输入语句实现。但这样又导致了另外一个问题,即两次姓名的输入如果不相同时所导致的错误,而且这个问题在学生的数量越多即两次输入离得越远时表现得越突出,但我也想不出更好的办法来解决这个问题了。

通过这次做课程设计,我感觉我学到了不少的东西,尤其是耐心的培养和在宏观上组织问题的能力让我受益非浅。这不仅是设计程序所必需的,也是今后的学习和工作所不可缺少的。希望我能在这次课程设计的基础上,继续学习更多的C语言的知识,使自己的编程能力更上一层楼。

1,178

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 数据库及相关技术
社区管理员
  • 数据库及相关技术社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧