学生信息管理系统C++

可以增删查改,使用链表存储,支持排序以及文件存储及数据读取,基本可以应付期末大作业(狗头)
界面为

《学生信息管理系统C++》
源代码为一个main.cpp和三个头文件,具体为
main.cpp


#include <iostream>
#include <fstream>//文件操作
#include <sstream>//int转string
#include <iomanip>//cout格式化输出 setw()
#include <stdlib.h>
#include "student.h"
#include "node.h"
#include "list.h"
using namespace std;



int main()//入口函数
{ 
	//test();

	CList list1;//创建链表对象
	Read4File(list1);//将文件数据读取到链表中
    
	int choice = -1;//接收用户选择
	while(true)
	{ 
		system("cls");//清屏
		MainMenu();
		cin>>choice;
		switch(choice)
		{ 
		case 1:
			system("cls");//清屏
			cout<<"********【所有数据】********"<<endl;
			cout<<"序号\t学号 姓名 班级 分数"<<endl;
			cout<<"*******【共 "<<list1.DisplayListData()<<" 人】******\n"<<endl;
			list1.Compute(); 
			system("pause");//暂停一下
			break;
		case 2:
			Add(list1);//添加操作
			break;
		case 3:
			Find(list1);//查找操作
			break;
		case 4:
			Update(list1);//更新操作(修改)
			break;
		case 5:
			Sort(list1);//排序操作
			break;
		case 6:
			Del(list1);//删除操作
			break;
		case 7:
			ClearFileData();//清空文件数据
			list1.Clear();//清空链表数据
			break;
		case 0://退出程序
			return 0;
		default:
			cout<<"请输入0~7"<<endl;
			system("pause");
			break;
		}
	}

	return 0;
}

\list.h

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <stdlib.h>
#define FILE_PATH "student.txt" //数据文件的路径
using namespace std;
//声明
class CList;
void Save2File(CList& list);//将数据保存到文件
void Read4File(CList& list);//读取文件数据到链表

bool CmpStr(string str1, string str2)//字符串比较函数
{ 
	int len1 = str1.size();//字符串1的长度
	int len2 = str2.size();//字符串2的长度

	//将两个字符串的长度 添加为一样长(达到右对齐的效果)
	for(int i=0; i<len1-len2; i++)//如果字符串str1比str2长,在str2的前面补0
	{ 
		str2.insert(0, "0");//在最前面补0
	}

	for(int i=0; i<len2-len1; i++)//如果字符串str2比str1长,在str1的前面补0
	{ 
		str1.insert(0, "0");//在最前面补0
	}
	
	return str1>str2;
}

bool SortById(SNode* &p, SNode* &q)//按学号升序排序
{ 
	return ( p->stu.GetId()>q->stu.GetId() );
}

bool SortByName(SNode* &p, SNode* &q)//按姓名升序排序
{ 
	return CmpStr(p->stu.GetName(), q->stu.GetName());	
}

bool SortByClass(SNode* &p, SNode* &q)//按班级升序排序
{ 
	return CmpStr(p->stu.GetClass(), q->stu.GetClass());	
}
bool SortByScore(SNode* &p, SNode* &q)//按Score升序排序
{ 
	return ( p->stu.GetScore()>q->stu.GetScore() );
}

typedef bool (*FUNCP)(SNode* &p, SNode* &q);//函数指针
FUNCP pFunArr[] = { SortById, SortByName, SortByClass,SortByScore};//排序函数的指针数组

//链表操作类
class CList
{ 
	SNode* m_pListHead;//链表头结点指针
	void Init_ListHead();//初始化头结点
public:
	CList();//无参构造函数,用来初始化成员,创建对象的时候自动调用
	~CList();//析构函数,用来释放格外申请的堆空间,(对象被销毁的时候自动调用)
	void AddHead(SNode& node);//头插法 添加数据
	void AddTail(SNode& node);//尾插法 添加数据
	bool DelData(int id);//根据id删除数据
	SNode* FindData(int id);//根据id查找指定数据
	bool UpdateData(int id, SNode& update);//根据id修改数据(更新)
	int DisplayListData();//显示链表所有数据,返回数据条数
	SNode* GetListHead();//外界获取头结点指针的接口(头指针是private权限)
	void Clear();//清空链表。释放链表空间
	void Sort(int type = 0);//默认按id升序排序
	int Size();
	void Compute();//获取链表数据的个数
};

