C語言實現(xiàn)學生成績管理系統(tǒng)實戰(zhàn)教學
趁著放假無事,開始用C語言開發(fā)一些小的項目,鞏固基礎知識的同時學習新的知識。
學生成績管理系統(tǒng)實現(xiàn)的功能有:成績錄入、學生成績查詢、刪除、修改、通過文件保存等。
開發(fā)這樣一個系統(tǒng)需要具備的知識:線性表(鏈表)、文件操作、排序(如果需要成績排序)。
開發(fā)環(huán)境為VS2015;在Linux下沒有conio.h的頭文件,需要修改與getch()函數(shù)相關的代碼。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> /*學生信息結構體*/ typedef struct Node { char Name[10]; //學生姓名 char ID[15]; //學生學號 int Score[3]; //三科成績(數(shù)學、英語、數(shù)據(jù)結構) float Ave_Sco; struct Node *next; }Lnode; void Display(); /*界面顯示函數(shù)*/ void GetScore(Lnode *&h); /*成績錄入函數(shù)*/ void PrintScore(Lnode *h); /*成績打印函數(shù)*/ void ModifyScore(Lnode *h); /*成績修改函數(shù)*/ void FindInf(Lnode *h); /*查找信息*/ void Delete(Lnode *h); /*刪除函數(shù)*/ void Quit(Lnode *h); /*退出函數(shù)*/ void SaveInf(Lnode *h); void LoadInf(Lnode *h); /*初始化鏈表*/ void InitList(Lnode *&head) { head = (Lnode *)malloc(sizeof(Lnode)); if (head == NULL) { printf("error!"); exit(1); } head->next = NULL; //使頭節(jié)點指針域為空 } int main() { Lnode *ScoreList; //建立成績鏈表,所有學生信息存放在此鏈表 int Function; char flag; int t = 0; InitList(ScoreList); LoadInf(ScoreList); while (1) { Display(); printf("請選擇操作: "); scanf("%d", &Function); switch (Function) { case 1: while (1) { GetScore(ScoreList); printf("是否繼續(xù)輸入 (Y/N)"); scanf("%s", &flag); if (flag == 'N' || flag == 'n')break; } system("cls"); break; case 2: PrintScore(ScoreList); _getch(); system("cls"); break; case 3: ModifyScore(ScoreList); system("cls"); break; case 4: FindInf(ScoreList); _getch(); system("cls"); break; case 5: Delete(ScoreList); _getch(); system("cls"); break; case 6: Quit(ScoreList); break; default: printf("Error!??! 請重新輸入:"); break; } //switch結束 } return 0; } /*系統(tǒng)界面顯示*/ void Display() { printf("\t\t**********************************************\n"); printf("\t\t*************歡迎使用成績管理系統(tǒng)*************\n"); printf("\t\t**********************************************\n"); printf("\t\t\t\t1、錄入成績\n"); printf("\t\t\t\t2、打印成績\n"); printf("\t\t\t\t3、修改成績\n"); printf("\t\t\t\t4、查找學生信息\n"); printf("\t\t\t\t5、刪除學生信息\n"); printf("\t\t\t\t6、退出系統(tǒng)\n"); printf("\n\n\n\n\n\n"); } /*成績錄入*/ void GetScore(Lnode *&h) { Lnode *p, *q = h; char name[10], id[15]; int Math, English, Datastruct; p = (Lnode *)malloc(sizeof(Lnode)); //為學生信息申請節(jié)點 printf("請依次輸入學生信息:\n"); printf("姓名 學號 數(shù)學 英語 數(shù)據(jù)結構\n"); scanf("%s %s %d %d %d", &name, &id, &Math, &English, &Datastruct); for (; q->next != NULL; q = q->next){;} //移動到尾節(jié)點 strcpy(p->Name, name); strcpy(p->ID, id); p->Score[0] = Math; p->Score[1] = English; p->Score[2] = Datastruct; p->Ave_Sco = ((float)((p->Score[0] + p->Score[1] + p->Score[2]) - 150)) / 30; p->next = NULL; q->next = p; q = p; } /*成績打印*/ void PrintScore(Lnode *h) { Lnode *p = h->next; printf("%-14s%-8s%-8s%-8s%-8s%-8s\n","排名", "學號", "姓名", "數(shù)學", "英語", "數(shù)據(jù)結構", "平均績點"); while (p != NULL) { printf("%-14s%-8s%-8d%-8d%-8d%.2f\n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2], p->Ave_Sco); p = p->next; } } /*成績修改*/ void ModifyScore(Lnode *h) { Lnode *p = h->next; char name[10], id[15]; int Math, English, Datastruct; printf("請輸入學生姓名:"); scanf("%s", name); printf("請輸入學生學號:"); scanf("%s", id); while (p) { if (strcmp(p->Name, name)==0 && strcmp(p->ID, id)==0) { printf("當前學生信息:\n"); printf("%-14s%-8s%-8s%-8s%-8s\n", "學號", "姓名", "數(shù)學", "英語", "數(shù)據(jù)結構"); printf("%-14s%-8s%-8d%-8d%-8d\n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2]); printf("請輸入更正后的數(shù)學成績:"); scanf("%d", &Math); printf("請輸入更正后的英語成績:"); scanf("%d", &English); printf("請輸入更正后的數(shù)據(jù)結構成績:"); scanf("%d", &Datastruct); p->Score[0] = Math; p->Score[1] = English; p->Score[2] = Datastruct; break; } else { p = p->next; } }//while循環(huán)結束 } /*信息查找*/ void FindInf(Lnode *h) { Lnode *p = h->next; char name[10], id[15]; printf("請輸入學生姓名:"); scanf("%s", name); printf("請輸入學生學號:"); scanf("%s", id); while (p) { if (strcmp(p->Name, name) == 0 && strcmp(p->ID, id) == 0) { printf("當前學生信息:\n"); printf("%-14s%-8s%-8s%-8s%-8s\n", "學號", "姓名", "數(shù)學", "英語", "數(shù)據(jù)結構"); printf("%-14s%-8s%-8d%-8d%-8d\n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2]); break; } else { p = p->next; } }//while循環(huán)結束 } /*刪除*/ void Delete(Lnode *h) { Lnode *p = h, *q; q = p->next; char name[10], id[15]; printf("請輸入學生姓名:"); scanf("%s", name); printf("請輸入學生學號:"); scanf("%s", id); while (q) { if (strcmp(q->Name, name) == 0 && strcmp(q->ID, id) == 0) { p->next = q->next; free(q); //刪除p節(jié)點 printf("刪除成功\n"); break; } else { p = p->next; q = q->next; } }//while循環(huán)結束 } /*退出系統(tǒng)*/ void Quit(Lnode *h) { SaveInf(h); //退出時保存信息 exit(0); } /*打開文件*/ void LoadInf(Lnode *h) { Lnode *p = h; Lnode *q; //臨時變量 用于保存從文件中讀取的信息 FILE* file = fopen("./Information.dat", "rb"); if (!file) { printf("文件打開失??!"); return ; } /* 使用feof判斷文件是否為結束要注意的問題: 當讀取文件結束時,feof函數(shù)不會立即設置標志符為-1,而是 需要再讀取一次后,才會設置。所以要先讀一次。 */ q = (Lnode *)malloc(sizeof(Lnode)); fread(q, sizeof(Lnode), 1, file); while (!feof(file)) //一直讀到文件末尾 { p->next = q; p = q; q = (Lnode *)malloc(sizeof(Lnode)); fread(q, sizeof(Lnode), 1, file); } //while循環(huán)結束 p->next = NULL; fclose(file); } /*保存信息到文件中*/ void SaveInf(Lnode *h) { Lnode *p = h->next; int flag; FILE* file = fopen("./Information.dat", "wb"); if (!file) { printf("文件打開失??!"); return; } while (p != NULL) { flag = fwrite(p, sizeof(Lnode), 1, file); //將p的內(nèi)容寫到文件中 if (flag != 1) { break; } p = p->next; } fclose(file); }
雖然是很簡單的小項目,還是有很多問題。
一:鏈表相關
在寫成績錄入和成績打印功能時,發(fā)現(xiàn)始終只能保存(沒加入文件保存)最后一個數(shù)據(jù),確定鏈表的相關操作沒有問題,仔細判斷邏輯關系后,發(fā)現(xiàn)是每次在頭節(jié)點傳到GetScore()函數(shù),為新節(jié)點申請內(nèi)存后,直接將數(shù)據(jù)保存在了新申請的節(jié)點里面,沒有將鏈表移動到尾節(jié)點,導致每次錄入成績,都會覆蓋前一次輸入的數(shù)據(jù)。解決辦法是鏈表傳到函數(shù)后,先移動到最后一個節(jié)點,將新申請的節(jié)點掛接在最后一個節(jié)點之后。
/*成績錄入*/ void GetScore(Lnode *&h) { Lnode *p, *q = h; char name[10], id[15]; int Math, English, Datastruct; p = (Lnode *)malloc(sizeof(Lnode)); //為學生信息申請節(jié)點 printf("請依次輸入學生信息:\n"); printf("姓名 學號 數(shù)學 英語 數(shù)據(jù)結構\n"); scanf("%s %s %d %d %d", &name, &id, &Math, &English, &Datastruct); for (; q->next != NULL; q = q->next){;} //移動到尾節(jié)點 //保存數(shù)據(jù) strcpy(p->Name, name); strcpy(p->ID, id); p->Score[0] = Math; p->Score[1] = English; p->Score[2] = Datastruct; p->Ave_Sco = ((float)((p->Score[0] + p->Score[1] + p->Score[2]) - 150)) / 30; //始終指向最后一個節(jié)點 p->next = NULL; q->next = p; q = p; }
二、文件操作
用文件保存遇到的問題主要是每次打印數(shù)據(jù)時除正常數(shù)據(jù)外,始終多一行亂碼。判斷方法是while(!feof(file))。排除錯誤時確定了兩種可能性:多保存了一行;多讀取了一行。經(jīng)過某度feof()與EOF的關系后,確定是多讀取了一行數(shù)據(jù)。
用feof()函數(shù)進行文件尾判斷時,當文件已經(jīng)到達尾部后,還需要在讀取一次后,feof()函數(shù)才會返回-1,所以會出現(xiàn)多讀一次的情況;解決辦法時,在循環(huán)讀取之前先將第一個數(shù)據(jù)讀取出來,然后在正常讀取。即注意多讀一次的問題。
/*打開文件*/ void LoadInf(Lnode *h) { Lnode *p = h; Lnode *q; //臨時變量 用于保存從文件中讀取的信息 FILE* file = fopen("./Information.dat", "rb"); if (!file) { printf("文件打開失??!"); return ; } /* 使用feof判斷文件是否為結束要注意的問題: 當讀取文件結束時,feof函數(shù)不會立即設置標志符為-1,而是 需要再讀取一次后,才會設置。所以要先讀一次。 */ q = (Lnode *)malloc(sizeof(Lnode)); fread(q, sizeof(Lnode), 1, file); while (!feof(file)) //一直讀到文件末尾 { p->next = q; p = q; q = (Lnode *)malloc(sizeof(Lnode)); fread(q, sizeof(Lnode), 1, file); } //while循環(huán)結束 p->next = NULL; fclose(file); }
相關文章
使用?c++?在?windows?上定時執(zhí)行一個函數(shù)的示例代碼
這篇文章主要介紹了使用c++在windows上穩(wěn)定定時執(zhí)行一個函數(shù),本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07C語言?超詳細介紹與實現(xiàn)線性表中的無頭單向非循環(huán)鏈表
無頭單向非循環(huán)鏈表:結構簡單,一般不會單獨用來存數(shù)據(jù)。實際中更多是作為其他數(shù)據(jù)結構的子結構,如哈希桶、圖的鄰接表等等。另外這種結構在筆試面試中出現(xiàn)很多2022-03-03VSCode配置C/C++并添加非工作區(qū)頭文件的方法
這篇文章主要介紹了VSCode配置C/C++并添加非工作區(qū)頭文件的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03