#C++學生成績管理系統
這個我們程序設計課要求寫的一個項目,埋頭寫了一個星期,最后的結果還是令我滿意的。
- 這個項目總共包含5個頭文件和5個源文件。
- 這個項目參考的是C++程序實際教程第十章——物流貨倉管理系統。
- 這個項目的源文件並未添加太多注釋,主要是因為語言表達能力不行(都是借口,主要是太懶)。
- 程序是在VS2017的環境下編寫。
首先是頭文件
然后是源文件
下面是頭文件
control.h
#pragma once
/*
*這是主控制類,一切控制都是從這里開始,
*/
#include "manager.h"
#include "menu.h"
using namespace std;
class Control{
private:
Manager t_manager; //定義一個管理類對象
int iChoice; //用戶選擇的選項
public:
Control(); //在這個構造函數中實現了對一級菜單的輸出,對文件內容的輸入,
//和主控制函數的調用
~Control();
void MainControl(); //主控制函數
};
manager.h
#pragma once
#include "studentList.h"
#include "menu.h"
using namespace std;
class Manager {
private:
ifstream stuFile;//定義文件輸入流
string strStuFileName; // 學生信息文件名稱
studentList* stuInfoHead; // 定義學生信息鏈表
public:
Manager(string t_strStuFileName, string t_strLogFileName);
~Manager();
void ReadRecord();// 從文件中讀取數據
void UpdateRecord(); // 更新數據到文件中
void InventoryManager(int t_iChoice, int t_attributeChoice, vector<string> attribute);// 選項控制函數
};
menu.h
#pragma once
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
//在指定位置輸出
#define GOTOXY_PUT(out, x, y, val) \
do \
{ \
COORD coord = { x, y };\
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);\
out << val; \
} \
while (0)
//在指定位置輸入
#define GOTOXY_IN(cin, x, y, val)\
do\
{\
COORD coord = { x, y };\
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);\
cin >> val;\
}\
while(0)
/*INPUT_STUINFO在studentList類中AddStudent()函數、
manager類中ReadRecord()函數使用,用於輸入數據 */
#define INPUT_STUINFO(in, stu) \
in >> stu.iNum \
>> stu.sName >> stu.sSex \
>> stu.iAge >> stu.iClass \
>> stu.iCplus >> stu.iEnglish \
>> stu.iMath>> stu.iProgramming
//用於交換學生鏈表數據域
#define CHANGE_STUINFO(before, now) \
do \
{ \
before->iNum = now.iNum; \
before->sName = now.sName; \
before->sSex = now.sSex; \
before->iAge = now.iAge; \
before->iClass = now.iClass; \
before->iCplus = now.iCplus; \
before->iEnglish = now.iEnglish; \
before->iMath = now.iMath; \
before->iProgramming = now.iProgramming; \
}while(0)
//輸出學生信息頭
#define OUTPUT_HEAD(out) \
do \
{ \
out << "學號\t" \
<< "姓名\t" \
<< "性別\t" \
<< "年齡\t" \
<< "班級\t\t" \
<< "Cplusplus\t" << "英語\t" << "高等數學\t" << "程序設計" << endl; \
out << "----------------------------------------------\
--------------------------------------------------" << endl;\
} \
while(0)
// 輸出學生信息
#define OUTPUT_STU(out, p) \
out << p->iNum << '\t' \
<< p->sName << '\t' \
<< p->sSex << '\t' \
<< p->iAge << '\t' \
<< p->iClass << '\t' << '\t' \
<< p->iCplus << '\t' << '\t' \
<< p->iEnglish << '\t' \
<< p->iMath << '\t' << '\t' \
<< p->iProgramming << endl
class Menu {
public:
static bool abnorma;//判斷文件打開是否異常
public:
static void MainMenu();//顯示主菜單
static void SubMenu();//顯示分菜單
};
student.h
#pragma once
/*
* student.h
*
*定義了一個學生信息結構體,用於儲存信息
*其中typedef是定義了一個類型別名
* 類型別名為 stuInfo
*/
#include <string>
typedef struct StuInfo{
int iNum;
std::string sName;
std::string sSex;
int iAge;
int iClass;
float iCplus;
float iEnglish;
float iMath;
float iProgramming;
}stuInfo;
studentList.h
#pragma once
#include "student.h"
#include "menu.h"
using namespace std;
class studentList {
private:
StuInfo* t_stuInfo;//這里是鏈表的創建
studentList* t_stuInfoNext;
public:
string P_Position; //用於記錄鏈表指針位置
private:
static studentList* t_stuInfoHead;//定義一個鏈表頭
static studentList* t_stuInfoEnd;//鏈表尾
public:
studentList();
~studentList();
void AddStudent(const stuInfo* p = nullptr); //添加學生
static studentList* GetListHead(); //獲得鏈表的頭,用於在manager類中使用的接口
void ShowAllStuInfo(studentList* head = t_stuInfoHead)const; //顯示傳進鏈表頭之后的所有學生信息
void ShowStuInfo(studentList* t_p);//顯示當前傳入鏈表指針的學生信息
studentList* IsSameStudent(const stuInfo& stu);//判斷學號是否相同
void EditStuInfo(StuInfo t_stu, int t_position);//編輯學生信息
vector<studentList* > SearchStuInfo(vector<string> t_attribute, int t_choice);//尋找學生信息
vector<studentList* > CompareStuInfo(string t_attribute, int t_choice); // 這個成員函數使用在SearchStuInfo成員函數中,用於匹配數據是否符合條件
studentList* SortStuInfo(int t_choice);//排序
void SwapStuInfo(studentList* ptr1, studentList* ptr2);//這個交換函數屬於排序成員函數中,用於交換數據
float sort_choice(int t_choice, studentList *p);//這個函數屬於交換函數中,用於根據不同選項計較不同值
vector<float> StatisticsStuInfo();//統計函數
void DeleteStuInfo(int t_position);//刪除學生數據
void SaveFile(string file);//保存文件
static float GetStuNumber();//獲得學生數據個數
};
接下來的就是源文件
control.cpp
#include "control.h"
Control::Control() : t_manager("student.txt", "log.txt") {
Menu::MainMenu();
t_manager.ReadRecord();
MainControl();
}
Control::~Control() {}
void Control::MainControl() {
while (true) {
int attributeChoice = 0;
vector<string> attribute;
string temp;
Menu::SubMenu();
GOTOXY_IN(cin, 71, 17, iChoice);
if (studentList::GetStuNumber() == 0) {}
else if (iChoice == 3) {
GOTOXY_PUT(cout, 60, 17,
"請輸入查詢條件:");
GOTOXY_PUT(cout, 60, 18,"(1. 學號, 2.姓名, 3.班級, 4.性別, 5.有一門掛科)");
GOTOXY_IN(cin, 60, 19, attributeChoice);
GOTOXY_PUT(cout, 60, 18,"請輸入屬性:(如選擇“有一門掛科”請任意輸入) ");
GOTOXY_PUT(cout, 60, 19, " ");
cin >> temp;
attribute.push_back(temp);
}
else if (iChoice == 4) {
GOTOXY_PUT(cout, 60, 17,
"請輸入需要修改學生學號:");
attributeChoice = 1;
cin >> temp;
attribute.push_back(temp);
}
else if (iChoice == 5) {
GOTOXY_PUT(cout, 60, 17,
"請輸入排序條件:");
GOTOXY_PUT(cout, 60, 18, "(1.Cplusplus,2. 英語,3.高等數學,4.程序設計,5.總分):");
GOTOXY_IN(cin, 60, 19, attributeChoice);
}
else if (iChoice == 7) {
GOTOXY_PUT(cout, 60, 17,
"請輸入需要刪除學生的學號:");
GOTOXY_IN(cin, 60, 18, temp);
attributeChoice = 1;
attribute.push_back(temp);
}
t_manager.InventoryManager(iChoice, attributeChoice, attribute);
}
}
manager.cpp
#include "manager.h"
Manager:: Manager(string t_strStuFileName, string t_strLogFileName) :
strStuFileName(t_strStuFileName),
stuInfoHead(new studentList()) {
stuFile.open(t_strStuFileName, ios::_Nocreate);
if (!stuFile)
Menu::abnorma = true;
stuFile.open(t_strStuFileName, ios_base::out | ios_base::app);
}
Manager::~Manager() {}
void Manager::ReadRecord() {
stuFile.open(strStuFileName, ios::in);
stuFile.clear();
stuFile.seekg(0, ios::beg);
StuInfo stu;
while (INPUT_STUINFO(stuFile, stu))
stuInfoHead->AddStudent(&stu);
stuFile.close();
}
void Manager::UpdateRecord() {
auto str = strStuFileName + ".bak";
stuInfoHead->SaveFile(str);
remove(strStuFileName.c_str());
rename(str.c_str(), strStuFileName.c_str());
}
void Manager::InventoryManager(int t_iChoice, int t_attributeChoice, vector<string> attribute) {
stuInfoHead = studentList::GetListHead();
if (studentList::GetStuNumber() == 0 &&
(t_iChoice == 1 || t_iChoice == 3 ||
t_iChoice == 4 || t_iChoice == 5 ||
t_iChoice == 6 || t_iChoice == 7 ||
t_iChoice == 8)) {
system("cls");
cout << "當先系統中沒有數據,請輸入!";
system("pause");
}
else if (t_iChoice == 1) {
system("cls");
stuInfoHead->ShowAllStuInfo(stuInfoHead);
cout << "\n學生信息顯示完成,";
system("pause");
}
else if (t_iChoice == 2) {
system("cls");
cout << "請按照以下格式輸入數據:\n\n";
OUTPUT_HEAD(cout);
stuInfoHead->AddStudent();
cout << "\n學生信息輸入完成,";
system("pause");
}
else if (t_iChoice == 3) {//剩選擇5的一個輸入問題
system("cls");
auto p = stuInfoHead->SearchStuInfo(attribute, t_attributeChoice);
if (p.size() == 1) {
cout << "未找到符合條件數據,";
system("pause");
}
else {
OUTPUT_HEAD(cout);
for (int i = 0; i < p.size() - 1; i++)
stuInfoHead->ShowStuInfo(p[i]);
cout << "\n顯示完成,";
system("pause");
}
}
else if (t_iChoice == 4) {//完成
system("cls");
auto p = stuInfoHead->SearchStuInfo(attribute, t_attributeChoice);
if (p.size() == 1) {
cout << "沒有找到" << endl;
system("pause");
return;
}
else {
cout << "顯示學生原信息:\n" << endl;
OUTPUT_HEAD(cout);
stuInfoHead->ShowStuInfo(p[0]);
cout << "\n請按以下格式修改數據" << endl;
OUTPUT_HEAD(cout);
stuInfo stu;
INPUT_STUINFO(cin, stu);
stuInfoHead->EditStuInfo(stu, stoi(p[1]->P_Position));
cout << "修改完成,";
system("pause");
}
}
else if (t_iChoice == 5) {
system("cls");
auto p = stuInfoHead->SortStuInfo(t_attributeChoice);
stuInfoHead->ShowAllStuInfo(p);
cout << "\n排序完成,";
system("pause");
}
else if (t_iChoice == 6) {
system("cls");
vector<float> statistics;
statistics = stuInfoHead->StatisticsStuInfo();
cout << "當前學生總人數為:" << statistics[4] << endl;
cout << "c++平均分:" << statistics[0] << endl;
cout << "數學平均分:" << statistics[1] << endl;
cout << "英語平均分:" << statistics[2] << endl;
cout << "程序設計平均分:" << statistics[3] << endl;
system("pause");
}
else if (t_iChoice == 7) {
system("cls");
auto p = stuInfoHead->SearchStuInfo(attribute, t_attributeChoice);
if (p.size() == 1) {
cout << "沒有找到" << endl;
system("pause");
return;
}
else {
cout << "顯示學生原信息:\n" << endl;
OUTPUT_HEAD(cout);
stuInfoHead->ShowStuInfo(p[0]);
stuInfoHead->DeleteStuInfo(stoi(p[1]->P_Position));
stuInfoHead = studentList::GetListHead();
cout << "\n數據已刪除,";
system("pause");
}
}
else if (t_iChoice == 8) {
system("cls");
UpdateRecord();
cout << "\n文件已存儲,";
system("pause");
}
else if (t_iChoice == 0) {
system("cls");
GOTOXY_PUT(cout, 71, 22, "歡迎下次使用!");
system("pause");
exit(0);
}
else {
system("cls");
GOTOXY_PUT(cout, 71, 17, "請選擇對應的選項!");
system("pause");
}
}
menu.cpp
#include "menu.h"
bool Menu::abnorma = false;
void Menu::MainMenu() {
system("color 2F");
system("title Student achievement management");
system("cls");
cout << "\n\t\t|--------學生信息管理系統---------|\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| 歡 |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| 迎 |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| 使 |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| 用 |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t| |\n";
cout << "\t\t|---------------------------------|\t";
if (abnorma == true)
GOTOXY_PUT(cout, 60, 15, "文件不存在,已重新創建!");
GOTOXY_PUT(cout, 60, 17, "系統運行正常!");
system("pause");
}
void Menu::SubMenu() {
system("cls");
cout << "\n\t\t|--------學生信息管理系統---------|\n";
cout << "\t\t| |\n";
cout << "\t\t| 1. 輸出所有信息 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2. 添加學生信息 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3. 學生信息查詢 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 4. 修改學生信息 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 5. 學生信息排序 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 6. 學生信息統計 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 7. 刪除學生信息 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 8. 保存變更 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0. 退出 |\n";
cout << "\t\t|---------------------------------|\t";
GOTOXY_PUT(cout, 60, 17, "請選擇功能:");
}
main.cpp
#include "control.h"
int main( ) {
Control a;
system("pause");
}
studentList.cpp
#include "studentList.h"
studentList* studentList::t_stuInfoHead = nullptr;
studentList* studentList::t_stuInfoEnd = nullptr;
studentList::studentList() :t_stuInfo(nullptr), t_stuInfoNext(nullptr) {
//鏈表剛創建時,只存在一個節點,內容無效,頭尾指針均指向該節點
if (!(t_stuInfoHead || t_stuInfoEnd)) {
t_stuInfoHead = this;
t_stuInfoEnd = this;
}
P_Position = "";
}
studentList::~studentList() {}
void studentList::AddStudent(const stuInfo* p) {
stuInfo stu;
int choice = 0;
if (!p)
INPUT_STUINFO(cin, stu);
else
stu = *p;
auto p1 = IsSameStudent(stu);
if (p1) {
cout << "您輸入的學生信息在系統中已經存在,是否覆蓋(1.覆蓋, 2.取消)\n";
cin >> choice;
if (choice == 1) {
cout << "您輸入的產品名稱在系統中已存在,現將信息進行合並!" << endl;
cout << "\n原有信息如下:" << endl;
OUTPUT_HEAD(cout);
ShowStuInfo(p1);
EditStuInfo(stu, stoi(p1->P_Position));
}
}
if (t_stuInfoEnd && choice != 2 && choice != 1) {
t_stuInfoEnd->t_stuInfo = new stuInfo(stu);
t_stuInfoEnd->t_stuInfoNext = new studentList();
t_stuInfoEnd = t_stuInfoEnd->t_stuInfoNext;
}
}
studentList* studentList::GetListHead() {
return t_stuInfoHead;
}
void studentList::ShowAllStuInfo(studentList* head)const {
if (head == nullptr)
return;
auto p = head;
OUTPUT_HEAD(cout);
while (p->t_stuInfo) {
OUTPUT_STU(cout, p->t_stuInfo);
p = p->t_stuInfoNext;
}
}
void studentList::ShowStuInfo(studentList* t_p) {
auto p = t_p;
OUTPUT_STU(cout, p->t_stuInfo);
}
studentList* studentList::IsSameStudent(const stuInfo& stu) {
auto p = t_stuInfoHead;
int i = 0;
while (p->t_stuInfo) {
if (p->t_stuInfo->iNum == stu.iNum) {
p->P_Position = to_string(i);
return p;
}
i++;
p = p->t_stuInfoNext;
}
return nullptr;
}
void studentList::EditStuInfo(StuInfo t_stu, int t_position) {
studentList *p = t_stuInfoHead; //注意這是指針,p記錄了t_stuInfoHead的地址,只是地址
for (int i = 0; i < t_position; i++)
t_stuInfoHead = t_stuInfoHead->t_stuInfoNext;
CHANGE_STUINFO(t_stuInfoHead->t_stuInfo, t_stu);
cout << "修改完成!修改后結果如下\n";
ShowStuInfo(t_stuInfoHead);
t_stuInfoHead = p;
}
vector<studentList* > studentList::SearchStuInfo(vector<string> t_attribute, int t_choice) {//返回多個鏈表指針
vector<studentList*> p;
p = CompareStuInfo(t_attribute[0], t_choice);
return p;
}
vector<studentList* > studentList::CompareStuInfo(string t_attribute, int t_choice) {
vector<studentList*> p_out;
auto p = t_stuInfoHead;
int i = 0;
while (p->t_stuInfo) {
if (t_choice == 1) {
if (t_attribute == to_string(p->t_stuInfo->iNum)) {
p_out.push_back(p);
break;
}
i++;
}
else if (t_choice == 2) {
if (t_attribute == p->t_stuInfo->sName)
p_out.push_back(p);
}
else if (t_choice == 3) {
if (t_attribute == to_string(p->t_stuInfo->iClass))
p_out.push_back(p);
}
else if (t_choice == 4) {
if (t_attribute == p->t_stuInfo->sSex)
p_out.push_back(p);
}
else if (t_choice == 5) {
if (p->t_stuInfo->iCplus < 60 ||
p->t_stuInfo->iEnglish < 60 ||
p->t_stuInfo->iMath < 60 ||
p->t_stuInfo->iProgramming < 60)
p_out.push_back(p);
}
p = p->t_stuInfoNext;
}
studentList* temp = new studentList;
temp->P_Position = to_string(i);
p_out.push_back(temp);
return p_out;
}
studentList* studentList::SortStuInfo(int t_choice) {
auto p = t_stuInfoHead;
auto p1 = p;
for (; p != t_stuInfoEnd; p = p->t_stuInfoNext)
for (p1 = p->t_stuInfoNext; p1 != t_stuInfoEnd; p1 = p1->t_stuInfoNext)
if (sort_choice(t_choice, p) < sort_choice(t_choice, p1))
SwapStuInfo(p, p1);
return t_stuInfoHead;
}
void studentList::SwapStuInfo(studentList* ptr1, studentList* ptr2) {
stuInfo *temp;
temp = ptr1->t_stuInfo;
ptr1->t_stuInfo = ptr2->t_stuInfo;
ptr2->t_stuInfo = temp;
}
float studentList::sort_choice(int t_choice, studentList *p) {
return (t_choice == 1 ? p->t_stuInfo->iCplus :
(t_choice == 2 ? p->t_stuInfo->iEnglish :
(t_choice == 3 ? p->t_stuInfo->iMath :
(t_choice == 4 ? p->t_stuInfo->iProgramming :
(t_choice == 5 ? (p->t_stuInfo->iCplus +
p->t_stuInfo->iEnglish +
p->t_stuInfo->iMath +
p->t_stuInfo->iProgramming) : -1)))));
}
vector<float> studentList::StatisticsStuInfo() {
auto p = t_stuInfoHead;
vector<float> out;
float C = 0, math = 0, eng = 0, programming = 0;
while (p->t_stuInfo) {
C += p->t_stuInfo->iCplus;
math += p->t_stuInfo->iMath;
eng += p->t_stuInfo->iEnglish;
programming += p->t_stuInfo->iProgramming;
p = p->t_stuInfoNext;
}
out.push_back(C / GetStuNumber());
out.push_back(math / GetStuNumber());
out.push_back(eng / GetStuNumber());
out.push_back(programming / GetStuNumber());
out.push_back(GetStuNumber());
return out;
}
void studentList::DeleteStuInfo(int t_position) {
studentList *p = t_stuInfoHead;
if (t_position == 0)
t_stuInfoHead = t_stuInfoHead->t_stuInfoNext;
else {
for (int i = 0; i < t_position - 1; i++)
t_stuInfoHead = t_stuInfoHead->t_stuInfoNext;
t_stuInfoHead->t_stuInfoNext = t_stuInfoHead->t_stuInfoNext->t_stuInfoNext;
t_stuInfoHead = p;
}
}
void studentList::SaveFile(string file) {
ofstream os(file, ios::out);
auto p = t_stuInfoHead;
while (p->t_stuInfo) {
OUTPUT_STU(os, p->t_stuInfo);
p = p->t_stuInfoNext;
}
os.close();
}
float studentList::GetStuNumber() {
float i = 0;
for (auto p = t_stuInfoHead; p != t_stuInfoEnd; p = p->t_stuInfoNext)
i++;
return i;
}
下面是運行出來的效果