//类成员函数的类外实现
CList::CList()//无参构造函数,用来初始化成员
{ 
	Init_ListHead();//初始化链表头结点
}

CList::~CList()//析构函数,用来释放格外申请的堆空间,(对象被销毁的时候自动调用)
{ 
	Clear();//释放链表空间
	delete m_pListHead;//释放头结点,
	m_pListHead = NULL;//置空,防止重复操作
}
void CList::Compute()//根据id升序排序
{  int a=0,b=0,c=0;
	if(m_pListHead == NULL)//空链表直接返回
	{ 
		return;
	}

	SNode* p; //排序辅助指针(以p为基准,q遍历连链表数据,temp在交换的数据时使用,指向需要交换时的较大者)
	
	for(p = m_pListHead->next;p != NULL;p = p->next)
	{ 
		if(p->stu.GetScore()<60)a++;
		else if(p->stu.GetScore()>=60&&p->stu.GetScore()<=80)b++;
		else if(p->stu.GetScore()>80)c++;
	}
	cout<<"60分以下(不含60分)的人数有:"<<a<<"人"<<endl;
			cout<<"60分以上80分以下(含80分)的人数有:"<<b<<"人"<<endl;
					cout<<"80分以上的人数有:"<<c<<"人"<<endl;
						if((a+b+c)!=0)cout<<"及格率为:"<<(float)(b+c)/(a+b+c)*100<<"%"<<endl;
						
}

void CList::Init_ListHead()//初始化头结点
{ 
	m_pListHead = new SNode;//初始化头结点
	m_pListHead->stu.SetId(0);
	m_pListHead->stu.SetName("头结点");
	m_pListHead->stu.SetClass("A班");
	m_pListHead->stu.SetScore(0);
	m_pListHead->next = NULL;
}

void CList::AddHead(SNode& node)//头插法 添加数据
{ 
	SNode* new_node = new SNode(node);
	new_node->next = NULL;
	if(m_pListHead == NULL)//头结点为空,就初始化头结点
	{ 
		Init_ListHead();
	}

	if(m_pListHead->next == NULL)//如果除头结点外还没有数据节点,直接让头结点指向新的节点,新的节点作为第一个数据节点
	{ 
		m_pListHead->next = new_node;
	}
	else //将新的节点作为第一个数据节点(头结点后面的一个)
	{ 
		new_node->next = m_pListHead->next;
		m_pListHead->next = new_node;
	}
}

void CList::AddTail(SNode& node)//尾插法 添加数据
{ 
	SNode* new_node = new SNode(node);
	new_node->next = NULL;
	if(m_pListHead == NULL)//头结点为空,就初始化头结点
	{ 
		Init_ListHead();
	}

	SNode* p = m_pListHead;
	while(p->next)//遍历到链表最后一个节点,直到p->next为NULL
	{ 
		p = p->next;
	}

	p->next = new_node;//链表最后的节点指向新的节点,新的节点成为尾节点

}

bool CList::DelData(int id)//根据id删除数据
{ 
	if(m_pListHead == NULL)
	{ 
		return false;
	}
	SNode* p = m_pListHead->next;//p遍历节点
	SNode* q = m_pListHead;//q为p的前一个节点
	while(p != NULL)//遍历链表
	{ 
			
		if(id == p->stu.GetId())//找到要删除的数据节点p
		{ 
			q->next = p->next;
			delete p;
			p = NULL;//置空,防止再次操作造成隐蔽错误
			return true;
		}
		q = p;
		p = p->next;
	}

	return false;
}

