#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define COURSE_NUM 5 /* 最多的考试科目 */
struct student
{
int number; /* 每个学生的学号 */
char name[15]; /* 每个学生的姓名 */
int score[COURSE_NUM]; /* 每个学生M门功课的成绩 */
int sum; /* 每个学生的总成绩 */
float average; /* 每个学生的平均成绩 */
struct student *next;
};
typedef struct student STU;
STU *head=NULL;
char Menu(void);
int Ascending(int a, int b);
int Descending(int a, int b);
void IntSwap(int *pt1, int *pt2);
void CharSwap(char *pt1, char *pt2);
void FloatSwap(float *pt1, float *pt2);
STU *DeleteNode(STU *head, int nodeNum);
STU *ModifyNode(STU *head, int nodeNum, const int m);
STU *SearchNode(STU *head, int nodeNum);
STU *AppendScore(STU *head, const int m);
void TotalScore(STU *head, const int m);
void PrintScore(STU *head, const int m);
STU *DeleteScore(STU *head, const int m);
void ModifyScore(STU *head, const int m);
void SortScore(STU *head, const int m, int (*compare)(int a, int b));
void SearchScore(STU *head, const int m);
void DeleteMemory(STU *head);
void InputNodeData(STU *pNew, int m);
STU *AppendNode(STU *head, STU **pNew);
void saveandfree( );
void open();
void main()
{
char ch;
int m;
STU *head = NULL;
system("COLOR e4");
open();
printf("请输入学生数量(m<10):");
scanf("%d", &m);
while (1)
{
ch = Menu(); /* 显示菜单,并读取用户输入 */
switch (ch)
{
case'1':head = AppendScore(head, m); /* 调用成绩输入模块 */
TotalScore(head, m);
break;
case'2':PrintScore(head, m); /* 调用成绩显示模块 */
break;
case'3':head = DeleteScore(head, m); /* 调用成绩删除模块 */
printf("\nAfter deleted\n");
PrintScore(head, m); /* 显示成绩删除结果 */
break;
case'4':ModifyScore(head, m); /* 调用成绩修改模块 */
TotalScore(head, m);
printf("\nAfter modified\n");
PrintScore(head, m); /* 显示成绩修改结果 */
break;
case'5':SearchScore(head, m); /* 调用按学号查找模块 */
break;
case'6':SortScore(head, m, Descending); /* 按总分降序排序 */
printf("\nsorted in descending order by sum\n");
PrintScore(head, m); /* 显示成绩排序结果 */
break;
case'7':SortScore(head, m, Ascending); /* 按总分升序排序 */
printf("\nsorted in ascending order by sum\n");
PrintScore(head, m); /* 显示成绩排序结果 */
break;
case'0':exit(0); /* 退出程序 */
DeleteMemory(head); /*释放所有已分配的内存*/
printf("End of program!");
saveandfree();
break;
default:printf("Input error!");
break;
}
}
}
/* 函数功能:显示菜单并获得用户键盘输入的选项
函数参数:无
函数返回值:用户输入的选项
*/
char Menu(void)
{
char ch;
printf("\n学生成绩管理系统\n");
printf(" 1.添加某个学生记录\n");
printf(" 2.输出全部学生记录\n");
printf(" 3.删除一个学生记录\n");
printf(" 4.修改一个学生记录\n");
printf(" 5.搜索学生记录\n");
printf(" 6.按总分降序排序\n");
printf(" 7.按总分升序排序\n");
printf(" 0.退出学生记录系统\n");
printf("请选择:");
scanf(" %c", &ch); /*在%c前面加一个空格,将存于缓冲区中的回车符读入*/
return ch;
}
/* 函数功能:删除一个指定学号的学生的记录
函数参数:结构体指针head,指向存储学生信息的链表的首地址
整型变量m,表示考试科目
函数返回值:删除学生记录后的链表的头指针
*/
STU *DeleteScore(STU *head, const int m)
{
int i = 0, nodeNum;
char c;
do{
printf("请输入你想要删除的同学的学号:");
scanf("%d", &nodeNum);
head = DeleteNode(head, nodeNum); /*删除学号为nodeNum的学生信息*/
PrintScore(head, m); /*显示当前链表中的各节点信息*/
printf("你真的想删除记录吗(Y/N)?");
scanf(" %c",&c); /*%c前面有一个空格*/
i++;
}while (c=='Y' || c=='y');
printf("%d 的记录已删除\n", i);
return head;
}
/* 函数功能:修改一个指定学号的学生的记录
函数参数:结构体指针head,指向存储学生信息的链表的首地址
整型变量m,表示考试科目
函数返回值:修改学生记录后的链表的头指针
*/
void ModifyScore(STU *head, const int m)
{
int i = 0, nodeNum;
char c;
do{
printf("请输入你想要修改的学生的学号:");
scanf("%d", &nodeNum);
head = ModifyNode(head, nodeNum, m); /*修改学号为nodeNum的节点*/
printf("你真的想修改此位同学的记录吗(Y/N)?");
scanf(" %c",&c); /*%c前面有一个空格*/
i++;
}while (c=='Y' || c=='y');
printf("%d 的记录已修改!\n", i);
}
/* 函数功能:计算每个学生的m门功课的总成绩和平均成绩
函数参数:结构体指针head,指向存储学生信息的链表的首地址
整型变量m,表示考试科目
函数返回值:无
*/
void TotalScore(STU *head, const int m)
{
STU *p = head;
int i;
while (p != NULL) /*若不是表尾,则循环*/
{
p->sum = 0;
for (i=0; i<m; i++)
{
p->sum += p->score[i];
}
p->average = (float)p->sum / m;
p = p->next; /*让p指向下一个节点*/
}
}
/* 函数功能:用交换法按总成绩由高到低排序
函数参数:结构体指针head,指向存储学生信息的链表的首地址
整型变量m,表示考试科目
函数返回值:无
*/
void SortScore(STU *head, const int m, int (*compare)(int a, int b))
{
STU *pt;
int flag = 0, i;
do{
flag = 0 ;
pt = head;
/*若后一个节点的总成绩比前一个节点的总成绩高,则交换两个节点中的数据
注意只交换节点数据,而节点顺序不变,即节点next指针内容不进行交换*/
while (pt->next != NULL)
{
if ((*compare)(pt->next->sum, pt->sum))
{
IntSwap(&pt->number, &pt->next->number);
CharSwap(pt->name, pt->next->name);
for (i=0; i<m; i++)
{
IntSwap(&pt->score[i], &pt->next->score[i]);
}
IntSwap(&pt->sum, &pt->next->sum);
FloatSwap(&pt->average, &pt->next->average);
flag = 1;
}
pt = pt->next;
}
}while(flag);
}
/*交换两个整型数*/
void IntSwap(int *pt1, int *pt2)
{
int temp;
temp = *pt1;
*pt1 = *pt2;
*pt2 = temp;
}
/*交换两个实型数*/
void FloatSwap(float *pt1, float *pt2)
{
float temp;
temp = *pt1;
*pt1 = *pt2;
*pt2 = temp;
}
/*交换两个字符串*/
void CharSwap(char *pt1, char *pt2)
{
char temp[15];
strcpy(temp, pt1);
strcpy(pt1, pt2);
strcpy(pt2, temp);
}
/*决定数据是否按升序排序,a<b为真,则按升序排序*/
int Ascending(int a, int b)
{
return a < b;
}
/* 决定数据是否按降序排序,a>b为真,则按降序排序 */
int Descending(int a, int b)
{
return a > b;
}
/* 函数功能:按学号查找学生成绩
函数参数:结构体指针head,指向存储学生信息的链表的首地址
整型变量m,表示考试科目
函数返回值:无
*/
void SearchScore(STU *head, const int m)
{
int number, i;
STU *findNode;
printf("请输入你想要查找的学生的学号:");
scanf("%d", &number);
findNode = SearchNode(head, number);
if (findNode == NULL)
{
printf("没有找到!\n");
}
else
{
printf("\nNo.%3d%8s", findNode->number, findNode->name);
for (i=0; i<m; i++)
{
printf("%7d", findNode->score[i]);
}
printf("%9d%9.2f\n", findNode->sum, findNode->average);
}
}
/* 函数的功能:显示所有已经建立好的节点的节点号和该节点中数据项内容
函数的参数:结构体指针变量head,表示链表的头节点指针
整型变量m,表示考试科目
函数返回值:无
*/
void PrintScore(STU *head, const int m)
{
STU *p = head;
char str[100] = {'\0'}, temp[3];
int i, j = 1;
strcat(str, "Number Name ");
for (i=1; i<=m; i++)
{
strcat(str, "Score");
itoa(i,temp, 10);
strcat(str, temp);
strcat(str, " ");
}
strcat(str," sum average");
printf("%s", str); /* 打印表头 */
while (p != NULL) /*若不是表尾,则循环打印*/
{
printf("\nNo.%3d%15s", p->number, p->name);
for (i=0; i<m; i++)
{
printf("%7d", p->score[i]);
}
printf("%9d%9.2f", p->sum, p->average);
p = p->next; /*让p指向下一个节点*/
j++;
}
printf("\n");
}
/* 函数功能:按学号查找并修改一个节点数据
函数参数:结构体指针变量head,表示链表的头节点指针
整型变量nodeNum,表示待修改节点的学号
整型变量m,表示考试科目
返回参数:修改节点后的链表的头节点指针
*/
STU *ModifyNode(STU *head, int nodeNum, const int m)
{
int j;
STU *newNode;
newNode = SearchNode(head, nodeNum);
if (newNode == NULL)
{
printf("没有找到!\n");
}
else
{
printf("输入新的记录:\n");
printf("输入名字:");
scanf("%s", newNode->name);
for (j=0; j<m; j++)
{
printf("输入分数%d:", j+1);
scanf("%d", newNode->score+j);
}
}
return head;
}
/* 函数功能:从head指向的链表中删除一个节点数据为nodeNum的节点
输入参数:结构体指针变量head,表示原有链表的头节点指针
整型变量nodeNum,表示待删除节点的节点数据值
返回参数:删除节点后的链表的头节点指针
*/
STU *DeleteNode(STU *head, int nodeNum)
{
STU *p = head, *pr = head;
if (head == NULL) /*链表为空,没有节点,无法删除节点*/
{
printf("无此节点!\n");
return(head);
}
/*若没找到节点nodeNum且未到表尾,则继续找*/
while (nodeNum != p->number && p->next != NULL)
{
pr = p;
p = p->next;
}
if (nodeNum == p->number) /*若找到节点nodeNum,则删除该节点*/
{
if (p == head) /*若待删节点为首节点,则让head指向第2个节点*/
{
head = p->next;
}
else /*若待删节点非首节点,则将前一节点指针指向当前节点的下一节点*/
{
pr->next = p->next;
}
free(p); /*释放为已删除节点分配的内存*/
}
else /*没有找到待删除节点*/
{
printf("此节点已被删除!\n");
}
return head; /*返回删除节点后的链表的头节点指针*/
}
/* 函数功能:按学号查找一个节点数据
函数参数:结构体指针变量head,表示链表的头节点指针
整型变量nodeNum,表示待修改节点的学号
返回参数:待修改的节点指针
*/
STU *SearchNode(STU *head, int nodeNum)
{
STU *p = head;
int j = 1;
while (p != NULL) /*若不是表尾,则循环*/
{
if (p->number == nodeNum) return p;
p = p->next; /*让p指向下一个节点*/
j++;
}
return NULL;
}
/* 函数功能:释放head指向的链表中所有节点占用的内存
输入参数:结构体指针变量head,表示链表的头节点指针
返回参数:无
*/
void DeleteMemory(STU *head)
{
STU *p = head, *pr = NULL;
while (p != NULL) /*若不是表尾,则释放节点占用的内存*/
{
pr = p; /*在pr中保存当前节点的指针*/
p = p->next; /*让p指向下一个节点*/
free(pr); /*释放pr指向的当前节点占用的内存*/
}
}
/* 函数功能:输入一个节点的节点数据
函数参数:结构体指针变量pNew,表示链表新添加节点的指针
整型变量m,表示考试科目
返回参数: 无
*/
void InputNodeData(STU *pNew, int m)
{
int j;
printf("输入节点信息......");
printf("\n输入学号:");
scanf("%d", &pNew->number);
printf("输入姓名:");
scanf("%s", pNew->name);
for (j=0; j<m; j++)
{
printf("输入分数%d:", j+1);
scanf("%d", pNew->score+j);
}
}
/* 函数功能:新建一个节点,并将该节点添加到链表的末尾
函数入口参数:结构体指针变量head,表示原有链表的头节点指针
函数出口参数:指向结构体指针的指针变量pNew,表示指向新添加节点指针的指针
函数返回值:添加节点后的链表的头节点指针
*/
STU *AppendNode(STU *head, STU **pNew)
{
STU *p = NULL;
STU *pr = head;
p = (STU *)malloc(sizeof(STU)); /*为新添加的节点申请内存*/
if (p == NULL) /*若申请内存失败,则打印错误信息,退出程序*/
{
printf("No enough memory to alloc");
exit(0);
}
if (head == NULL) /*若原链表为空表,则将新建节点置为首节点*/
{
head = p;
}
else /*若原链表为非空,则将新建节点添加到表尾*/
{
/*若未到表尾,则继续移动指针pr,直到pr指向表尾*/
while (pr->next != NULL)
{
pr = pr->next;
}
pr->next = p; /*将新建节点添加到链表的末尾*/
}
pr = p; /*让pr指向新建节点*/
pr->next = NULL; /*将新建节点置为表尾*/
*pNew = p; /*将新建节点指针通过二级指针pNew返回给调用函数*/
return head; /*返回添加节点后的链表的头节点指针*/
}
/* 函数功能:向链表中添加从键盘输入的学生学号、姓名和成绩等信息
函数参数:结构体指针head,指向存储学生信息的结构体数组的首地址
整型变量m,表示考试科目
函数返回值:无
*/
STU *AppendScore(STU *head, const int m)
{
int i = 0;
char c;
STU *pNew;
do{
head = AppendNode(head, &pNew); /*向链表末尾添加一个节点*/
InputNodeData(pNew, m); /*向新添加的节点中输入节点数据*/
printf("你真的想要添加一个节点(Y/N)?");
scanf(" %c",&c); /*%c前面有一个空格*/
i++;
}while (c=='Y' || c=='y');
printf("%d 新的节点已被添加!\n", i);
return head;
}
/*输出信息到文件 */
void saveandfree( )
{
STU *p=NULL;
FILE * fp;
int i;
char * file="student.txt";
if(head==NULL)
{
printf("无记录\n");
return;
}
else
p=head->next;
if((fp=fopen(file,"w"))==NULL)
{
printf("\n打不开文件\n");
return;
}
while(p!=NULL)
{
fprintf(fp,"%d\t%s\t%d\t%f\t\n",p->number,p->name,p->sum,p->average);
for(i=0;i<COURSE_NUM;i++)
fprintf(fp,"%d\n",p->score[i]);
p=p->next;
}
printf("保存完毕\n");
fclose(fp);
for(;head->next!=NULL;)
{
p=head->next;
head->next=head->next->next;
free(p);
}
free(head);
}
/*读取文件信息到链表*/
void open()
{
FILE * fp;
STU *p1=NULL;
STU *p2=NULL;
STU *temp=NULL;
int i ;
if((fp=fopen("E:\\student.txt","r"))==NULL)
{
printf("\n************这是一个学生管理程序************");
return ;
}
head=(STU *)malloc(sizeof(struct student));
head->next=NULL;
temp=p2=head;
while(! feof(fp))
{
p1=(STU *)malloc(sizeof(struct student));
temp=p2;
p2->next=p1;
p2=p1;
fscanf(fp,"%d%s%d%f",p1->number,p1->name,p1->sum,p1->average);
for(i=0;i<COURSE_NUM;i++)
fscanf(fp,"%d",p1->score[i]);
}
temp->next=NULL;
fclose(fp);
}
温馨提示:内容为网友见解,仅供参考