/**********************************************************************
*製作時間:2008年9月17日
*程序名稱:學生成績管理系統
*程序功能:能實現對學生成績的錄入,插入,刪除,查找,瀏覽,排序,
* 合計,保存,讀取等功能
***********************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define STRSNO "/n學生學號: "
#define STRSNAME "/n學生姓名: "
#define STRC "/nC企業要求與實踐: "
#define STRTD "/nTD-SCDMA: "
#define STRLINUX "/nLinux 基礎與開發: "
#define STRJ "/nJ2ME: "
#define STREN "/n專業英語: "
#define CPRJ 0
#define TD 1
#define LINUX 2
#define J2ME 3
#define CSENG 4
#define SUMSUBJ 5
#define STRINPUTERROR "輸入有誤,請重新輸入!/n"
#define PRINTTITLE "/n 學號 | 姓 名 |C企業要求|TD-SCDMA|LINUX|J2ME|專業英語| 總分 | 平均 /n/n"
#define PRINTSTYLE " %s %s/t %d/t %d/t %d/t %d/t %d/t%d %.2f/n"
#define GETINPUTSTRDATA(str,data) printf(str); /
scanf("%s",&data)
#define GETINPUTINTDATA(str,data) printf(str); /
scanf("%d",&data)
#define CHECKINPUTFUNC(score) if( score > 100 || score < 0 ) /
{ /
printf(STRINPUTERROR); /
printf(STRC); /
scanf("%d",&score); /
}
#define INTTYPE 1
#define FLOATTYPE 2
#define STRTYPE 3
#define OFFSETSNO 0
#define OFFSETSNAME (OFFSETSNO+16*sizeof(char))
#define OFFSETSCORE (OFFSETSNAME+12*sizeof(char))
#define OFFSETSUM (OFFSETSCORE+SUMSUBJ*sizeof(int))
#define OFFSETAVR (OFFSETSUM+sizeof(int))
/****************************************************************************
*******************用 system("color 0A"); ***********************************
*****其中color後面的0是背景色代號,A是前景色代號。各顏色代碼如下: **********
****************************************************************************/
#define USECOLORBLACK system("color 00") //0=黑色
#define USECOLORBLUE system("color 01") //1=藍色
#define USECOLORGREEN system("color 02") //2=綠色
#define USECOLORLBLUE system("color 03") //3=湖藍色
#define USECOLORRED system("color 04") //4=紅色
#define USECOLORPURPLE system("color 05") //5=紫色
#define USECOLORYELLOW system("color 06") //6=黃色
#define USECOLORWHITE system("color 07") //7=白色
#define USECOLORDARK system("color 08") //8=灰色
#define USECOLORSKYBLUE system("color 09") //9=淡藍色
#define USECOLORLGREEN system("color 0A") //A=淡綠色
#define USECOLORLLGREEN system("color 0B") //B=淡淺綠色
#define USECOLORLRED system("color 0C") //C=淡紅色
#define USECOLORLPURPLE system("color 0D") //D=淡紫色
#define USECOLORLYELLOW system("color 0E") //E=淡黃色
#define USECOLORHWHITE system("color 0F") //F=亮白色
// 結構體定義學生的所有屬性,包括學生證號,姓名,5門學科成績,總成績,平均成績
struct studentLink
{
char sno[16];
char sname[12];
int arscore[SUMSUBJ];
int sum;
float avr;
struct studentLink* link;
};
typedef struct studentLink STULINK;
// 函數聲明
STULINK* creat();
STULINK* searchbysno(STULINK *head, char * sno, STULINK **prev);
void insert(STULINK *head,STULINK *p, STULINK stu);
void delstunode(STULINK *head,STULINK *prelink,STULINK *dellink);
void insertbysno(STULINK *head, STULINK stu);
void menu(); //主菜單函數
void input(STULINK *head); //錄入函數
void insertbysno(STULINK *head, STULINK stu);
void del(STULINK *head); //刪除函數
void delbysno(STULINK* head); //按學生證號刪除
void delbysname(STULINK* head); //按姓名刪除
void select(STULINK* head); //查找函數
void selectsno(STULINK* head); //按學生證號查找
void selectsname(STULINK* head); //按姓名查找
void sort(STULINK *head,int offset, int type); //冒泡排序函數
void display(STULINK* head); //製表格式函數
void total(STULINK* head); //分類合計函數
void save(STULINK* head); //保存函數
void load(STULINK* head); //讀取函數
void freelink(STULINK* head);
void sortready(STULINK* head);
void sortbyscore(STULINK* head);
// 主函數
int main(void)
{
int in; //選擇功能的變量
char ch='y'; //選擇是否繼續時的變量,(y / n)
STULINK* stuhead=NULL;
stuhead = creat();
//USECOLORLLGREEN;
if(stuhead==NULL)
return 1;
load(stuhead);
do
{
menu();
scanf("%d",&in);
if(in<0 || in>7)
{
printf("/a輸入有誤,請在0~7之間選擇!");
continue;
}
else if(in==0)
{
printf("確定要退出程序嗎?(y / n) ");
scanf(" %c",&ch);
printf("/n");
if(ch=='Y' || ch=='y')
{
printf("謝謝您的使用,再見!");
break;
}
}
switch(in)
{
case 1: //錄入
printf("/n----------------------------- 請輸入學員信息 -----------------------------");
input(stuhead);
break;
case 2: //插入
if(stuhead->sum!=0)
{
del(stuhead);
}
else
{
printf("/a沒有數據!/n"); //(如果學生人數爲0,彈出此消息)
}
break;
case 3: //刪除
if(stuhead->sum!=0)
{
select(stuhead);
}
else
{
printf("/a沒有數據!/n");
}
break;
case 4: //查找
if(stuhead->sum!=0)
{
display(stuhead);
}
else
{
printf("/a沒有數據!/n");
}
break;
case 5: //排序
if(stuhead->sum!=0)
{
sortready(stuhead);
display(stuhead);
}
else
{
printf("/a沒有數據!/n");
}
break;
case 6: //合計
if(stuhead->sum!=0)
{
total(stuhead);
}
else
{
printf("/a沒有數據!/n");
}
break;
case 7: //保存
save(stuhead);
break;
default :
break;
}
}while(1);
freelink(stuhead);
return 0;
}
/*建立單鏈表的函數*/
STULINK * creat()
{
/* *head保存表頭結點的指針,*p指向當前結點的前一個結點,*s指向當前結點*/
STULINK *head;
/*分配空間並檢測*/
if((head=(STULINK *)malloc(sizeof(STULINK)))==NULL)
{
printf("不能分配內存空間!");
return head;
}
/*把表頭結點的數據域置空*/
head->sname[0]='/0';
head->sno[0]='/0';
head->avr=0;
//記錄學生總人數
head->sum=0;
head->arscore[CPRJ]=0;
head->arscore[TD]=0;
head->arscore[LINUX]=0;
head->arscore[J2ME]=0;
head->arscore[CSENG]=0;
/*把表頭結點的鏈域置空*/
head->link=NULL;
/*p指向表頭結點*/
return(head);
}
/*查找鏈表的函數,其中h指針是鏈表的表頭指針,sno指針是要查找的學生的學號,
prev爲要查找的學生的前一個節點的指針(主要在刪除使使用)*/
STULINK * searchbysno(STULINK *head, char * sno, STULINK **prev)
{
/*當前指針,指向要與所查找的學號比較的結點*/
STULINK *p;
/*保存結點數據域內學號的指針*/
char *no;
p=head->link;
*prev=head;
while(p!=NULL)
{
no = p->sno;
/*把數據域裏的學號與所要查找的學號比較,若相同則返回0,即條件成立*/
if(strcmp(no, sno)==0)
/*返回與所要查找結點的地址*/
return(p);
else
{
*prev=p;
p=p->link;
}
}
printf("沒有查找到該數據!");
return(NULL);
}
STULINK * searchbysname(STULINK *head, char * sname, STULINK **prev)
{
/*當前指針,指向要與所查找的學生姓名比較的結點*/
STULINK *p;
/*保存結點數據域內學生姓名的指針*/
char *name;
p=head->link;
*prev=head;
while(p!=NULL)
{
name = p->sname;
/*把數據域裏的學號與所要查找的學生姓名比較,若相同則返回0,即條件成立*/
if(strcmp(name, sname)==0)
/*返回與所要查找結點的地址*/
return(p);
else
{
*prev=p;
p=p->link;
}
}
printf("沒有查找到該數據!");
return(NULL);
}
void insertbysno(STULINK *head, STULINK stu)
{
STULINK *p, *n;
p = head;
n = p->link;
while(n!=NULL)
{
if( strcmp( stu.sno, n->sno ) < 0 )
{
insert(head,p, stu);
return;
}
p = n;
n = p->link;
}
insert(head, p, stu);
}
/*插入函數,在指針p後插入*/
void insert(STULINK *head, STULINK *p, STULINK stu)
{
/*指針s是保存新結點地址的*/
STULINK *s;
if((s= (STULINK *) malloc(sizeof(STULINK)))==NULL)
{
printf("不能分配內存空間!");
exit(0);
}
/*把指針stuname所指向的數組元素拷貝給新結點的數據域*/
strcpy(s->sname,stu.sname);
strcpy(s->sno,stu.sno);
s->avr = stu.avr;
s->sum = stu.sum;
memcpy(s->arscore, stu.arscore, SUMSUBJ*sizeof(int));
head->sum++;
/*把新結點的鏈域指向原來p結點的後繼結點*/
s->link=p->link;
/*p結點的鏈域指向新結點*/
p->link=s;
}
/*刪除函數,其中dellink爲要刪除的結點的指針,prelink爲要刪除的結點的前一個結點的指針*/
void delstunode(STULINK *head, STULINK *prelink,STULINK *dellink)
{
STULINK *s;
s = dellink;
prelink->link = dellink->link;
free(s);
head->sum--;
}
// 主菜單函數
void menu()
{
printf(" *****************************************/n");
printf(" | 學生成績系統主菜單界面 |/n");
printf(" | |/n");
printf(" | 1.錄入學生成績 5.排序學生成績 |/n");
printf(" | |/n");
printf(" | 2.刪除學生成績 6.合計學生成績 |/n");
printf(" | |/n");
printf(" | 3.查找學生成績 7.存儲學生成績 |/n");
printf(" | |/n");
printf(" | 4.瀏覽學生成績 0.安全退出系統 |/n");
printf(" | |/n");
printf(" | |/n");
printf(" |----------->學生成績管理程序<----------|/n");
printf(" *****************************************/n");
printf(" 請在0~7之間選擇 :");
}
// 錄入函數
void input(STULINK *head)
{
int i;
char ch;
STULINK s;
do
{
printf("/n------------------------ 請輸入要插入的學員信息 ------------------------");
GETINPUTSTRDATA(STRSNO,s.sno);
GETINPUTSTRDATA(STRSNAME,s.sname);
GETINPUTINTDATA(STRC,s.arscore[CPRJ]);
CHECKINPUTFUNC(s.arscore[CPRJ]);
GETINPUTINTDATA(STRTD,s.arscore[TD]);
CHECKINPUTFUNC(s.arscore[TD]);
GETINPUTINTDATA(STRLINUX,s.arscore[LINUX]);
CHECKINPUTFUNC(s.arscore[LINUX]);
GETINPUTINTDATA(STRJ,s.arscore[J2ME]);
CHECKINPUTFUNC(s.arscore[J2ME]);
GETINPUTINTDATA(STREN,s.arscore[CSENG]);
CHECKINPUTFUNC(s.arscore[CSENG]);
s.sum=0;
for(i=0;i<SUMSUBJ;i++)
s.sum+=s.arscore[i];
s.avr=(float)(s.sum/5.0);
printf("/n總成績:%d",s.sum);
printf("/n平均成績:%lf",s.avr);
printf("/n/n");
insertbysno(head, s);
printf("是否繼續輸入?(y / n) ");
scanf(" %c",&ch);
printf("/n");
if(ch!='Y' && ch!='y')
{
break;
}
}while(1);
}
// 刪除函數,含子菜單:按學生證號刪除,按姓名刪除
void del(STULINK* head)
{
int in;
do
{
printf(" ************************/n");
printf(" | 1.按學生證號刪除 |/n");
printf(" | |/n");
printf(" | 2.學生按姓名刪除 |/n");
printf(" | |/n");
printf(" | 3.返回上一級菜單 |/n");
printf(" ************************/n");
printf(" 請在1~3之間選擇: ");
scanf("%d",&in);
if(in<1 || in>3)
{
printf("/a輸入有誤,請重新輸入!/n");
continue;
}
else
{
break;
}
}while(1);
switch(in)
{
case 1:
delbysno(head);
break;
case 2:
delbysname(head);
break;
case 3:
break;
default:
break;
}
}
// 刪除函數,按學生證號刪除
void delbysno(STULINK* head)
{
STULINK *p, *pre;
char strsno[15];
char ch;
p=NULL;
pre=NULL;
printf("/n-------------------- 請輸入要刪除的學員的學生證號 ------------------------");
do
{
printf("/n輸入學號: ");
scanf("%s",strsno);
if(strlen(strsno)>15)
printf("/n輸入的學號超過規定長度,請重新輸入!");
else
{
p = searchbysno(head, strsno, &pre);
if(p==NULL)
{
printf("/n您所輸入的學號並不存在 !");
printf("/n需要重新輸入請按(Y)鍵,其他任意鍵將放棄刪除!");
scanf(" %c",&ch);
printf("/n");
if(ch!='y' && ch!='Y')
return;
}
else
break;
}
}while(1);
printf(PRINTTITLE);
printf(PRINTSTYLE, p->sno,p->sname,p->arscore[CPRJ],p->arscore[TD],
p->arscore[LINUX],p->arscore[J2ME],p->arscore[CSENG],
p->sum,p->avr);
printf("/n確定要刪除嗎?(Y / N)");
scanf(" %c",&ch);
printf("/n");
if(ch=='y' || ch=='Y')
{
delstunode(head, pre, p );
printf("刪除成功/n");
}
}
// 刪除函數,按學生姓名刪除
void delbysname(STULINK* head)
{
STULINK *p, *pre;
char strsname[10];
char ch;
p=NULL;
pre=NULL;
printf("/n-------------------- 請輸入要刪除的學生的姓名 ------------------------");
do
{
printf("/n輸入學號: ");
scanf("%s",strsname);
if(strlen(strsname)>10)
printf("/n你輸入的是日本人的名字嗎?超過了規定長度,請重新輸入!");
else
{
p = searchbysname(head, strsname, &pre);
if(p==NULL)
{
printf("/n您所輸入的學生姓名並不存在 !");
printf("/n需要重新輸入請按(Y)鍵,其他任意鍵將放棄刪除!");
scanf(" %c",&ch);
printf("/n");
if(ch!='y' && ch!='Y')
return;
}
else
break;
}
}while(1);
printf(PRINTTITLE);
printf(PRINTSTYLE, p->sno,p->sname,p->arscore[CPRJ],p->arscore[TD],
p->arscore[LINUX],p->arscore[J2ME],p->arscore[CSENG],
p->sum,p->avr);
printf("/n確定要刪除嗎?(Y / N)");
scanf(" %c",&ch);
printf("/n");
if(ch=='y' || ch=='Y')
{
delstunode(head, pre, p );
printf("刪除成功/n");
}
}
// 查找函數,含子程序:按學生證號查找,按姓名查找
void select(STULINK* head)
{
int in;
do
{
printf(" ************************/n");
printf(" | 1.按學生證號查找 |/n");
printf(" | |/n");
printf(" | 2.按學生姓名查找 |/n");
printf(" | |/n");
printf(" | 3.返回上一級菜單 |/n");
printf(" ************************/n");
printf(" 請在1~3之間選擇: ");
scanf("%d",&in);
if(in<1 || in>3)
{
printf("/a輸入有誤,請重新輸入!/n");
continue;
}
else
{
break;
}
}while(1);
switch(in)
{
case 1:
selectsno(head);
break;
case 2:
selectsname(head);
break;
case 3:
break;
default:
break;
}
}
// 查找函數,按學生證號查找學員信息
void selectsno(STULINK* head)
{
STULINK *p, *pre;
char strsno[15];
char ch;
p=NULL;
pre=NULL;
printf("/n-------------------- 請輸入要查詢的學員的學生證號 ------------------------");
do
{
printf("/n輸入學號: ");
scanf("%s",strsno);
if(strlen(strsno)>15)
printf("/n輸入的學號超過規定長度,請重新輸入!");
else
{
p = searchbysno(head, strsno, &pre);
if(p==NULL)
{
printf("/n您所輸入的學號並不存在 !");
printf("/n需要重新輸入請按(Y)鍵,其他任意鍵將放棄查詢!");
scanf("%c",&ch);
printf("/n");
if(ch!='y' && ch!='Y')
return;
}
else
break;
}
}while(1);
printf(PRINTTITLE);
printf(PRINTSTYLE, p->sno,p->sname,p->arscore[CPRJ],p->arscore[TD],
p->arscore[LINUX],p->arscore[J2ME],p->arscore[CSENG],
p->sum,p->avr);
}
// 查找函數,按姓名查找學員信息
void selectsname(STULINK* head)
{
STULINK *p, *pre;
char strsname[10];
char ch;
p=NULL;
pre=NULL;
printf("/n-------------------- 請輸入要查詢的學生的姓名 ------------------------");
do
{
printf("/n輸入學號: ");
scanf("%s",strsname);
if(strlen(strsname)>10)
printf("/n你輸入的是日本人的名字嗎?超過了規定長度,請重新輸入!");
else
{
p = searchbysname(head, strsname, &pre);
if(p==NULL)
{
printf("/n您所輸入的學生姓名並不存在 !");
printf("/n需要重新輸入請按(Y)鍵,其他任意鍵將放棄查詢!");
scanf("%c",&ch);
printf("/n");
if(ch!='y' && ch!='Y')
return;
}
else
break;
}
}while(1);
printf(PRINTTITLE);
printf(PRINTSTYLE, p->sno,p->sname,p->arscore[CPRJ],p->arscore[TD],
p->arscore[LINUX],p->arscore[J2ME],p->arscore[CSENG],
p->sum,p->avr);
}
//按各門具體課程的成績排序
void sortbyscore(STULINK* head)
{
int in;
do
{
printf(" ********************************/n");
printf(" | 下面是可排序的課程的名稱 |/n");
printf(" | |/n");
printf(" | 1.C企業要求與實踐 |/n");
printf(" | |/n");
printf(" | 2.TD-SCDMA |/n");
printf(" | |/n");
printf(" | 3.LINUX |/n");
printf(" | |/n");
printf(" | 4.J2ME |/n");
printf(" | |/n");
printf(" | 5.專業英語 |/n");
printf(" | |/n");
printf(" | 6.返回上一級菜單 |/n");
printf(" ********************************/n");
printf(" 請在1~6之間選擇: ");
scanf("%d",&in);
if(in<1 || in>6)
{
printf("/a輸入有誤,請重新輸入!/n");
continue;
}
else
{
break;
}
}while(1);
if( in != 6 )
sort(head,OFFSETSCORE+(in-1)*sizeof(int), INTTYPE);
}
// 排序界面函數,含子菜單:按學生證號排序,按姓名排序,按課程成績排序(包括五門課程),按總成績來排序
void sortready(STULINK* head)
{
int in;
do
{
printf(" ****************************/n");
printf(" | 1.按學生證號排序 |/n");
printf(" | |/n");
printf(" | 2.按學生姓名排序 |/n");
printf(" | |/n");
printf(" | 3.按學生單科成績排序 |/n");
printf(" | |/n");
printf(" | 4.按學生總成績排序 |/n");
printf(" | |/n");
printf(" | 5.返回上一級菜單 |/n");
printf(" ****************************/n");
printf(" 請在1~5之間選擇: ");
scanf("%d",&in);
if(in<1 || in>5)
{
printf("/a輸入有誤,請重新輸入!/n");
continue;
}
else
{
break;
}
}while(1);
switch(in)
{
case 1:
sort(head,OFFSETSNO, STRTYPE);
break;
case 2:
sort(head, OFFSETSNAME, STRTYPE);
break;
case 3:
sortbyscore(head);
break;
case 4:
sort(head, OFFSETSUM, INTTYPE);
break;
case 5:
break;
default:
break;
}
}
// 排序函數,按成績從高到低排序,學號或姓名按字符由小到大排序
void sort(STULINK *head, int offset, int type)
{
int i,j,sum;
int *numdest,*numsrc;
float *fdest, *fsrc;
char *strdest,*strsrc;
int isswap=0;
STULINK *p,*q,*prev;
sum=head->sum;
for(i=0;i<sum-1;i++)
{
prev = head;
p=head->link;
q=p->link;
for(j=0;j<sum-1-i;j++)
{
isswap = 0;
switch(type)
{
case INTTYPE:
numsrc=(int*)((char*)p+offset);
numdest=(int*)((char*)q+offset);
if(*numsrc < *numdest )
isswap=1;
break;
case FLOATTYPE:
fsrc=(float*)((char*)p+offset);
fdest=(float*)((char*)q+offset);
if(*fsrc < *fdest )
isswap=1;
break;
case STRTYPE:
strsrc = (char*)((char*)p+offset);
strdest = (char*)((char*)q+offset);
if( strcmp(strsrc,strdest)>0 )
isswap=1;
break;
default:
return;
}
if( isswap == 1 )
{
p->link = q->link;
q->link = p;
prev->link = q;
p = prev->link;
q = p->link;
}
prev = prev->link;
p = p->link;
q = q->link;
}
}
}
// 製表函數,將所有學員成績以表格形式輸出
void display(STULINK* head)
{
STULINK *p;
printf("------------------------------------------------------");
printf(PRINTTITLE);
p=head->link;
while(p!=NULL)
{
printf(PRINTSTYLE, p->sno,p->sname,p->arscore[CPRJ],p->arscore[TD],
p->arscore[LINUX],p->arscore[J2ME],p->arscore[CSENG],
p->sum,p->avr);
p = p->link;
}
printf("------------------------------------------------------/n");
}
// 合計函數,將3門學科的個人成績,總分,平均分輸出
void total(STULINK* head)
{
int i;
int arsum[SUMSUBJ];
float aravr[SUMSUBJ];
int stusum=head->sum;
STULINK *p;
p = head->link;
printf("/n/t班級總人數 | C企業要求與實踐 | TD-SCDMA | LINUX | J2ME | 專業英語/n/n");
for(i=0;i<SUMSUBJ;i++)
{
arsum[i]=0;
}
while(p!=NULL)
{
for(i=0;i<SUMSUBJ;i++)
{
arsum[i]+=p->arscore[i];
}
p = p->link;
}
for(i=0;i<SUMSUBJ;i++)
{
aravr[i] = (float)arsum[i] / stusum;
}
printf("合計:/t %d/t/t %d/t/t %d/t %d/t %d/t %d/n",stusum, arsum[0],arsum[1],arsum[2],arsum[3],arsum[4]);
printf("平均分:/t/t/t %.2f/t/t %.2f/t %.2f %.2f/t %.2f/n",aravr[0],aravr[1],aravr[2],aravr[3],aravr[4]);
printf("/n");
}
// 保存函數,將數據保存到student.dat文件下
void save(STULINK* head)
{
FILE *fp;
STULINK *p;
fp=fopen("student.dat","w");
if(fp==NULL)
{
printf("文件保存失敗!/n");
return;
}
else
{
p=head->link;
while(p!=NULL)
{
fwrite(p,sizeof(STULINK),1,fp);
p = p->link;
}
printf("數據成功保存到程序下的student.dat文件中!/n");
}
fclose(fp);
}
// 讀取函數,提取student.txt文件中的數據
void load(STULINK* head)
{
int i;
FILE *fp;
int counter=0;
STULINK stu;
STULINK* p;
int readcount;
fp=fopen("student.dat","r+");
if(fp==NULL)
{
printf("/a文件打開失敗!/n");
return;
}
else
{
i=0;
p = head;
while((readcount=fread(&stu,sizeof(STULINK),1,fp))>0)
{
insert( head, p ,stu );
i++;
}
head->sum = i; //在讀取循環過程中counter多加了一次,所以在循環結束後自身減1
// 讀取完畢後打印出來
if( i > 0 )
{
sort(head, OFFSETSNO, STRTYPE);
display(head);
}
}
}
void freelink(STULINK* head)
{
STULINK *p, *q;
p = head;
while(p!=NULL)
{
q = p;
p = p->link;
free(q);
}
}