SNode* CList::FindData(int id)//根据id查找指定数据
{ 
	if(m_pListHead == NULL)
	{ 
		return NULL;
	}
	SNode* p = m_pListHead->next;//p遍历节点
	while(p != NULL)//遍历链表
	{ 
			
		if(id == p->stu.GetId())//找到要删除的数据节点p
		{ 
			return p;
		}
		p = p->next;
	}

	return NULL;
}

bool CList::UpdateData(int id, SNode& update)//根据id修改数据(更新)
{ 
	if(m_pListHead == NULL)
	{ 
		return false;
	}
	
	SNode* findNode = NULL;
	findNode = FindData(id);
	if(findNode != NULL)
	{ 
		//memcpy(findNode, &update, sizeof(SNode)-sizeof(SNode*));//更新数据,不更新指针域
		findNode->stu.SetId(update.stu.GetId());
		findNode->stu.SetName(update.stu.GetName());
		findNode->stu.SetClass(update.stu.GetClass());
		findNode->stu.SetScore(update.stu.GetScore());
		return true;
	}
	return false;
}

int CList::DisplayListData()//显示链表所有数据
{ 
	if(m_pListHead == NULL)
	{ 
		return 0;
	}
	int count = 0;//记录数据的总条数
	SNode* p = m_pListHead->next;
	while(p != NULL)//遍历链表
	{ 
		count++;
		cout<<"["<<count<<"]\t"<<setw(4)<<p->stu.GetId()<<" "<<setw(8)<<p->stu.GetName()<<" "<<setw(8)<<p->stu.GetClass()<<setw(8)<<p->stu.GetScore()<<endl;//(setw(8)输出宽度,默认右对齐)
		p = p->next;
	}
	return count;
}

void CList::Clear()//清空链表。释放链表空间
{ 
	if(m_pListHead == NULL)
	{ 
		return;
	}
	SNode* p = m_pListHead->next;
	while(p != NULL)//遍历链表
	{ 
		m_pListHead->next = p->next;
		delete p;
		p = m_pListHead->next;
	}
}

void CList::Sort(int type)//排序
{ 
	if(m_pListHead == NULL)//空链表直接返回
	{ 
		return;
	}

	SNode* p, *q, *bigger;//排序辅助指针(以p为基准,q遍历连链表数据,temp在交换的数据时使用,指向需要交换时的较大者)
	
	for(p = m_pListHead->next;p != NULL;p = p->next)
	{ 
		bigger = p;
		for(q = p->next;q != NULL;q = q->next)
		{ 
			
			if( pFunArr[type](bigger, q) )//前面的比后面的大,就交换
			{ 
				bigger = q;//指向需要交换时的较大者
			}
		}
		if(bigger != p)//需要交换
		{ 
			SNode temp = *bigger;//指针域不用交换
			bigger->stu.SetId(p->stu.GetId());
			bigger->stu.SetName(p->stu.GetName());
			bigger->stu.SetClass(p->stu.GetClass());
			bigger->stu.SetScore(p->stu.GetScore());
			p->stu.SetId(temp.stu.GetId());
			p->stu.SetName(temp.stu.GetName());
			p->stu.SetClass(temp.stu.GetClass());
			p->stu.SetScore(temp.stu.GetScore());
		}
	}
}

SNode* CList::GetListHead()//外界获取头结点指针的接口(头指针是private权限)
{ 
	return  this->m_pListHead;
}

int CList::Size()
{ 
	if(m_pListHead == NULL)
	{ 
		return 0;
	}

	int count = 0;//数据的个数
	SNode* p = m_pListHead;
	while( (p=p->next) != NULL)
	{ 
		count++;
	}

	return count;
}

void AddMenu()//添加 菜单
{ 
	cout<<"┏━━━━━━━━━━┓"<<endl;
	cout<<"┃ 添加菜单 ┃"<<endl;
	cout<<"┃ 【1】 添加到头部 ┃"<<endl;
	cout<<"┃ 【2】 添加到尾部 ┃"<<endl;
	cout<<"┃ 【0】 返回 ┃"<<endl;
	cout<<"┗━━━━━━━━━━┛"<<endl;
	cout<<" ******请输入0~2:";
}

