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)操作沒有問題,仔細判斷邏輯關(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ù)進行文件尾判斷時,當(dāng)文件已經(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判斷文件是否為結(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語言
下一篇:C++線程安全的單例模式講解
本文標(biāo)題:C語言實現(xiàn)學(xué)生成績管理系統(tǒng)實戰(zhàn)教學(xué)
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/513.html
您可能感興趣的文章
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用函數(shù)刪除字符
- 04-02c語言的正則匹配函數(shù) c語言正則表達式函數(shù)庫
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對數(shù)怎么表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02C語言中怎么打出三角函數(shù) c語言中怎么打出三角函數(shù)的值
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求階乘


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機閱讀
- 01-10delphi制作wav文件的方法
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11ajax實現(xiàn)頁面的局部加載
- 04-02jquery與jsp,用jquery
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結(jié)


