C語言編寫學生成績管理系統
阿新 • • 發佈:2018-12-17
這個《學生成績管理系統》是以前大一的時候的課設,今天整理檔案的時候發現了,就直接把程式碼貼到部落格上吧。挺基礎的一個東西,就是涉及到C語言實現的連結串列,以及檔案操作,結構體的序列化儲存與讀取等。
DataType.h
/* 編譯環境:VS2017\Windows10 作者:smallerXuan 指導: */ #ifndef ___DDATA_TYPE__ #define ___DDATA_TYPE__ typedef struct grades //成績 { char id[20]; //學號 char subject[20]; //科目 float grade; //成績 }Grade; typedef struct GradeDataNode //成績節點 { Grade grades; struct GradeDataNode *Pnext; }GradeData; typedef struct studentInformation //學生資訊 { char Class[30]; //班級 char name[30]; //姓名 char id[20]; //學號 }StudentInformation; typedef struct StudentNode //學生節點 { StudentInformation studentinfor; struct StudentNode *Next; }Student; extern GradeData *pHeader_g,*pTail_g; //成績連結串列頭、尾 extern Student *pHeader_s,*pTail_s; //學生連結串列頭、尾 extern char textGradeDataFile[20]; //成績資料檔名稱 extern char textStudentDataFile[20]; //學生資料檔名稱 extern int isModified; //記錄修改是否成功 #endif
StudentInfor.h
/* 編譯環境:VS2017\Windows10 作者:smallerXuan 指導: */ #ifndef ___STUDENT_INFOR_H #define ___STUDENT_INFOR_H #include "DataType.h" //對成績資料及成績節點的基本操作函式(共10個) void inputGradeData(Grade *pGrade); // 輸入成績 void inputGradeDataNode(GradeData *pGradeNode); // 輸入成績節點 void printGradeData(Grade *pGrade); // 輸出成績 void printGradeDataNode(GradeData *pGradeNode); // 輸出成績節點 void printGradeDataAll(); // 輸出所有成績節點 void addAtGradeTail(GradeData *pNewNode_g); // 在成績尾部新增節點 void deleteGradeNode(GradeData *pDeleted); // 刪除成績節點 void deleteGradeAll(); // 刪除所有成績節點 void editGradeNode(GradeData *pEdited); // 編輯成績節點 GradeData *findAGradeData(); // 通過學號和科目 查詢到準確的成績節點 //對學生資料及學生節點的基本操作函式(共10個) void inputStudentInformation(StudentInformation *pStudentInfor); // 輸入學生資訊 void inputStudentNode(Student *pStudentNode); // 輸入學生節點 void printStudentInformation(StudentInformation *pStuInfor); // 輸出學生資訊 void printStudentNode(Student *pStudentNode); // 輸出學生節點 void printStudentNodeAll(); // 輸出所有學生節點 void addAtStudentTail(Student *pNewNoStudentNode); // 在學生尾部新增節點 void deleteStudentNode(Student *pDeleate); // 刪除學生節點 void deleteStudentAll(); // 刪除所有學生節點 void editStudentNode(Student *pEdite); // 編輯學生節點 Student *findByStudentId(); // 通過學生ID查詢學生節點 #endif
Menu.h
/* 編譯環境:VS2017\Windows10 作者:smallerXuan 指導: */ #ifndef ___MENU_H_ #define ___MENU_H_ #include <stdio.h> #include <stdlib.h> //提供 malloc() 和 free() 原型和定義 #include "DataType.h" #include "StudentInfor.h" //對介面的基本操作及響應函式(共6組,36個) // 主選單 void drawMainMenu(); //繪製主選單 void doMainMenu(); //主選單響應 void onMenuitemExit(); //在選單退出 // 檔案管理 void drawFileManagementMenu(); //繪製 檔案管理 子選單 void doFileManagementMenu(); //檔案管理 子選單 響應 void openGradeDataFromTextFile(); //從文字讀入 成績資料 void saveGradeDataInTextFile(); //儲存成績資料到文字 void saveStudentDataInTextFile(); //儲存學生資料到文字 void openStudentDataFromTextFile(); //從文字讀入 學生資料 // 資料維護 void drawDataMaintenanceMenu(); //繪製 資料維護 子選單 void doDataMaintenanceMenu(); //資料維護 子選單 響應 void drawDataMaintenanceMenu_s(); //繪製 資料維護 二級子選單(成績) void doDataMaintenanceMenu_s(); //資料維護 二級子選單(成績)響應 void onMenueitemAddGrade(); //在選單新增成績記錄 void onMenuitemEditeGrade(); //在選單編輯成績 void onMenuitemDeleteGrade(); //在選單刪除成績節點 void drawDataMaintenanceMenu_g(); //繪製 資料維護 二級子選單(學生) void doDataMaintenanceMenu_g(); //資料維護 二級子選單(學生)響應 void onMenueitemAddStudent(); //在選單新增學生記錄 void onMenuitemEditeStudent(); //在選單編輯學生 void onMenuitemDeleteStudent(); //在選單刪除學生節點 // 資料查詢 void drawDataQueryMenu(); //繪製 資料查詢 子選單 void doDataQueryMenu(); //資料查詢 子選單 響應 void drawStudentDataQueryMenu(); //繪製 資料查詢 二級子選單(學生) void doStudentDataQueryMenu(); //資料查詢 二級子選單(學生) 響應 void onMenueitemBrowseStudent(); //在選單瀏覽學生資料 void onMenueitemSearchStudent(); //在選單查詢學生資料 void drawGradeDataQueryMenu(); //繪製 資料查詢 二級子選單(成績) void doGradeDataQueryMenu(); //資料查詢 二級子選單(成績) 響應 void onMenueitemBrowseGradeData(); //在選單瀏覽成績資料 void onMenueitemSearchGradeData(); //在選單查詢成績資料 // 資料統計 void doDataCensuMenu(); //資料統計 子選單 響應 void drawDataCensuMenu(); //繪製 資料統計 子選單 void onMenueitemStatisticsStudent(); //在選單統計學生成績資訊 //幫助文件 void drawHelpDocumentMenu(); //繪製 幫助文件 子選單 void doHelpDocumentMenu(); //幫助文件 子選單 響應 #endif
StudentInfor.c
/*
編譯環境:VS2017\Windows10
作者:smallerXuan
指導:
*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "DataType.h"
#include "StudentInfor.h"
//輸入成績
void inputGradeData(Grade *pGrade)
{
printf("學號:");
scanf("%s",&(pGrade->id));
printf("學科:");
scanf("%s",&(pGrade->subject));
printf("成績:");
scanf("%f",&(pGrade->grade));
}
//輸入成績節點
void inputGradeDataNode(GradeData *pGradeNode)
{
inputGradeData(&(pGradeNode->grades)); //輸入成績節點的成績
}
//輸出成績
void printGradeData(Grade *pGrade)
{
printf("\t%s\t%s\t%f\n",pGrade->id, pGrade->subject, pGrade->grade);
}
//輸出成績節點
void printGradeDataNode(GradeData *pGradeNode)
{
printGradeData(&(pGradeNode->grades)); //列印成績節點的成績
}
//輸出所有成績節點
void printGradeDataAll()
{
GradeData *p = pHeader_g; //指標指向成績節的頭
if(p == NULL)
{
puts("沒有成績記錄");
}
else
{
printf("\t%s\t%s\t%s\n","學號","科目", "成績" );
while(p!=NULL)
{
printGradeDataNode(p);
p=p->Pnext;
}
}
}
//在成績尾部新增
void addAtGradeTail(GradeData *pNewNode_g)
{
if(pHeader_g == NULL) //無頭時
{
pHeader_g = pTail_g = pNewNode_g;
}
else
{
pTail_g->Pnext = pNewNode_g;
pTail_g = pNewNode_g;
}
}
//刪除成績節點
void deleteGradeNode(GradeData *pDeleted)
{
GradeData *p,*q; //成績節點型指標 p, q
p= q= pHeader_g; //p,q 賦值為成績頭指標
while(p!= pDeleted) //當要刪除的節點不是頭節點時 ,迴圈判斷直到p為要刪除的節點
{
q= p; //q 儲存 P
p= p->Pnext; //p 指向該節點的 Pnext
}
if(p== pHeader_g) //如果p為頭節點 ,此時頭為p的後一個節點,即頭部後移
{
pHeader_g= p->Pnext; //頭指標指向該節點的Pnext
}
else if(p== pTail_g) //如果 p為 尾節點
{
q->Pnext= NULL; //q 的Pnext置空
pTail_g= q; //尾節點改為q ,此時尾為p的前一個節點,即尾部前移
}
else //普通節點時
{
q->Pnext= p->Pnext; //將該節點的前一個節點的Pnext設定為該節點的Pnext
}
free(p); //釋放p
if(pHeader_g == NULL) //如果頭部為空則尾部也置空
{
pTail_g= NULL;
}
}
//刪除所有成績
void deleteGradeAll()
{
GradeData *p;
p= pHeader_g;
while(pHeader_g != NULL) //當頭部不為空時
{
pHeader_g=p->Pnext; //頭部後移
free(p); //釋放頭部
p=pHeader_g; //p 指向新頭部
}
pHeader_g = pTail_g = NULL; //頭、尾置空
}
//編輯成績節點
void editGradeNode(GradeData *pEdited)
{
printf("輸入成績資訊:");
inputGradeDataNode(pEdited); //呼叫函式 輸入成績節點
}
//通過學號和科目 查詢到準確的成績節點
GradeData *findAGradeData()
{
GradeData *p;
int result = 0;
int result1,result2;
char buffer[30];
char buffer1[30];
char buffer2[30];
gets(buffer); //清除緩衝區殘留
printf("輸入查詢學號:");
scanf("%s",&buffer1);
gets(buffer); //清除緩衝區殘留
printf("輸入查詢科目:");
scanf("%s",&buffer2);
p= pHeader_g;
while(p!= NULL && !result) //迴圈判斷,直至p 指向連結串列尾部
{
result1= strcmp(buffer1,(p->grades.id)); //對輸入的學號和 成績節點中的 學號進行 基於字串的比較
result2= strcmp(buffer2,(p->grades.subject)); //對輸入的科目和 成績節點中的 科目進行 基於字串的比較
if(result1 == 0 && result2 == 0) //如果學號和科目相同
{
return p;
}
else //不同時,指標p後移動
{
p = p->Pnext;
}
}
return NULL;
}
//輸入學生資訊
void inputStudentInformation(StudentInformation *pStudentInfor)
{
char buffer[50]; //用於消除Scanf() 快取區殘留
printf("任意鍵繼續。。。。\n");
gets(buffer);
printf("班級:");
scanf("%s",pStudentInfor->Class);
gets(buffer);
printf("姓名:");
scanf("%s",pStudentInfor->name);
gets(buffer);
printf("學號:");
scanf("%s",pStudentInfor->id);
}
//輸入學生節點
void inputStudentNode(Student*pStudentNode)
{
inputStudentInformation(&(pStudentNode->studentinfor));
}
//輸出學生資訊
void printStudentInformation(StudentInformation *pStuInfor)
{
printf("\n");
printf("\t%s",pStuInfor->Class);
printf("\t%s",pStuInfor->name);
printf("\t%s",pStuInfor->id);
printf("\n");
}
//輸出學生節點
void printStudentNode(Student *pStudentNode)
{
printStudentInformation(&(pStudentNode->studentinfor));
}
//輸出所有學生節點
void printStudentNodeAll()
{
Student *p= pHeader_s;
if(p == NULL)
{
puts("沒有記錄\n");
exit(-1);
}
else
{
printf("\t%s\t%s\t%s","班級","姓名","學號");
while(p!= NULL)
{
printStudentNode(p);
p= p->Next;
}
}
}
//在學生尾部新增節點
void addAtStudentTail(Student *pNewNoStudentNode)
{
if(pHeader_s==NULL) //無頭時
{
pHeader_s= pTail_s= pNewNoStudentNode;
}
else
{
pTail_s->Next= pNewNoStudentNode;
pTail_s= pNewNoStudentNode;
}
}
//刪除學生節點
void deleteStudentNode(Student *pDeleate)
{
Student *p,*q; //學生節點型指標 p, q
p= q= pHeader_s; //p,q 賦值為成績頭指標
while(p!= pDeleate) //找到要刪除的學生節點 記為 p
{
q= p; //q 儲存 P
p= p->Next; //p 賦值為 p->Next
}
if(p == pHeader_s) //如果是頭
{
pHeader_s= p->Next;
}
else if(p == pTail_s) //如果是尾
{
q->Next= NULL;
pTail_s= q;
}
else
{
q->Next= p->Next;
}
free(p);
if(pHeader_s== NULL)
{
pTail_s= NULL;
}
}
//刪除所有學生節點
void deleteStudentAll()
{
Student *p;
p= pHeader_s;
while(pHeader_s != NULL) //當頭部不為空時
{
pHeader_s=p->Next; //頭部後移
free(p); //釋放頭部
p=pHeader_s; //p 指向新頭部
}
pHeader_s = pTail_s = NULL; //頭、尾置空
}
//編輯學生節點
void editStudentNode(Student *pEdite)
{
printf("請輸入學生資訊:\n");
inputStudentNode(pEdite);
}
//通過學生ID查詢
Student *findByStudentId()
{
Student *p; //學生節點型指標 *p
int result;
char buffer[30];
gets(buffer); //清除緩衝區殘留
printf("輸入查詢學號:");
scanf("%s",&buffer);
p= pHeader_s;
while(p!= NULL) //迴圈判斷,直至p 指向連結串列尾部
{
result= strcmp(buffer,(p->studentinfor.id)); //對輸入的學號和 學生節點中的 學號進行 基於字串的比較
if(result == 0 ) //如果學號相同
{
return p;
}
else //不同時,指標p後移動
{
p = p->Next;
}
}
return NULL;
}
Menu.c
/*
編譯環境:VS2017\Windows10
作者:smallerXuan
指導:
*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "Menu.h"
#include "StudentInfor.h"
//繪製主選單
void drawMainMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t學生成績管理系統 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 系統主介面 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、檔案管理 ========== 請按F(f) ##\n");
printf("\t## ##\n");
printf("\t##\t2、資料維護 ========== 請按M(m) ##\n");
printf("\t## ##\n");
printf("\t##\t3、資料查詢 ========== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t4、資料統計 ========== 請按C(c) ##\n");
printf("\t## ##\n");
printf("\t##\t5、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t6、退出系統 ========== 請按Q(q) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//主選單響應
void doMainMenu()
{
int done = 0;
char cmd[2];
openGradeDataFromTextFile(); //從文字讀入成績資料
openStudentDataFromTextFile(); //從文字讀入學生資料
system("pause");
while(!done)
{
char buffer[1000];
drawMainMenu(); //繪製主選單
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'F':
case 'f':
doFileManagementMenu(); //檔案管理 子選單 響應
break;
case 'M':
case 'm':
doDataMaintenanceMenu(); //資料維護 子選單 響應
break;
case 'S':
case 's':
doDataQueryMenu(); //資料查詢 子選單 響應
break;
case 'C':
case 'c':
doDataCensuMenu(); //資料統計 子選單 響應
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'Q':
case 'q':
onMenuitemExit(); //在選單退出
break;
default:
printf("輸入有誤,請從新輸入");
}
}
saveGradeDataInTextFile(); //退出系統預設儲存成績資料
saveStudentDataInTextFile(); //退出系統預設儲存學生資料
system("pause");
}
//在選單退出
void onMenuitemExit()
{
char cmd[2];
if(isModified);
{
puts("資料已修改,是否存檔?");
scanf("%s",cmd);
if(cmd[0]== 'Y' || cmd[0]=='y') //存檔,退出成績
{
//onMenuitemSave();
saveGradeDataInTextFile(); //儲存成績資料
saveStudentDataInTextFile(); //儲存學生資料
system("pause");
exit(0);
}
}
//deleteAll();
deleteStudentAll(); // 刪除所有學生節點
deleteGradeAll(); // 刪除所有成績節點
}
//繪製 檔案管理 子選單
void drawFileManagementMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 檔案管理 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、匯入檔案 ========== 請按O(o) ##\n");
printf("\t## ##\n");
printf("\t##\t2、儲存檔案 ========== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t4、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//檔案管理子選單響應
void doFileManagementMenu()
{
int done = 0;
char cmd[2];
while(!done)
{ char buffer[1000];
drawFileManagementMenu(); //繪製 檔案管理 子選單
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'O':
case 'o':
openGradeDataFromTextFile(); //從文字讀入 成績 資料
openStudentDataFromTextFile(); //從文字讀入 學生 資料
break;
case 'S':
case 's':
saveGradeDataInTextFile(); //儲存 成績 資料 到文字
saveStudentDataInTextFile(); //儲存 學生 資料 到文字
system("pause");
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
// 從文字讀入成績資料
void openGradeDataFromTextFile()
{
/*
//隨機讀寫版本
long int q,len, nowfp,diff; //q儲存偏移差值,len檔案尾偏移量,nowfp當前偏移量, diff偏移差值
long int d=0;
GradeData *newGradeDataNode= NULL;
FILE *inFile= NULL;
deleteGradeAll(); //在讀取文字前 清空所有連結串列節點
inFile= fopen(textGradeDataFile,"rt"); //用fopen()只讀開啟一個文字檔案,只允許讀資料
if(inFile==NULL)
{
printf("無法開啟文字 %s.txt",textGradeDataFile);
exit(-1);
}
nowfp =ftell(inFile);
fseek(inFile, 0,SEEK_END); //移動檔案指標到檔案尾部
len =ftell(inFile); //獲取當前檔案針相對檔案首部的偏移量
fseek(inFile, 0,SEEK_SET); //移動檔案指標到檔案頭部
q= nowfp =ftell(inFile); //獲取並儲存當前偏移量
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中開闢空間
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
free(newGradeDataNode); //釋放臨時儲存區
nowfp =ftell(inFile); //獲取當前偏移量
diff= nowfp - q + 1; //得到一次讀取偏移差值
fseek(inFile, 0,SEEK_SET); //移動檔案指標到檔案頭部
nowfp =ftell(inFile); //獲取當前偏移量
//while(!feof(inFile));
if(nowfp== len)
{
printf("\n從檔案讀入資料\n");
}
while(nowfp <= (len-diff))
{
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中開闢空間
if(newGradeDataNode ==NULL)
{
puts("記憶體不足,無法讀取資料");
}
else
{
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
nowfp=ftell(inFile); //更新當前偏移量
addAtGradeTail(newGradeDataNode); //在成績尾部新增節點
}
d++;
}
fclose(inFile);
printf("\n已讀入%d條成績資訊\n",d);
*/
GradeData *newGradeDataNode= NULL;
FILE *inFile= NULL;
int d=0;
deleteGradeAll(); //在讀取文字前 清空所有連結串列節點
inFile= fopen(textGradeDataFile,"rt"); //用fopen()只讀開啟一個文字檔案,只允許讀資料
if(inFile==NULL)
{
printf("無法開啟文字 %s.txt",textGradeDataFile);
exit(-1);
}
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中開闢空間
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
while(!feof(inFile))
{
addAtGradeTail(newGradeDataNode); //在成績尾部新增節點
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中開闢空間
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
d++;
}
free(newGradeDataNode);
fclose(inFile);
printf("已經讀入: %d",d);
}
// 儲存成績資料到文字
void saveGradeDataInTextFile()
{
GradeData *p= pHeader_g;
FILE *outFile= NULL;
int d=0;
outFile= fopen(textGradeDataFile,"wt"); //用fopen()只寫開啟或建立一個文字檔案,只允許寫資料
if(outFile == NULL)
{
printf("無法開啟文字 %s.txt",textGradeDataFile);
}
if(p== NULL)
{
puts("沒有記錄!");
}
else
{
while(p!= NULL)
{
fprintf(outFile,"%15s%15s%15f\n",p->grades.id,p->grades.subject,p->grades.grade);
p= p->Pnext;
d++;
}
}
fclose(outFile);
printf("成績資料已儲存%d\n",d);
}
//從文字讀入 學生資料
void openStudentDataFromTextFile()
{
long int q,len, nowfp,diff; //q儲存偏移差值,len檔案尾偏移量,nowfp當前偏移量, diff偏移差值
long int d=0;
Student *newStudentDataNode= NULL;
FILE *inFile= NULL;
deleteStudentAll(); //在讀取文字前 清空所有連結串列節點
inFile= fopen(textStudentDataFile,"rt"); //用fopen()只讀開啟一個文字檔案,只允許讀資料
if(inFile==NULL)
{
printf("無法開啟文字 %d.txt",textStudentDataFile);
exit(-1);
}
nowfp =ftell(inFile);
fseek(inFile, 0,SEEK_END); //移動檔案指標到檔案尾部
len =ftell(inFile); //獲取當前檔案針相對檔案首部的偏移量
fseek(inFile, 0,SEEK_SET); //移動檔案指標到檔案頭部
q= nowfp =ftell(inFile); //獲取並儲存當前偏移量
newStudentDataNode= (Student*)malloc(sizeof(Student)); //在堆中開闢空間
newStudentDataNode->Next= NULL;
fscanf(inFile,"%s%s%s",&(newStudentDataNode->studentinfor).Class,&(newStudentDataNode->studentinfor).name,&(newStudentDataNode->studentinfor).id);
free(newStudentDataNode); //釋放臨時儲存區
nowfp =ftell(inFile); //獲取當前偏移量
diff= nowfp - q + 1; //得到一次讀取偏移差值
fseek(inFile, 0,SEEK_SET); //移動檔案指標到檔案頭部
nowfp =ftell(inFile); //獲取當前偏移量
//while(!feof(inFile));
while(nowfp <= (len-diff))
{
newStudentDataNode= (Student*)malloc(sizeof(Student)); //在堆中開闢空間
if(newStudentDataNode ==NULL)
{
puts("記憶體不足,無法讀取資料");
}
else
{
newStudentDataNode->Next= NULL;
fscanf(inFile,"%s%s%s",&(newStudentDataNode->studentinfor).Class,&(newStudentDataNode->studentinfor).name,&(newStudentDataNode->studentinfor).id);
nowfp=ftell(inFile); //更新當前偏移量
addAtStudentTail(newStudentDataNode); //在學生尾部新增節點
}
d++;
}
fclose(inFile);
printf("已讀入%d條學生資訊\n",d);
}
//儲存學生資料到文字
void saveStudentDataInTextFile()
{
Student *p= pHeader_s;
FILE *outFile= NULL;
int d=0;
outFile= fopen(textStudentDataFile,"wt"); //用fopen()只寫開啟或建立一個文字檔案,只允許寫資料
if(outFile == NULL)
{
printf("無法開啟文字 %s.txt",textStudentDataFile);
}
if(p== NULL)
{
puts("沒有記錄!");
}
else
{
while(p!= NULL)
{
fprintf(outFile,"%15s%15s%15s\n",p->studentinfor.Class,p->studentinfor.name,p->studentinfor.id);
p= p->Next;
d++;
}
}
fclose(outFile);
printf("\n學生資料已儲存%d條\n",d);
}
//繪製 資料維護 子選單
void drawDataMaintenanceMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 資料維護 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、學生資料維護 ======== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、成績資料維護 ======== 請按G(g) ##\n");
printf("\t## ##\n");
printf("\t##\t4、使用幫助 ======== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ======== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//資料維護 子選單 響應
void doDataMaintenanceMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataMaintenanceMenu(); //資料維護 子選單
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'S':
case 's':
doDataMaintenanceMenu_s(); // 資料維護 二級子選單(學生)響應
break;
case 'G':
case 'g':
doDataMaintenanceMenu_g(); // 資料維護 二級子選單(成績)響應
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
// 繪製 資料維護 二級子選單(學生)
void drawDataMaintenanceMenu_s()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 學生資料維護 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、新增記錄 ========== 請按A(a) ##\n");
printf("\t## ##\n");
printf("\t##\t2、修改記錄 ========== 請按E(e) ##\n");
printf("\t## ##\n");
printf("\t##\t3、刪除記錄 ========== 請按D(d) ##\n");
printf("\t## ##\n");
printf("\t##\t4、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
// 資料維護 二級子選單(學生)響應
void doDataMaintenanceMenu_s()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataMaintenanceMenu_s(); // 繪製 資料維護 二級子選單(學生)
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'A':
case 'a':
onMenueitemAddStudent(); //在選單新增學生記錄
break;
case 'E':
case 'e':
onMenuitemEditeStudent(); //在選單編輯學生
break;
case 'D':
case 'd':
onMenuitemDeleteStudent(); //在選單刪除學生節點
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
// 在選單新增學生記錄
void onMenueitemAddStudent()
{
Student *newNode; //建立新學生節點記錄
newNode= (Student*) malloc(sizeof(Student)); //依據學生結構體的資料大小在堆中分配記憶體
if(newNode == NULL) //當記憶體分配失敗時
{
puts("記憶體不足,無法建立");
exit(-1);
}
system ("cls");
inputStudentNode(newNode); // 輸入學生節點
newNode->Next= NULL;
addAtStudentTail(newNode); // 在學生尾部新增節點
puts("記錄新增成功! ");
printStudentNode(pTail_s); // 輸出學生節點
system ("pause");
isModified= 1;
}
//在選單編輯學生
void onMenuitemEditeStudent()
{
Student *pFound;
printf("請輸入要編輯的學生的相關資訊:\n");
pFound= findByStudentId(); //pFound 為通過學生ID查詢到的學生節點
if(pFound != NULL)
{
system("cls");
editStudentNode(pFound); //通過pFound 編輯學生節點
printf("記錄已修改 。\n");
printStudentNode(pFound); //列印修改後的學生節點
isModified= 1; //標識修改成功
}
else
{
puts("沒有要修改的記錄!");
}
system("pause");
}
//在選單刪除學生節點
void onMenuitemDeleteStudent()
{
Student *pFound;
printf("請輸入要刪除學生的相關資訊:\n");
pFound= findByStudentId(); //pFound 為通過學號查詢到的結果
if(pFound != NULL)
{
system("cls");
deleteStudentNode(pFound); //通過pFound 刪除成績節點
printf("記錄已刪除 。\n");
printStudentNodeAll(); //輸出所有學生節點
isModified= 1; //標識修改成功
}
else
{
puts("沒有要刪除的記錄!");
}
system("pause");
}
//繪製 資料維護 二級子選單(成績)
void drawDataMaintenanceMenu_g()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 成績資料維護 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、新增記錄 ========== 請按A(a) ##\n");
printf("\t## ##\n");
printf("\t##\t2、修改記錄 ========== 請按E(e) ##\n");
printf("\t## ##\n");
printf("\t##\t3、刪除記錄 ========== 請按D(d) ##\n");
printf("\t## ##\n");
printf("\t##\t4、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//資料維護 二級子選單(成績)響應
void doDataMaintenanceMenu_g()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataMaintenanceMenu_g(); //繪製 資料維護 二級子選單(成績)
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'A':
case 'a':
onMenueitemAddGrade(); //在選單新增成績記錄
break;
case 'E':
case 'e':
onMenuitemEditeGrade(); //在選單編輯成績
break;
case 'D':
case 'd':
onMenuitemDeleteGrade(); //在選單刪除成績節點
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
//在選單新增成績記錄
void onMenueitemAddGrade()
{
GradeData *newNode; //建立新成績節點記錄
newNode= (GradeData*) malloc(sizeof(GradeData)); //依據成績結構體的資料大小在堆中分配記憶體
if(newNode == NULL) //當記憶體分配失敗時
{
puts("記憶體不足,無法建立");
exit(-1);
}
system ("cls");
inputGradeDataNode(newNode); //輸入成績節點資訊
newNode->Pnext= NULL;
addAtGradeTail(newNode); //在成績連結串列尾部新增
puts("記錄新增成功! ");
printGradeDataNode(pTail_g); //輸出已新增的成績節點
system ("pause");
isModified= 1;
}
//在選單編輯成績
void onMenuitemEditeGrade()
{
GradeData *pFound= findAGradeData(); //pFound 為通過學號和科目查詢到的結果
if(pFound != NULL)
{
system("cls");
editGradeNode(pFound); //通過pFound 編輯成績節點
printf("記錄已修改 。\n");
printGradeDataNode(pFound); //列印修改後的節點
isModified= 1; //標識修改成功
}
else
{
puts("沒有要修改的記錄!");
}
system("pause");
}
//在選單刪除成績節點
void onMenuitemDeleteGrade()
{
GradeData *pFound= findAGradeData(); //pFound 為通過學號和科目查詢到的結果
if(pFound != NULL)
{
system("cls");
deleteGradeNode(pFound); //通過pFound 刪除成績節點
printf("記錄已刪除 。\n");
printGradeDataAll(); //輸出所有成績節點
isModified= 1; //標識修改成功
}
else
{
puts("沒有要刪除的記錄!");
}
system("pause");
}
//繪製 資料查詢 子選單
void drawDataQueryMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 資料查詢 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、學生資料 ========== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、成績資料 ========== 請按G(g) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
// 資料查詢 子選單 響應
void doDataQueryMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataQueryMenu(); //繪製 資料查詢 子選單
printf("任意鍵繼續。\n");
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'S':
case 's':
doStudentDataQueryMenu(); //資料查詢 二級子選單(學生) 響應
break;
case 'G':
case 'g':
doGradeDataQueryMenu(); //資料查詢 二級子選單(成績) 響應
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
//繪製 資料查詢 二級子選單(學生)
void drawStudentDataQueryMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 學生資料查詢 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、瀏覽資料 ========== 請按B(B) ##\n");
printf("\t## ##\n");
printf("\t##\t2、查詢資料 ========== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//資料查詢 二級子選單(學生) 響應
void doStudentDataQueryMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawStudentDataQueryMenu(); //繪製 資料查詢 二級子選單(學生)
printf("任意鍵繼續。\n");
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'B':
case 'b':
onMenueitemBrowseStudent(); //在選單瀏覽學生資料
break;
case 'S':
case 's':
onMenueitemSearchStudent(); //在選單查詢學生資料
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
//在選單瀏覽學生資料
void onMenueitemBrowseStudent()
{
printStudentNodeAll(); // 輸出所有學生節點
system("pause");
}
//在選單查詢學生資料
void onMenueitemSearchStudent()
{
Student *pFound;
pFound= findByStudentId(); // pFound為通過學生ID查詢到的學生節點
if(pFound != NULL)
{
printStudentNode(pFound); // 輸出查詢到的學生節點
}
else
{
puts("未查詢到相關資訊!");
}
system("pause");
}
//繪製 資料查詢 二級子選單(成績)
void drawGradeDataQueryMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 成績資料查詢 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、瀏覽資料 ========== 請按B(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、查詢資料 ========== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//資料查詢 二級子選單(成績) 響應
void doGradeDataQueryMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawGradeDataQueryMenu(); //繪製 資料查詢 二級子選單(成績)
printf("任意鍵繼續。\n");
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'B':
case 'b':
onMenueitemBrowseGradeData(); //在選單瀏覽成績資料
break;
case 'S':
case 's':
onMenueitemSearchGradeData(); //在選單查詢成績資料
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
//在選單瀏覽成績資料
void onMenueitemBrowseGradeData()
{
printGradeDataAll(); // 輸出所有成績節點
system("pause");
}
//在選單查詢成績資料
void onMenueitemSearchGradeData()
{
GradeData *pFound;
pFound= findAGradeData(); // pFound為通過學生ID和科目查詢到的成績節點
if(pFound != NULL)
{
printGradeDataNode(pFound); // 輸出查詢到的成績節點
}
else
{
puts("未查詢到相關資訊!");
}
system("pause");
}
// 繪製 資料統計 子選單
void drawDataCensuMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 資料統計 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、學生統計 ========== 請按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、使用幫助 ========== 請按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t3、返回 ========== 請按R(r) ##\n");
printf("\t## ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//資料統計 子選單 響應
void doDataCensuMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataCensuMenu(); // 繪製 資料統計 子選單
printf("任意鍵繼續。\n");
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'S':
case 's':
onMenueitemStatisticsStudent(); //在選單統計學生成績資訊
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //幫助文件 子選單 響應
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
//在選單統計學生成績資訊
void onMenueitemStatisticsStudent()
{
Student *pFound;
GradeData *p= pHeader_g; //指標指向成績節的頭
char buffer[30];
char buffer1[30];
int result = 0;
float Sumgrade=0.0; //總成績
float num=0.0; //科目數
gets(buffer); //清除緩衝區殘留
printf("輸入查詢學號:");
scanf("%s",&buffer1);
pFound= findByStudentId(); // pFound為通過學生ID查詢到的學生節點
if(pFound != NULL)
{
printStudentNode(pFound); // 輸出查詢到的學生節點
}
else
{
puts("未查詢到相關學生資訊!");
}
if(p == NULL)
{
puts("沒有成績記錄");
}
while(p!= NULL) //迴圈判斷,直至p 指向連結串列尾部
{
result= strcmp(buffer1,(p->grades.id)); //對輸入的學號和 成績節點中的 學號進行 基於字串的比較
if(result == 0 ) //如果學號相同
{
printGradeDataNode(p); // 輸出成績節點
Sumgrade+=p->grades.grade; //成績增加
num++; //科目數增加
}
p = p->Pnext; //不同時,指標p後移動
}
if(num== 0.0)
num=1.0;
printf("\n\t總成績:%f\t平均成績: %f\n",Sumgrade,Sumgrade/num);
system("pause");
}
// 繪製 幫助文件 子選單
void drawHelpDocumentMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 使用幫助 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t ##\n");
printf("\t## ##\n");
printf("\t##\t1、請依照介面提示進行相應輸入 ##\n");
printf("\t## ##\n");
printf("\t##\t ##\n");
printf("\t##\t2、返回 ========== 請按R(r) ##\n");
printf("\t##\t ##\n");
printf("\t## ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//幫助文件 子選單 響應
void doHelpDocumentMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawHelpDocumentMenu(); // 繪製 幫助文件 子選單
gets(buffer);
printf("請輸入選項:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'R':
case 'r':
done = 1;
break;
default:
printf("輸入有誤,請從新輸入");
}
}
}
StudentAchievementManagementSystemStart.c
/*
編譯環境:VS2017\Windows10
作者:smallerXuan
指導:
*/
#include <stdio.h>
#include "DataType.h"
#include "StudentInfor.h"
#include "Menu.h"
GradeData *pHeader_g=NULL,*pTail_g=NULL; //成績連結串列頭、尾
Student *pHeader_s=NULL,*pTail_s=NULL; //學生連結串列頭、尾
char textGradeDataFile[20]= "textGradeDataFile"; //成績資料檔名稱
char textStudentDataFile[20]= "textStudentDataFile"; //學生資料檔名稱
int isModified=0; //記錄修改是否成功
int main (void)
{
doMainMenu();
return 0;
}