void Add(CList& list)//添加处理
{ 
	int id = -1;//接收用户输入的id
	string name = "";//接收用户输入的姓名
	string _class = "";//接收用户输入的班级
	float score =0;
	SNode new_node;//存储输入的合法数据
	int choice = -1;//接收用户选择
	char save = 'Y';//是否将数据保存到文件
	char isAdd = 'N';//用来表识 用户是否有添加过数据,如果有会在返回上级菜单的时候提示用户保存到文件
	char isContinue = 'Y';//表识是否继续添加
	while(true)
	{ 
		system("cls");//清屏
		AddMenu();//添加菜单
		cin>>choice;//接收用户选择
		switch(choice)
		{ 
		case 1://头插法
		case 2://尾部添加
			isContinue = 'Y';
			while(isContinue == 'Y' || isContinue == 'y')//循环添加
			{ 
				cout<<"请输入学号:";
				cin>>id;
				if(id<=0)//检查用户输入的id是否合法
				{ 
					cout<<"序号应大于0!请重新输入!"<<endl;
				}
				else if(list.FindData(id) != NULL)//学号大于0但是已经存在
				{ 
					cout<<"学号 "<<id<<" 已经存在!请重新输入!"<<endl;
				}
				else//学号大于0且不存在
				{ 
					new_node.stu.SetId(id);//设置新的学号

					for(;;)//循环接收用户输入的姓名,直到姓名不为空
					{ 
						cout<<"请输入姓名:";
						cin>>name;
						if(name.empty())//如果姓名为空
						{ 
							cout<<"姓名 不能为空!请重新输入!(按0结束输入)"<<endl;
							continue;
						}
						break;
					}

					if(name == "0")//如果姓名为0,结束添加
					{ 
						break;//跳出循环
					}

					new_node.stu.SetName(name);//设新节点的姓名

					for(;;)//循环接收用户输入的班级,直到班级不为空
					{ 
						cout<<"请输入班级:";
						cin>>_class;
						if(_class.empty())//如果班级为空
						{ 
							cout<<"班级 不能为空!请重新输入!(按0结束输入)"<<endl;
							continue;
						}
						break;
					}

					if(_class == "0")//如果班级为0,结束添加
					{ 
						break;//跳出循环
					}
					new_node.stu.SetClass(_class);//设置新节点的班级
					for(;;)//循环接收用户输入的score,直到score不为空
					{ 
						cout<<"请输入分数:";
						cin>>score;
						if(score<0)
						{ 
							cout<<"分数不能为负!请重新输入!(按0结束输入)"<<endl;
							continue;
						}
						break;
					}

					if(score==0)//如果分数为0,结束添加
					{ 
						break;//跳出循环
					}
					new_node.stu.SetScore(score);

					
					if(choice == 1)
					{ 
						list.AddHead(new_node);//头插法添加到链表
					}
					else
					{ 
						list.AddTail(new_node);//尾插法添加到链表
					}
					isAdd = 'Y';//表识用户添加了数据
					
				}
				cout<<"是否继续添加?(y/n):";
				cin>>isContinue;
			}
			break;
		case 0:
			if(isAdd == 'Y')//用户添加过数据才提示保存
			{ 
				cout<<"是否保存到文件?(y/n)"<<endl;
				cin>>save;
				if(save == 'Y'|| save == 'y')
				{ 
					Save2File(list);//将数据保存到文件
					cout<<"保存成功!"<<endl;
					system("pause");
				}
				else//不保存
				{ 
					list.Clear();//清除数据
					Read4File(list);//重新读取数据
				}
			}
			return;
		default:
			cout<<"请输入0~2"<<endl;
			system("pause");
			break;
		}
		
	}
}

