C語(yǔ)言實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng)實(shí)戰(zhàn)教學(xué)
趁著放假無(wú)事,開始用C語(yǔ)言開發(fā)一些小的項(xiàng)目,鞏固基礎(chǔ)知識(shí)的同時(shí)學(xué)習(xí)新的知識(shí)。
學(xué)生成績(jī)管理系統(tǒng)實(shí)現(xiàn)的功能有:成績(jī)錄入、學(xué)生成績(jī)查詢、刪除、修改、通過(guò)文件保存等。
開發(fā)這樣一個(gè)系統(tǒng)需要具備的知識(shí):線性表(鏈表)、文件操作、排序(如果需要成績(jī)排序)。
開發(fā)環(huán)境為VS2015;在Linux下沒(méi)有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é)號(hào)
int Score[3]; //三科成績(jī)(數(shù)學(xué)、英語(yǔ)、數(shù)據(jù)結(jié)構(gòu))
float Ave_Sco;
struct Node *next;
}Lnode;
void Display(); /*界面顯示函數(shù)*/
void GetScore(Lnode *&h); /*成績(jī)錄入函數(shù)*/
void PrintScore(Lnode *h); /*成績(jī)打印函數(shù)*/
void ModifyScore(Lnode *h); /*成績(jī)修改函數(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é)點(diǎn)指針域?yàn)榭?
}
int main()
{
Lnode *ScoreList; //建立成績(jī)鏈表,所有學(xué)生信息存放在此鏈表
int Function;
char flag;
int t = 0;
InitList(ScoreList);
LoadInf(ScoreList);
while (1)
{
Display();
printf("請(qǐng)選擇操作: ");
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?。?! 請(qǐng)重新輸入:");
break;
} //switch結(jié)束
}
return 0;
}
/*系統(tǒng)界面顯示*/
void Display()
{
printf("\t\t**********************************************\n");
printf("\t\t*************歡迎使用成績(jī)管理系統(tǒng)*************\n");
printf("\t\t**********************************************\n");
printf("\t\t\t\t1、錄入成績(jī)\n");
printf("\t\t\t\t2、打印成績(jī)\n");
printf("\t\t\t\t3、修改成績(jī)\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");
}
/*成績(jī)錄入*/
void GetScore(Lnode *&h)
{
Lnode *p, *q = h;
char name[10], id[15];
int Math, English, Datastruct;
p = (Lnode *)malloc(sizeof(Lnode)); //為學(xué)生信息申請(qǐng)節(jié)點(diǎn)
printf("請(qǐng)依次輸入學(xué)生信息:\n");
printf("姓名 學(xué)號(hào) 數(shù)學(xué) 英語(yǔ) 數(shù)據(jù)結(jié)構(gòu)\n");
scanf("%s %s %d %d %d", &name, &id, &Math, &English, &Datastruct);
for (; q->next != NULL; q = q->next){;} //移動(dòng)到尾節(jié)點(diǎn)
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;
}
/*成績(jī)打印*/
void PrintScore(Lnode *h)
{
Lnode *p = h->next;
printf("%-14s%-8s%-8s%-8s%-8s%-8s\n","排名", "學(xué)號(hào)", "姓名", "數(shù)學(xué)", "英語(yǔ)", "數(shù)據(jù)結(jié)構(gòu)", "平均績(jī)點(diǎn)");
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;
}
}
/*成績(jī)修改*/
void ModifyScore(Lnode *h)
{
Lnode *p = h->next;
char name[10], id[15];
int Math, English, Datastruct;
printf("請(qǐng)輸入學(xué)生姓名:");
scanf("%s", name);
printf("請(qǐng)輸入學(xué)生學(xué)號(hào):");
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é)號(hào)", "姓名", "數(shù)學(xué)", "英語(yǔ)", "數(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("請(qǐng)輸入更正后的數(shù)學(xué)成績(jī):");
scanf("%d", &Math);
printf("請(qǐng)輸入更正后的英語(yǔ)成績(jī):");
scanf("%d", &English);
printf("請(qǐng)輸入更正后的數(shù)據(jù)結(jié)構(gòu)成績(jī):");
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("請(qǐng)輸入學(xué)生姓名:");
scanf("%s", name);
printf("請(qǐng)輸入學(xué)生學(xué)號(hào):");
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é)號(hào)", "姓名", "數(shù)學(xué)", "英語(yǔ)", "數(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("請(qǐng)輸入學(xué)生姓名:");
scanf("%s", name);
printf("請(qǐng)輸入學(xué)生學(xué)號(hào):");
scanf("%s", id);
while (q)
{
if (strcmp(q->Name, name) == 0 && strcmp(q->ID, id) == 0)
{
p->next = q->next;
free(q); //刪除p節(jié)點(diǎn)
printf("刪除成功\n");
break;
}
else
{
p = p->next;
q = q->next;
}
}//while循環(huán)結(jié)束
}
/*退出系統(tǒng)*/
void Quit(Lnode *h)
{
SaveInf(h); //退出時(shí)保存信息
exit(0);
}
/*打開文件*/
void LoadInf(Lnode *h)
{
Lnode *p = h;
Lnode *q; //臨時(shí)變量 用于保存從文件中讀取的信息
FILE* file = fopen("./Information.dat", "rb");
if (!file)
{
printf("文件打開失敗!");
return ;
}
/*
使用feof判斷文件是否為結(jié)束要注意的問(wèn)題:
當(dāng)讀取文件結(jié)束時(shí),feof函數(shù)不會(huì)立即設(shè)置標(biāo)志符為-1,而是
需要再讀取一次后,才會(huì)設(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);
}
雖然是很簡(jiǎn)單的小項(xiàng)目,還是有很多問(wèn)題。
一:鏈表相關(guān)
在寫成績(jī)錄入和成績(jī)打印功能時(shí),發(fā)現(xiàn)始終只能保存(沒(méi)加入文件保存)最后一個(gè)數(shù)據(jù),確定鏈表的相關(guān)操作沒(méi)有問(wèn)題,仔細(xì)判斷邏輯關(guān)系后,發(fā)現(xiàn)是每次在頭節(jié)點(diǎn)傳到GetScore()函數(shù),為新節(jié)點(diǎn)申請(qǐng)內(nèi)存后,直接將數(shù)據(jù)保存在了新申請(qǐng)的節(jié)點(diǎn)里面,沒(méi)有將鏈表移動(dòng)到尾節(jié)點(diǎn),導(dǎo)致每次錄入成績(jī),都會(huì)覆蓋前一次輸入的數(shù)據(jù)。解決辦法是鏈表傳到函數(shù)后,先移動(dòng)到最后一個(gè)節(jié)點(diǎn),將新申請(qǐng)的節(jié)點(diǎn)掛接在最后一個(gè)節(jié)點(diǎn)之后。
/*成績(jī)錄入*/
void GetScore(Lnode *&h)
{
Lnode *p, *q = h;
char name[10], id[15];
int Math, English, Datastruct;
p = (Lnode *)malloc(sizeof(Lnode)); //為學(xué)生信息申請(qǐng)節(jié)點(diǎn)
printf("請(qǐng)依次輸入學(xué)生信息:\n");
printf("姓名 學(xué)號(hào) 數(shù)學(xué) 英語(yǔ) 數(shù)據(jù)結(jié)構(gòu)\n");
scanf("%s %s %d %d %d", &name, &id, &Math, &English, &Datastruct);
for (; q->next != NULL; q = q->next){;} //移動(dòng)到尾節(jié)點(diǎn)
//保存數(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;
//始終指向最后一個(gè)節(jié)點(diǎn)
p->next = NULL;
q->next = p;
q = p;
}
二、文件操作
用文件保存遇到的問(wèn)題主要是每次打印數(shù)據(jù)時(shí)除正常數(shù)據(jù)外,始終多一行亂碼。判斷方法是while(!feof(file))。排除錯(cuò)誤時(shí)確定了兩種可能性:多保存了一行;多讀取了一行。經(jīng)過(guò)某度f(wàn)eof()與EOF的關(guān)系后,確定是多讀取了一行數(shù)據(jù)。
用feof()函數(shù)進(jìn)行文件尾判斷時(shí),當(dāng)文件已經(jīng)到達(dá)尾部后,還需要在讀取一次后,feof()函數(shù)才會(huì)返回-1,所以會(huì)出現(xiàn)多讀一次的情況;解決辦法時(shí),在循環(huán)讀取之前先將第一個(gè)數(shù)據(jù)讀取出來(lái),然后在正常讀取。即注意多讀一次的問(wèn)題。
/*打開文件*/
void LoadInf(Lnode *h)
{
Lnode *p = h;
Lnode *q; //臨時(shí)變量 用于保存從文件中讀取的信息
FILE* file = fopen("./Information.dat", "rb");
if (!file)
{
printf("文件打開失??!");
return ;
}
/*
使用feof判斷文件是否為結(jié)束要注意的問(wèn)題:
當(dāng)讀取文件結(jié)束時(shí),feof函數(shù)不會(huì)立即設(shè)置標(biāo)志符為-1,而是
需要再讀取一次后,才會(huì)設(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語(yǔ)言編寫學(xué)生成績(jī)管理系統(tǒng)
- 學(xué)生成績(jī)管理系統(tǒng)C語(yǔ)言代碼實(shí)現(xiàn)
- C語(yǔ)言利用結(jié)構(gòu)體數(shù)組實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng)
- C語(yǔ)言學(xué)生成績(jī)管理系統(tǒng)源代碼
- C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng)
- C語(yǔ)言結(jié)構(gòu)體版學(xué)生成績(jī)管理系統(tǒng)
- 使用C語(yǔ)言實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng)
- C語(yǔ)言實(shí)現(xiàn)學(xué)生成績(jī)管理系統(tǒng)
- C語(yǔ)言學(xué)生成績(jī)管理系統(tǒng)課程設(shè)計(jì)
- 基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng)
相關(guān)文章
海量數(shù)據(jù)處理系列之:用C++實(shí)現(xiàn)Bitmap算法
本篇文章是對(duì)用C++實(shí)現(xiàn)Bitmap算法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語(yǔ)言編程之預(yù)處理過(guò)程與define及條件編譯
這篇文章主要為大家介紹了C語(yǔ)言編程之預(yù)處理過(guò)程與define及條件編譯,文中通過(guò)圖文及示例代碼方式作了詳細(xì)的解釋,有需要的朋友可以借鑒參考下2021-09-09
通過(guò)c++11改進(jìn)我們的模式之改進(jìn)命令模式
這篇我要講的是如何使用c++11改進(jìn)命令模式,感興趣的朋友可以看下2013-11-11
C++?點(diǎn)(.)和箭頭(->)運(yùn)算符用法小結(jié)
在C++中,點(diǎn)運(yùn)算符(.)用于訪問(wèn)類的成員變量和成員函數(shù),而箭頭運(yùn)算符(->)用于通過(guò)指針訪問(wèn)類的成員變量和成員函數(shù),本文就來(lái)詳細(xì)的介紹一下如何使用,感興趣的可以了解一下2024-01-01
C++作用域與函數(shù)重載的實(shí)現(xiàn)
本文主要介紹了C++作用域與函數(shù)重載的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02

