文章目录
实验要求
实验要求:将班上同学的信息(编号(001对应第一个,008对应第八个),姓名,性别,年龄,学校,年级,班级,爱好……),使用自己设计的结构体来存储。并在此基础上结合之前学的vector设计一个管理系统,并按以下要求实现
1.main函数大致按以下框架实现。(需要增加自己的系统功能就自己再加)
2.增加学生信息---构造一个学生,将其保存到vector里面
3.修改学生信息---输入学生编号,以及对应自己想修改的信息,比如修改001号学生的姓名,也可以修改001号学生的年龄
4.删除学生信息---输入学生编号,删除该学生信息
5.查询学生信息---输入学生编号,输出其具体信息,并且查询全部学生的具体信息
6.将程序中所得到的学生信息存储到文件中。(一行一个学生)(可以在退出整个程序时,将程序所有的学生信息写入文件,也可以自己想一种更高效的方式)
7.将文件中的学生信息读取到程序中。(每次程序运行时,需要先从文件中读入已有学生信息以免反复输入重复的学生信息)
一、实验平台
操作系统:win10
语言:C++17
IDE:Clion/Dev-cpp/Red-Panda
二、代码
1.结构体以及相关变量
学生Struct结构体
struct Student{
int no,age;
string name,sex,school,class_1,hobby;
//class是一个C++的关键字,所以用class_1表示班级
Student(){
}
Student(int no1){
no = no1;
}
};
vector<Student> banji;//banji代表存储快班所有学生的动态数组
banji是作为全局变量来使用的。struct里面的两个函数是构造函数(我在使用结构体的时候喜欢加上一两个构造函数来简化代码)
//假设上面的结构体中再加一个构造函数。
Student(int no1,int age1,string name1,string sex1,string shcool1){
no=no1;
age=age1;
name=name1;
sex=sex1;
school=school1;
}
//那么我在构造一个学生对象的时候就可以这样做
Studnet s(1,48,"张三","男","社会大学");
//而不是像下面这样啰啰嗦嗦的
Student s;
s.no= 1;
s.age= 48;
s.name= "张三";
s.sex= "男";
s.school= "社会大学";
2.相关函数实现过程
(1)判断一个学生是否已经存在
int isInBanji(Student& s){
for(int i=0;i<banji.size();i++){
if(s.no==banji[i].no){
return i;
}
}
return -1;
}
根据学号判断学生是否存在,该处使用-1代表不存在,0~n-1代表其下标。不简化为bool类型的函数,是为了在后面需要用到查找学生下标好直接调用
(2)从文件中读写学生信息
void writeToFile(){
ofstream fout("student.txt");
for(auto& s:banji) {
fout << s.no << " " << s.name << " " << s.sex << " " << s.age << " " << s.school << " " << s.class_1 << " "
<< s.hobby << endl;
}
fout.close();
}
void readFromFile(){
ifstream fin("student.txt");
Student s;
while(!fin.eof()){
fin>>s.no>>s.name>>s.sex>>s.age>>s.school>>s.class_1>>s.hobby;
if(fin.fail())
break;
banji.push_back(s);
}
fin.close();
}
创建一个student.txt的文件来存储学生信息。ifstream,ofstream来进行对应的文件操作。特别注意的是在读文件时,需要加上fin.fail()的判断,不然文件最后一行会被读两次。最后在操作完文件后,不要忘记文件的关闭-close();
(3)增加学生
void addStu(){
Student s;
// string op[6]={"编号","姓名",};
cout<<"输入添加学生的 编号 姓名 性别 年龄 学校 班级 爱好:\n";
cin>>s.no>>s.name>>s.sex>>s.age>>s.school>>s.class_1>>s.hobby;
if(isInBanji(s)==-1) {
banji.push_back(s);
cout<<"成功添加一个学生!"<<endl;
return ;
}
cout << "该编号学生已经存在,无法反复添加!" << endl;
}
首先声明一个学生对象s,然后输出一串提示信息,依次输入对应的信息。根据编号来查找注意的是不能添加重复编号的学生。输入信息无误,就调用vector自带的函数push_back(),把学生压入向量
(4)删除学生
void delStu(){
cout<<"输入需要删除的学生编号:"<<endl;
int no;
cin>>no;
Student s(no);//调用Student(int no1)构造函数
int ind = isInBanji(s);
if(ind!=-1){
banji.erase(banji.begin()+ind);//删除下标为ind的学生
cout<<"成功删除一个学生!"<<endl;
return ;
}
cout<<"该编号学生不存在,无法删除!"<<endl;
}
(5)修改学生
void changeStu(){
cout<<"输入需要修改的学生的编号:";
int no;
cin>>no;
Student s(no);
int ind = isInBanji(s);
if(ind==-1){
cout<<"该编号学生不存在,无法修改!"<<endl;
return ;
}
int op;
while(1){
cout<<"0-退出修改\n"
"1-修改姓名\n"
"2-修改性别\n"
"3-修改年龄\n"
"4-修改学校\n"
"5-修改班级\n"
"6-修改爱好\n";
cin>>op;
if(op==0)break;
cout<<"原信息:";
switch (op) {
case 1:cout<<banji[ind].name<<" 修改后:";
cin>>banji[ind].name;break;
case 2:cout<<banji[ind].sex<<" 修改后:";
cin>>banji[ind].sex;break;
case 3:cout<<banji[ind].age<<" 修改后:";
cin>>banji[ind].age;break;
case 4:cout<<banji[ind].school<<" 修改后:";
cin>>banji[ind].school;break;
case 5:cout<<banji[ind].class_1<<" 修改后:";
cin>>banji[ind].class_1;break;
case 6:cout<<banji[ind].hobby<<" 修改后:";
cin>>banji[ind].hobby;break;
}
}
}
同样的套路,定义一个学生对象,通过输入对应的编号,先用isInBanji函数查出该学生的下标,然后通过提示信息,进行下一步的修改。
(6)查询学生
void findStu(){
cout<<"输入需要查询的学生编号(查询全部输入-1):\n";
int no;
cin>>no;
if(no==-1){
printf("%3s %3s %2s %3s %10s %8s %20s\n",
"编号","姓名","性别","年龄","学校","班级","爱好");
for(auto& s: banji){
printf("%3d %3s %2s %3d %10s %8s %20s\n",
s.no,s.name.c_str(),s.sex.c_str(),s.age,
s.school.c_str(),s.class_1.c_str(),s.hobby.c_str());
// cout<<s.no<<" "<<s.name<<" "<<s.sex<<" "<<s.age<<" "<<s.school<<" "<<s.class_1<<" "<<s.hobby<<endl;
}
}
else{
Student s(no);
int ind = isInBanji(s);
if(ind == -1){
cout<<"该编号学生不存在,请输入正确的编号!"<<endl;
}
else{
s = banji[ind];
printf("%3s %3s %2s %3s %10s %8s %20s\n",
"编号","姓名","性别","年龄","学校","班级","爱好");
printf("%3d %3s %2s %3d %10s %8s %20s\n",
s.no,s.name.c_str(),s.sex.c_str(),s.age,
s.school.c_str(),s.class_1.c_str(),s.hobby.c_str());
}
}
}
提供两种查询方法,查询全部学生,查询单个学生。查全部的就for循环遍历。查单个的就用isInBanji函数查出对应下标,再printf()输出就OK啦
(7)main函数的实现
int main() {
int option;
readFromFile();
while(1){
cout<<"0-退出\n";
cout<<"1-增加学生\n";
cout<<"2-删除学生\n";
cout<<"3-修改学生\n";
cout<<"4-查询学生\n";
cout<<"选择系统功能:";
cin>>option;
if(option==0){
break;
}
switch (option) {
//调用自己实现的函数功能
case 1:addStu();break;
case 2:delStu();break;
case 3:changeStu();break;
case 4:findStu();break;
default:cout<<"请输入正确的编号\n";
}
}
writeToFile();
}
在main函数开始处,把文件的数据读入到banji中。然后一个while()循环,开始人机交互,根据提示输出对应的选项,调用写好的增删改查功能。最后退出循环后,将banji的所有数据写回到文件中(这里直接用的全覆盖方式)
3.整体代码
#include <bits/stdc++.h>
using namespace std;
//#define rep(i, a, b) for(int i=a;i<b;i++)
//#define rrep(i, a, b) for(int i=a;i>b;i--)
struct Student{
int no,age;
string name,sex,school,class_1,hobby;
//class是一个C++的关键字,所以用class_1表示班级
Student(){
}
Student(int no1){
no = no1;
}
};
vector<Student> banji;//banji代表存储快班所有学生的动态数组
/*
* 返回-1代表在班级中没有查到该学生,否则返回学生在其中的下标
*/
int isInBanji(Student& s){
for(int i=0;i<banji.size();i++){
if(s.no==banji[i].no){
return i;
}
}
return -1;
}
void writeToFile(){
ofstream fout("student.txt");
for(auto& s:banji) {
fout << s.no << " " << s.name << " " << s.sex << " " << s.age << " " << s.school << " " << s.class_1 << " "
<< s.hobby << endl;
}
fout.close();
}
void readFromFile(){
ifstream fin("student.txt");
Student s;
while(!fin.eof()){
fin>>s.no>>s.name>>s.sex>>s.age>>s.school>>s.class_1>>s.hobby;
if(fin.fail())
break;
banji.push_back(s);
}
fin.close();
}
void addStu(){
Student s;
// string op[6]={"编号","姓名",};
cout<<"输入添加学生的 编号 姓名 性别 年龄 学校 班级 爱好:\n";
cin>>s.no>>s.name>>s.sex>>s.age>>s.school>>s.class_1>>s.hobby;
if(isInBanji(s)==-1) {
banji.push_back(s);
cout<<"成功添加一个学生!"<<endl;
return ;
}
cout << "该编号学生已经存在,无法反复添加!" << endl;
}
void delStu(){
cout<<"输入需要删除的学生编号:"<<endl;
int no;
cin>>no;
Student s(no);//调用Student(int no1)构造函数
int ind = isInBanji(s);
if(ind!=-1){
banji.erase(banji.begin()+ind);//删除下标为ind的学生
cout<<"成功删除一个学生!"<<endl;
return ;
}
cout<<"该编号学生不存在,无法删除!"<<endl;
}
void changeStu(){
cout<<"输入需要修改的学生的编号:";
int no;
cin>>no;
Student s(no);
int ind = isInBanji(s);
if(ind==-1){
cout<<"该编号学生不存在,无法修改!"<<endl;
return ;
}
int op;
while(1){
cout<<"0-退出修改\n"
"1-修改姓名\n"
"2-修改性别\n"
"3-修改年龄\n"
"4-修改学校\n"
"5-修改班级\n"
"6-修改爱好\n";
cin>>op;
if(op==0)break;
cout<<"原信息:";
switch (op) {
case 1:cout<<banji[ind].name<<" 修改后:";
cin>>banji[ind].name;break;
case 2:cout<<banji[ind].sex<<" 修改后:";
cin>>banji[ind].sex;break;
case 3:cout<<banji[ind].age<<" 修改后:";
cin>>banji[ind].age;break;
case 4:cout<<banji[ind].school<<" 修改后:";
cin>>banji[ind].school;break;
case 5:cout<<banji[ind].class_1<<" 修改后:";
cin>>banji[ind].class_1;break;
case 6:cout<<banji[ind].hobby<<" 修改后:";
cin>>banji[ind].hobby;break;
}
}
}
void findStu(){
cout<<"输入需要查询的学生编号(查询全部输入-1):\n";
int no;
cin>>no;
if(no==-1){
printf("%3s %3s %2s %3s %10s %8s %20s\n",
"编号","姓名","性别","年龄","学校","班级","爱好");
for(auto& s: banji){
printf("%3d %3s %2s %3d %10s %8s %20s\n",
s.no,s.name.c_str(),s.sex.c_str(),s.age,
s.school.c_str(),s.class_1.c_str(),s.hobby.c_str());
// cout<<s.no<<" "<<s.name<<" "<<s.sex<<" "<<s.age<<" "<<s.school<<" "<<s.class_1<<" "<<s.hobby<<endl;
}
}
else{
Student s(no);
int ind = isInBanji(s);
if(ind == -1){
cout<<"该编号学生不存在,请输入正确的编号!"<<endl;
}
else{
s = banji[ind];
printf("%3s %3s %2s %3s %10s %8s %20s\n",
"编号","姓名","性别","年龄","学校","班级","爱好");
printf("%3d %3s %2s %3d %10s %8s %20s\n",
s.no,s.name.c_str(),s.sex.c_str(),s.age,
s.school.c_str(),s.class_1.c_str(),s.hobby.c_str());
}
}
}
int main() {
int option;
readFromFile();
while(1){
cout<<"0-退出\n";
cout<<"1-增加学生\n";
cout<<"2-删除学生\n";
cout<<"3-修改学生\n";
cout<<"4-查询学生\n";
cout<<"选择系统功能:";
cin>>option;
if(option==0){
break;
}
switch (option) {
//调用自己实现的函数功能
case 1:addStu();break;
case 2:delStu();break;
case 3:changeStu();break;
case 4:findStu();break;
default:cout<<"请输入正确的编号\n";
}
}
writeToFile();
}
总结
通过本实验,我学到了如何解决ifstream读取文件末尾会读两次的问题。