void DelMenu()//删除菜单
{ 
	cout<<"┏━━━━━━━━━━┓"<<endl;
	cout<<"┃ 删除菜单 ┃"<<endl;
	cout<<"┃ 【1】 按学号删除 ┃"<<endl;
	cout<<"┃ 【0】 返回 ┃"<<endl;
	cout<<"┗━━━━━━━━━━┛"<<endl;
	cout<<" ******请输入0~1:";
}

void Del(CList& list)//删除操作
{ 
	int id  = -1;
	char choice = '0';//用户选择
	bool isDel = false;//接收删除结果
	char isSure = 'N';//提示用户 确认删除
	SNode* findNode = NULL;//指向匹配的数据节点
	while(true)
	{ 
		system("cls");//清屏
		DelMenu();
		cin>>choice;
		if(choice == '1')
		{ 
			cout<<"请输入要删除的学号:";
		}
		else
		{ 
			break;
		}
		cin>>id;
		if(id == 0)
		{ 
			break;
		}
		findNode = list.FindData(id);
		if(findNode != NULL)//存在目标数据
		{ 
			cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"班级"<<"\t"<<"分数"<<endl;
			cout<<findNode->stu.GetId()<<"\t"<<findNode->stu.GetName()<<"\t"<<findNode->stu.GetClass()<<endl;
			cout<<"已经找到学号为 "<<id<<"的数据,是否删除?(y/n):";
			cin>>isSure;
			if(isSure == 'Y' || isSure == 'y')//用户确认删除
			{ 
				isDel = list.DelData(id);
				Save2File(list);//保存到文件
				if(isDel)//删除成功
				{ 
					cout<<"已成功删除id为"<<id<<"的数据"<<endl;
				}
				else
				{ 
					cout<<"删除id为"<<id<<"的数据 失败!"<<endl;
				}
			}
		}
		else
		{ 
			cout<<"请检查"<<id<<"是否存在!"<<endl;
		}
		system("pause");
	}
}

void FindMenu()//查找的菜单
{ 
	cout<<"┏━━━━━━━━━━┓"<<endl;
	cout<<"┃ 查找菜单 ┃"<<endl;
	cout<<"┃ 【1】 按学号查找 ┃"<<endl;
	cout<<"┃ 【2】 按姓名查找 ┃"<<endl;
	cout<<"┃ 【3】 按班级查找 ┃"<<endl;
	cout<<"┃ 【0】 返回 ┃"<<endl;
	cout<<"┗━━━━━━━━━━┛"<<endl;
	cout<<" ******请输入0~3:";
}

void Find(CList& list)//查找操作
{ 
	int id  = -1;//存放要查找的学号
	string name_class = "";//存放要查找的姓名(或班级)
	int choice = -1;//接收用户的选择
	SNode* findNode = NULL;//接收查找结果
	while(true)
	{ 
		system("cls");//清屏
		FindMenu();//查找菜单
		cin>>choice;//接收用户选择
		switch(choice)
		{ 
		case 1://按学号查找,因为学号是唯一的,所以最多只有一个匹配的数据
			cout<<"请输入要查找的学号:";
			cin>>id;
			findNode = list.FindData(id);
			if(findNode != NULL)//找到数据
			{ 
				cout<<"\n已经找到id为"<<id<<"的数据"<<endl;
				cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"班级"<<endl;
				cout<<findNode->stu.GetId()<<"\t"<<findNode->stu.GetName()<<"\t"<<findNode->stu.GetClass()<<"\t"<<findNode->stu.GetScore()<<endl;
			}
			else
			{ 
				cout<<"未找到,请检查学号 "<<id<<" 是否存在!"<<endl;
			}
			break;
		case 2://按姓名查找,可能有重名的,所以结果可能包含多个数据
		case 3:
			{ 
				if(choice == 2)
				{ 
					cout<<"请输入要查找的姓名:";
				}
				else
				{ 
					cout<<"请输入要查找的班级:";
				}
				cin>>name_class;
				CList findList;//存放查询的结果
				findNode = list.GetListHead();//获取链表头结点
				if(findNode != NULL)
				{ 
					findNode = findNode->next;
					while(findNode != NULL)//遍历数据链表,匹配就添加到结果链表
					{ 
						if( ((choice == 2) && name_class == findNode->stu.GetName()) ||
							((choice == 3) && name_class == findNode->stu.GetClass()))//姓名(或班级)匹配
						{ 
							findList.AddTail(*findNode);//添加到结果链表中
						}
						findNode = findNode->next;
					}
				}
				int count = findList.Size();//匹配到的数据数目
				if( count>0 )//如果结果链表中匹配到有数据
				{ 
					if(choice == 2)
					{ 
						cout<<"\n已经找到姓名为 "<<name_class<<" 的数据"<<endl;
					}
					else
					{ 
						cout<<"\n已经找到班级为 "<<name_class<<" 的数据"<<endl;
					}
					cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"班级"<<endl;
					
					findNode = findList.GetListHead()->next;
					while(findNode != NULL)
					{ 
						cout<<findNode->stu.GetId()<<"\t"<<findNode->stu.GetName()<<"\t"<<findNode->stu.GetClass()<<endl;
						findNode = findNode->next;
					}
					cout<<"*****【共 "<<count<<" 名学生】*****\n"<<endl;
				}
				else
				{ 
					if(choice == 2)
					{ 
						cout<<"未找到,请检查姓名 "<<name_class<<" 是否存在!"<<endl;
					}
					else
					{ 
						cout<<"未找到,请检查班级 "<<name_class<<" 是否存在!"<<endl;
					}
					
				}
				break;
			}
		case 0://返回
			return;
		default:
			cout<<"请输入0~3"<<endl;
			break;
		}
		system("pause");
		
	}
}

