C語言實現(xiàn)學(xué)生成績管理系統(tǒng)實戰(zhàn)教學(xué)
趁著放假無事,開始用C語言開發(fā)一些小的項目,鞏固基礎(chǔ)知識的同時學(xué)習(xí)新的知識。
學(xué)生成績管理系統(tǒng)實現(xiàn)的功能有:成績錄入、學(xué)生成績查詢、刪除、修改、通過文件保存等。
開發(fā)這樣一個系統(tǒng)需要具備的知識:線性表(鏈表)、文件操作、排序(如果需要成績排序)。
開發(fā)環(huán)境為VS2015;在Linux下沒有conio.h的頭文件,需要修改與getch()函數(shù)相關(guān)的代碼。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> /*學(xué)生信息結(jié)構(gòu)體*/ typedef struct Node { char Name[10]; //學(xué)生姓名 char ID[15]; //學(xué)生學(xué)號 int Score[3]; //三科成績(數(shù)學(xué)、英語、數(shù)據(jù)結(jié)構(gòu)) 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; //建立成績鏈表,所有學(xué)生信息存放在此鏈表 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結(jié)束 } 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、查找學(xué)生信息\n"); printf("\t\t\t\t5、刪除學(xué)生信息\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)); //為學(xué)生信息申請節(jié)點 printf("請依次輸入學(xué)生信息:\n"); printf("姓名 學(xué)號 數(shù)學(xué) 英語 數(shù)據(jù)結(jié)構(gòu)\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","排名", "學(xué)號", "姓名", "數(shù)學(xué)", "英語", "數(shù)據(jù)結(jié)構(gòu)", "平均績點"); 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("請輸入學(xué)生姓名:"); scanf("%s", name); printf("請輸入學(xué)生學(xué)號:"); scanf("%s", id); while (p) { if (strcmp(p->Name, name)==0 && strcmp(p->ID, id)==0) { printf("當(dāng)前學(xué)生信息:\n"); printf("%-14s%-8s%-8s%-8s%-8s\n", "學(xué)號", "姓名", "數(shù)學(xué)", "英語", "數(shù)據(jù)結(jié)構(gòu)"); printf("%-14s%-8s%-8d%-8d%-8d\n", p->ID, p->Name, p->Score[0], p->Score[1], p->Score[2]); printf("請輸入更正后的數(shù)學(xué)成績:"); scanf("%d", &Math); printf("請輸入更正后的英語成績:"); scanf("%d", &English); printf("請輸入更正后的數(shù)據(jù)結(jié)構(gòu)成績:"); scanf("%d", &Datastruct); p->Score[0] = Math; p->Score[1] = English; p->Score[2] = Datastruct; break; } else { p = p->next; } }//while循環(huán)結(jié)束 } /*信息查找*/ void FindInf(Lnode *h) { Lnode *p = h->next; char name[10], id[15]; printf("請輸入學(xué)生姓名:"); scanf("%s", name); printf("請輸入學(xué)生學(xué)號:"); scanf("%s", id); while (p) { if (strcmp(p->Name, name) == 0 && strcmp(p->ID, id) == 0) { printf("當(dāng)前學(xué)生信息:\n"); printf("%-14s%-8s%-8s%-8s%-8s\n", "學(xué)號", "姓名", "數(shù)學(xué)", "英語", "數(shù)據(jù)結(jié)構(gòu)"); 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)結(jié)束 } /*刪除*/ void Delete(Lnode *h) { Lnode *p = h, *q; q = p->next; char name[10], id[15]; printf("請輸入學(xué)生姓名:"); scanf("%s", name); printf("請輸入學(xué)生學(xué)號:"); 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)結(jié)束 } /*退出系統(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判斷文件是否為結(jié)束要注意的問題: 當(dāng)讀取文件結(jié)束時,feof函數(shù)不會立即設(shè)置標(biāo)志符為-1,而是 需要再讀取一次后,才會設(shè)置。所以要先讀一次。 */ 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)結(jié)束 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); }
雖然是很簡單的小項目,還是有很多問題。
一:鏈表相關(guān)
在寫成績錄入和成績打印功能時,發(fā)現(xiàn)始終只能保存(沒加入文件保存)最后一個數(shù)據(jù),確定鏈表的相關(guān)操作沒有問題,仔細(xì)判斷邏輯關(guān)系后,發(fā)現(xiàn)是每次在頭節(jié)點傳到GetScore()函數(shù),為新節(jié)點申請內(nèi)存后,直接將數(shù)據(jù)保存在了新申請的節(jié)點里面,沒有將鏈表移動到尾節(jié)點,導(dǎo)致每次錄入成績,都會覆蓋前一次輸入的數(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)); //為學(xué)生信息申請節(jié)點 printf("請依次輸入學(xué)生信息:\n"); printf("姓名 學(xué)號 數(shù)學(xué) 英語 數(shù)據(jù)結(jié)構(gòu)\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的關(guān)系后,確定是多讀取了一行數(shù)據(jù)。
用feof()函數(shù)進(jìn)行文件尾判斷時,當(dāng)文件已經(jīng)到達(dá)尾部后,還需要在讀取一次后,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判斷文件是否為結(jié)束要注意的問題: 當(dāng)讀取文件結(jié)束時,feof函數(shù)不會立即設(shè)置標(biāo)志符為-1,而是 需要再讀取一次后,才會設(shè)置。所以要先讀一次。 */ 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)結(jié)束 p->next = NULL; fclose(file); }
- C語言編寫學(xué)生成績管理系統(tǒng)
- 學(xué)生成績管理系統(tǒng)C語言代碼實現(xiàn)
- C語言利用結(jié)構(gòu)體數(shù)組實現(xiàn)學(xué)生成績管理系統(tǒng)
- C語言學(xué)生成績管理系統(tǒng)源代碼
- C語言實現(xiàn)簡單學(xué)生成績管理系統(tǒng)
- C語言結(jié)構(gòu)體版學(xué)生成績管理系統(tǒng)
- 使用C語言實現(xiàn)學(xué)生成績管理系統(tǒng)
- C語言實現(xiàn)學(xué)生成績管理系統(tǒng)
- C語言學(xué)生成績管理系統(tǒng)課程設(shè)計
- 基于C語言實現(xiàn)簡單學(xué)生成績管理系統(tǒng)
相關(guān)文章
c語言中位字段與結(jié)構(gòu)聯(lián)合的組合使用詳解
本篇文章是對c語言中位字段與結(jié)構(gòu)聯(lián)合的組合使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05使用?c++?在?windows?上定時執(zhí)行一個函數(shù)的示例代碼
這篇文章主要介紹了使用c++在windows上穩(wěn)定定時執(zhí)行一個函數(shù),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07C語言?超詳細(xì)介紹與實現(xiàn)線性表中的無頭單向非循環(huán)鏈表
無頭單向非循環(huán)鏈表:結(jié)構(gòu)簡單,一般不會單獨用來存數(shù)據(jù)。實際中更多是作為其他數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),如哈希桶、圖的鄰接表等等。另外這種結(jié)構(gòu)在筆試面試中出現(xiàn)很多2022-03-03VSCode配置C/C++并添加非工作區(qū)頭文件的方法
這篇文章主要介紹了VSCode配置C/C++并添加非工作區(qū)頭文件的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03