void UpdateMenu()//更新菜单
{ 
	cout<<"┏━━━━━━━━━━┓"<<endl;
	cout<<"┃ 更新菜单 ┃"<<endl;
	cout<<"┃ 【1】 按学号更新 ┃"<<endl;
	cout<<"┃ 【0】 返回 ┃"<<endl;
	cout<<"┗━━━━━━━━━━┛"<<endl;
	cout<<" ******请输入0~1:";
}

void Update(CList& list)//更新操作
{ 
	int id = -1;
	int choice = -1;//用户的选择
	bool isUpdate = NULL;//接收修改结果
    string name = "";//新的姓名
	string _class = "";//新的班级
	float score=0;
	SNode* findNode = NULL;//指向要更新的节点
	SNode update;//新的数据
	while(true)
	{ 
		system("cls");//清屏
		UpdateMenu();//更新菜单
		cin>>choice;//接收用户选择
		switch(choice)
		{ 
		case 1:
			cout<<"请输入要更新的学号:";
			cin>>id;
			findNode = list.FindData(id);
			if(findNode == NULL)//不存在目标数据,则重新输入
			{ 
				cout<<"不存在此学号!"<<endl;
				system("pause");
				continue;
			}

			cout<<"\n已经找到id为"<<id<<"的数据"<<endl;
			cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"班级"<<"\t"<<"分数"<<endl;
			cout<<findNode->stu.GetId()<<"\t"<<findNode->stu.GetName()<<"\t"<<findNode->stu.GetClass()<<"\t"<<findNode->stu.GetScore()<<endl;
			update = *findNode;

			cout<<"【输入0,表示不更改】"<<endl;
			cout<<"将姓名:"<<findNode->stu.GetName()<<" 改为:";
			cin>>name;
			if(name != "0")
			{ 
				update.stu.SetName(name);
			}
			cout<<"将分数:"<<findNode->stu.GetScore()<<" 改为:";
			cin>>score;
			if(score != 0)
			{ 
				update.stu.SetScore(score);
			}

			cout<<"将班级:"<<findNode->stu.GetClass()<<" 改为:";
			cin>>_class;
			if(_class != "0")
			{ 
				update.stu.SetClass(_class);
			}
			
			if(name != "0" || _class != "0")//用户有更改
			{ 
				isUpdate = list.UpdateData(id, update);
				if(isUpdate == true)
				{ 
					Save2File(list);//保存到文件
					cout<<"更新成功!"<<endl;
				}
				else
				{ 
					cout<<"更新失败!"<<endl;
				}
			}
			else
			{ 
				cout<<"未更改!"<<endl;
			}

			break;
		case 0:
			return;
		default:
			cout<<"请输入0~1"<<endl;
			break;
		}
		system("pause");//因为有清屏动作,所以暂停一下,让用户查看输出信息
	}
}

void Save2File(CList& list)//将数据保存到文件
{ 
	SNode* listHead = list.GetListHead();//获取到链表头结点
	if(listHead == NULL)
	{ 
		return;
	}
	
	ofstream fout(FILE_PATH,ios_base::binary);//不存在则创建,存在则会清空。
	//fout.clear();//清空文件数据

	SNode* p = listHead->next;
	while(p !=NULL )
	{ 
		fout<<p->stu.ToString()<<" ";//以空格分隔数据
		p = p->next;
	}

	fout.close();//关闭流
	return;
}

void Read4File(CList& list)//读取文件数据 到链表中
{ 
	SNode node;
	int beforeId = -1;//上一个id
	int id = -1;//临时存放学号
	string name = "";//临时存放姓名
	string _class = "";//存放班级
	float score=0;

	ifstream fin;
	fin.open(FILE_PATH, ios_base::in);//打开文件
	if(fin == NULL)//文件不存在,直接返回
	{ 
		return;
	}

	while(!fin.eof())//循环读取直到文件末尾
	{ 
		fin>>id>>name>>_class>>score;
		if(id>0 && id != beforeId)//因为空格的原因 读取读后一个数据两次,这里使用beforeId来避免重复添加
		{ 
			node.stu.SetId(id);
			node.stu.SetName(name);
			node.stu.SetClass(_class);
			node.stu.SetScore(score);
			list.AddTail(node);//添加
		}
		beforeId = id;//记录上一次id
	}

	fin.close();//关闭文件流
	return;
}

void ClearFileData()//清空文件数据,方便测试
{ 
	char isSure = 'n';//是否确认清除数据
	cout<<"确认清除文件数据?(y/n):";
	cin>>isSure;
	if(isSure == 'Y' || isSure == 'y')
	{ 
		ofstream fout(FILE_PATH);//不存在则创建,存在则会清空
		fout.close();
		cout<<"清除文件数据成功!"<<endl;
		system("pause");
	}
}

void SortMenu()//排序菜单
{ 
	cout<<"┏━━━━━━━━━━┓"<<endl;
	cout<<"┃ 排序菜单 ┃"<<endl;
	cout<<"┃ 【1】 按学号排序 ┃"<<endl;
	cout<<"┃ 【2】 按姓名排序 ┃"<<endl;
	cout<<"┃ 【3】 按班级排序 ┃"<<endl;
	cout<<"┃ 【4】 按分数排序 ┃"<<endl;
	cout<<"┃ 【0】 返回 ┃"<<endl;
	cout<<"┗━━━━━━━━━━┛"<<endl;
	cout<<" ******请输入0~4:";
}

void Sort(CList& list)
{ 
	char isSave = 'n';//是否将排序后的数据更新到文件
	int choice = -1;
	while(true)
	{ 
		system("cls");//清屏
		SortMenu();
		cin>>choice;
		switch(choice)
		{ 
		case 1://按学号排序
		case 2://按姓名排序
		case 3:
		case 4://按班级排序
			list.Sort(choice-1);
			if(choice == 1)
			{ 
				cout<<"***按学号升序排序如下:"<<endl;
			}
			else if(choice == 2)
			{ 
				cout<<"***按姓名升序排序如下:"<<endl;
			}
			else if(choice == 3)
			{ 
				cout<<"***按班级升序排序如下:"<<endl;
			}
			else if(choice == 4)
			{ 
				cout<<"***按分数升序排序如下:"<<endl;
			}
			cout<<"序号\t学号 姓名 班级 分数"<<endl;
			list.DisplayListData();//显示
			cout<<"是否将排序后的数据更新到文件?(y/n):";
			cin>>isSave;
			if(isSave == 'Y' || isSave == 'y')//确认保存到文件
			{ 
				Save2File(list);//将数据重新写入到文件
				cout<<"保存数据成功!"<<endl;
				system("pause");
			}
			else
			{ 
				list.Clear();//清空链表数据
				Read4File(list);//重新加载数据文件
			}
			break;
		case 0:
			return;
			break;
		default:
				cout<<"请输入0~3"<<endl;
				system("pause");
				break;
		}
	}
}

void MainMenu()//主菜单
{ 
	cout<<"┏━━━━━━━━┓"<<endl;
	cout<<"┃学生信息管理程序┃"<<endl;
	cout<<"┃ 【1】 显示 ┃"<<endl;
	cout<<"┃ 【2】 添加 ┃"<<endl;
	cout<<"┃ 【3】 查找 ┃"<<endl;
	cout<<"┃ 【4】 修改 ┃"<<endl;
	cout<<"┃ 【5】 排序 ┃"<<endl;
	cout<<"┃ 【6】 删除 ┃"<<endl;
	cout<<"┃ 【7】 清空 ┃"<<endl;
	cout<<"┃ 【0】 退出 ┃"<<endl;
	cout<<"┗━━━━━━━━┛"<<endl;
	cout<<" *****请输入0~7:";
}

node.h

//链表节点
typedef struct SNode
{ 
	Student stu;//数据域
	struct SNode* next;//指针域
	SNode()//无参构造函数
	{ 
		stu.SetId(0);
		next = NULL;
	}
	SNode(int id)//有参构造函数
	{ 
		stu.SetId(id);
		next = NULL;
	}
}SNode;

student.h

//学生类
#include <sstream>
using namespace std;//int转string
class Student
{ 
private:
	int m_id;//学号
	string m_name;//姓名
	string m_class;//班级
	float m_score;
public:
	Student()//无参构造函数
	{ 
		m_id = 0;
		m_score=0;
		m_name = "0";
		m_class = "0";
	}
	Student(int id, string name, string _class,float score)//有参构造函数,class是关键字,所以不能用作变量名
	{ 
		if(id < 0)//确保id不为负数
		{ 
			id = 0;
		}
		this->m_id = id;

		if(name.empty())//确保name不为空
		{ 
			name = "0";
		}
		this->m_name = name;

		if(_class.empty())//确保_class不为空
		{ 
			_class = "0";
		}
		this->m_class = _class;
		if(score<0)//确保_class不为空
		{ 
			score = 0;
		}
		this->m_score = score;

	}
	void SetId(int id)//设置id
	{ 
		if(id < 0 )//确保id>0,id=0为无效
		{ 
			id = 0;
		}
		this->m_id = id;
	}
	int GetId()//获取id
	{ 
		return this->m_id;
	}
	void SetName(string name)//设置姓名
	{ 
		if(name.empty())//确保name不为空
		{ 
			name = "0";
		}
		this->m_name = name;
	}
	string GetName()//获取姓名
	{ 
		return this->m_name;
	}
	void SetClass(string _class)//设置班级
	{ 
		if(_class.empty())//确保_class不为空
		{ 
			_class = "0";
		}
		this->m_class = _class;
	}
	string GetClass()//获取班级
	{ 
		return this->m_class;
	}
	void SetScore(float score)//设置id
	{ 
		if(score < 0 )//确保id>0,id=0为无效
		{ 
			score = 0;
		}
		this->m_score = score;
	}
	float GetScore()//获取id
	{ 
		return this->m_score;
	}
	string ToString()//将数据转为字符串形式,方便存到文件中
	{ 
		stringstream ss;
		ss<<m_id<<" "<<m_name<<" "<<m_class<<" "<<m_score;//学号 姓名 班级
		return ss.str();
	}
};

使用GCC编译。

    原文作者:T-cookie
    原文地址: https://blog.csdn.net/weixin_43518179/article/details/104736386
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