C++实现简易图书馆管理系统

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: C++实现简易图书馆管理系统



一、 概要设计

   本程序为图书馆管理系统。按需求,本程序大致分为2个部分:其一是管理员部分,其二是借阅者部分。模块的切换可以在main函数中让用户输入选项数字来确定。

二、详细设计

模块一:管理员模块

一、概要设计

 总共有6个功能:

       1.显示图书信息。包括图书的书名、价格、作者、总库存、现库存、借阅记录等。

       2.添加图书。添加新的图书。

       3.修改图书信息。可以直接修改图书的各项信息。

       4.删除图书。

       5.清除图书借阅记录。

       6.显示借阅者信息。

   模块二:借阅者模块

   总共有2个功能

       1.借书。

       2.还书。

二 、详细设计

  1.结构体

struct LendBook{   //被借出去的书
    string time;   //借阅时间
    string name;   //书名
};
struct LendList{   //借阅的书的链表
    string stuNum;  //学号
    LendList *next;  //指针
    vector<LendBook>v;  //向量,存储借阅的书
};
struct Book{      //图书文件
    string name;   //书名
    double price;  //价格
    string author;  //作者
    double allStock; //所有库存
    double nowStock; //现有库存
    bool isLend;     //借阅与否
    vector<string>record;  //存储借阅记录的向量
};
struct List{    //图书链表
    Book *book;  //Book类结构体
    List *next;  //指针
};

其实用类更好。不过我上数据结构课用的就是结构体,已经习惯了。

LendBook和Book是基本类型。LendList和List是这两种基本类型的链表。由于本程序要进行文件操作,涉及到一些文件的删改,如果直接对文件进行改动的话很不方便。所以这里采用的思路是先由文件生成链表,在链表中进行信息的改动,之后再把链表中的信息一起写入文件(所以这里是直接覆盖文件)。

2、函数

       管理员模块:

string timeNow(){  //得到现在的时间 
  time_t rawtime;
    time(&rawtime);   
    struct tm * timeinfo;
    timeinfo = localtime(&rawtime);
    timeinfo = gmtime(&rawtime);
    char   pblgtime[20];
    strftime(pblgtime, 20, "%Y-%m-%d-%X", localtime(&rawtime));
    int i=0;
    string str="";
    while(pblgtime[i]!='\0'){
      str+=pblgtime[i];
      i++;
  }
    return str;
}

这个函数是得到现在的时间。参照这位大神的博客:

(75条消息) <C++>获取并显示当前时间_jenny_84的专栏-CSDN博客_c++显示时间

List * fileToList(){   //将图书的信息转换为链表 
  List *list = new List;
  list->next=NULL;
  List *r = list;
  ifstream myfile;
  myfile.open("LibraryDate.txt",ios::in);   //读文件 
    string temp; 
    if (!myfile.is_open())
    {
        cout << "未成功打开文件" << endl;
    } 
    while(getline(myfile,temp)) 
    {
//        cout<<temp<<endl;
    stringstream is(temp);    //将is绑定到str
      string s;
      int i=0;
      Book *book = new Book();
      vector<string>v;
      while (is >> s)
      {
        switch(i){
          case 0:{
            book->name = s;
          break;
        }
        case 1:{
          double nums;
          stringstream ss;
          ss<<s;
          ss>>nums;
          book->price = nums;
          break;
        }
        case 2:{
          book->author = s;
          break;
        }
        case 3:{
          double nums;
          stringstream ss;
          ss<<s;
          ss>>nums;
          book->allStock = nums;
          break;
        }
        case 4:{
          double nums;
          stringstream ss;
          ss<<s;
          ss>>nums;
          book->nowStock = nums;
          break;
        }
        case 5:{
          int ret = s.compare("true");
          switch(ret){
            case 0:{
              book->isLend = true;
              break;
            }
            default:{
              book->isLend = false;
              break;
            }
          }
          break;
        }
        default:{
          v.push_back(s);
          break;
        }
      }
      i++;
      }
      List *p = new List;
      book->record=v;
      p->book = book;
      r->next = p;
      p->next = NULL;
      r = p;
    }
    myfile.close();
    return list;
}

ifstream是文件输出流,头文件是fstream

getline(myfile,temp)函数是把文件的内容按行读取,每行的数据存储在temp中。

我设置的文件格式是这样的:

每本书的信息占一行,书的不同信息之间按空格分开。而要怎么才能按照空格分割string字符串呢?我这里用的是stringstream,包含在sstream头文件中。而程序中的is >>s则是以空格分割标记,并分别赋值给字符串s。我在这里用了一个辅助变量i,按照i的取值来确定s的信息类型(比如第一次分割得到的是书名,此时i=0)。一次类推。向量存储的是这本书的借阅记录。这些信息都存储在一个Book对象中,尾插到链表后。

void reviseFile(List *&m){     //修改图书文件信息 
  if(m==NULL){
    cout<<"修改文件失败!!!"<<endl; 
    return ;
  }
  ofstream ofs;
  ofs.open("LibraryDate.txt",ios::out);
  List *r = m->next;
  while(r!=NULL){
    string yes;
    if(r->book->isLend){
      yes = "true";
    }
    else{
      yes = "false";
    }
    ostringstream ost;
    vector<string>v;
    v = r->book->record;
    for (vector<string>::iterator it = v.begin(); it != v.end(); it++) {
      ost<<*it;
    }
    ost<<" "<<"\n";
      ostringstream oss;
    oss<<r->book->name<<" "<<r->book->price<<" "<<r->book->author<<" "<<r->book->allStock<<" "<<r->book->nowStock<<" "<<yes<<" ";
    ofs<<oss.str();
    ofs<<" ";   //在每个信息的后面插入空格
    ofs<<ost.str();
    r=r->next;
  }
  ofs.close();
}

这个函数是把链表中的信息存储到文件中。ostringstream变量是为了方便多个字符串的合成(用<<操作字符)。我发现在ostringstream变量添加空格,但是文件中经常不会显示有空格。所以我单独用文件操作符添加了空格。

void changeElement(List *&m){   //修改图书个别信息 
  if(m==NULL){
    cout<<"修改失败!"<<endl;
    return ;
  }
  else{
    cout<<"-----现在您是在修改数据界面!-----"<<endl<<"在下一项输入”999999“以退出"<<endl; 
    cout<<"您需要先输入书名"<<"或许您需要先预览一下书目?输入“1”预览,输入“0”直接进入修改:";
    int choice;
    while (!(cin >>choice))
      {
        cin.clear();
        while (cin.get() != '\n')
        {
          continue;
        }//跳过错误输入
        cout << "请输入一个数字:"<<endl;
      }
    List *r = m->next;
    List *pre=m;
    
    if(choice==999999){
      cout<<"退出成功!"<<endl;
      return ;
    }
    
    if(choice==1){
      int i=0;
      while(r!=NULL){
        if(i%5==0){
          cout<<endl;
        }
        cout<<r->book->name<<" ";
        i++;
        r=r->next;
      }
    }
    string str;
    cout<<"请输入你需要修改的书的书名:";
    cin>>str;
    
    r = m->next;
    while(r!=NULL){
      if(r->book->name==str){
        break;
      }
      r=r->next;
    }
    if(r==NULL){
      cout<<"您想修改的书不存在!此项即将退出,试一试重新输入吧!"<<endl;
      return ;
    }
    
    cout<<"您可以自由选择需要修改的项目,输入相应的序号即可!如果想修改数项,请输入“0”"<<endl;
    cout<<"1.书名 2.价格 3.作者 4.总库存 5.现库存 6是否借出:"<<endl;
    while (!(cin >>choice)){
      cin.clear();
      while (cin.get() != '\n')
      {
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    while(choice>6||choice<0){
      cout<<"检查一下是不是序号输错了,再输一遍吧"<<endl;
      while (!(cin >>choice)){
        cin.clear();
        while (cin.get() != '\n'){
          continue;
        }//跳过错误输入
        cout << "请输入一个数字:"<<endl;
      }
    }
    string tarStr;
    double tarNum;
    switch(choice){
      case 1:{
        cout<<"请输入您想修改的名字:";
        cin>>tarStr;
        r->book->name=tarStr;
        break;
      }
      case 2:{
        cout<<"请输入您想修改的价格:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        r->book->price=tarNum; 
        break;
      }
      case 3:{
        cout<<"请输入您想修改的作者:";
        cin>>tarStr;
        r->book->author = tarStr;
        break;
      }
      case 4:{
        cout<<"请输入您想修改的总库存量:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        r->book->allStock=tarNum;
        break;
      }
      case 5:{
        cout<<"请输入您想修改的现库存量:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        r->book->nowStock=tarNum;
        break;
      }
      case 6:{
        cout<<"输入”1“代表借出,输入“0”代表未借出:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        bool is;
        if(tarNum==1){
          is = true;
        } 
        else{
          is=false;
        }
        r->book->isLend=is;
        break;
      }
      case 0:{
        cout<<"请输入您想修改的名字:";
        cin>>tarStr;
        r->book->name=tarStr;
        
        cout<<"请输入您想修改的价格:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        r->book->price=tarNum; 
        
        cout<<"请输入您想修改的作者:";
        cin>>tarStr;
        r->book->author = tarStr;
        
        cout<<"请输入您想修改的总库存量:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        r->book->allStock=tarNum;
        
        cout<<"请输入您想修改的现库存量:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        r->book->nowStock=tarNum;
        
        cout<<"输入”1“代表借出,输入“0”代表未借出:";
        while (!(cin >>tarNum)){
          cin.clear();
          while (cin.get() != '\n'){
            continue;
          }//跳过错误输入
          cout << "请输入一个数字:"<<endl;
        }
        bool is;
        if(tarNum==1){
          is = true;
        } 
        else{
          is=false;
        }
        r->book->isLend=is;
        break;
      }
      default:{
        
        break;
      }
    }
    reviseFile(m);
    cout<<"修改成功!!"<<endl;
  }
}

这段修改书籍信息的代码如果可以通过可视化窗口会简单很多。

值得注意的是:检测用户输入的字符是不是数字字符,如果不是提醒,并让其重新输入。这个功能用到的主要知识点主要是cin.clear()这个函数。这段代码在后面用了很多次:

void addElement(List *&m){   //添加图书 
  if(m!=NULL){
    List *r = m;
    while(r->next!=NULL){
      r=r->next;
    }
    cout<<endl<<"TIPS: 你正在进行添加操作,输入“999999”即可终止此操作!!"<<endl;
    cout<<"新增的书默认没有借出记录"<<endl;
    string pause = "999999";
    
    string str01;
    cout<<"请输入书籍名:";
    cin>>str01;
    if(str01==pause){
      cout<<"-----退出成功!-----"<<endl;
      return ;
    }
    
    double price;
    cout<<"请输入价格:";
    while (!(cin >>price))
    {
      cin.clear();
      while (cin.get() != '\n')
      {
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    
    if(price == 999999){
      cout<<"-----退出成功!-----"<<endl;
      return ;
    }
    
    string str02;
    cout<<"请输入作者名:";
    cin>>str02;
    
    if(str02==pause){
      cout<<"-----退出成功!-----"<<endl;
      return ;
    }
    
    double nums01;
    cout<<"请输入总库存量:";
    while (!(cin >>nums01))
    {
      cin.clear();
      while (cin.get() != '\n')
      {
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    if(nums01==999999){
      cout<<"退出成功!"<<endl;
      return ;
    }
    
    double nums02;
    cout<<"请输入现有库存量:";
    while (!(cin >>nums02))
    {
      cin.clear();
      while (cin.get() != '\n')
      {
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    
    if(nums02==999999){
      cout<<"退出成功!"<<endl;
      return ;
    }
    
    Book *book = new Book;
    List *p = new List;
    book->name = str01;
    book->price = price;
    book->author = str02;
    book->isLend = false;
    book->allStock = nums01;
    book->nowStock = nums02;
    p->book = book;
    r->next = p;
    p->next = NULL;
    cout<<"添加新书成功!"<<endl;
    
    reviseFile(m);
  }
}

这是添加图书的函数。没什么难的。简单在链表后添加信息。

void moveElement(List *&m){     //删除图书 
  cout<<"默认是根据书名来进行删除!"<<endl<<"您或许需要现预览一遍全部书籍名称?输入“1”预览或输入“0”直接进入删除:";
  long choice;
  while (!(cin >>choice))
    {
      cin.clear();
      while (cin.get() != '\n')
      {
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
  List *r = m->next;
  List *pre=m;
  
  if(choice==999999){
    cout<<"退出成功!"<<endl;
    return ;
  }
  
  if(choice==1){
    int i=0;
    while(r!=NULL){
      if(i%5==0){
        cout<<endl;
      }
      cout<<r->book->name<<" ";
      i++;
      r=r->next;
    }
  }
  string str;
  cout<<endl<<"请输入你想删除的书的书名(区分大小写):";
  cin>>str;
  
  if(str=="999999"){
    cout<<"退出成功!"<<endl;
    return ;
  }
  
  pre=m;
  r=m->next;
  while(r!=NULL){
    if(r->book->name==str){
      pre->next=r->next;
      delete r;
      break;
    }
    pre=r;
    r=pre->next;
  }
  cout<<"-----删除成功!-----"<<endl;
  reviseFile(m);
}

这是删除书籍的函数。直接删除链表中是的数字即可。凡是设计到链表的删除的应该都会用到一前一后两个指针。记得在最后面要对文件进行修改

void clearRecord(List *&m){    //清除图书借阅记录 
  cout<<"您确定清除所有借阅记录吗?此项操作不可恢复!  输入“1”确认,输入“0”退出:"<<endl;
  int choice;
  while (!(cin >>choice)){
    cin.clear();
    while (cin.get() != '\n'){
      continue;
    }//跳过错误输入
    cout << "请输入一个数字:"<<endl;
  }
  if(choice==1){
    List *r = m->next;
    while(r!=NULL){
      r->book->record.clear();
      r=r->next;
    }
    reviseFile(m);
    cout<<"-----清除完毕!-----"<<endl;
    return ;
  }
  else{
    cout<<"-----退出成功!!------"<<endl;
    return ;
  }
}

这是清除所有的借阅记录。之所以会有这样的函数是因为我觉得很多借阅记录在文件里实在是太密了。注意这里的向量的clear()方法是不会把向量的存储空间都释放的,只会删除空间存储的数据。

void dispReader(LendList *&m){    //展示读者文件信息 
  if(m==NULL){
    cout<<"无数据!输出失败!!"<<endl;
    return ;
  }
  LendList *r = m->next;
  cout<<endl<<"--------借阅者信息如下:----------"<<endl;
  while(r!=NULL){
    vector<LendBook>v;
    LendBook lendbook;
    v = r->v;
    cout<<"学号为"<<r->stuNum<<"的同学的借阅记录如下:"<<endl;
    int i=0;
    for (vector<LendBook>::iterator it = v.begin(); it != v.end(); it++) {
      lendbook = *it;
      cout<<"   于"<<lendbook.time<<"借阅《"<<lendbook.name<<"》一书"<<endl; 
    }
    r=r->next;
    cout<<endl;
  }
  cout<<"----------借阅者信息输出完毕!!----------"<<endl;
}

这是展示借阅者信息的函数。主要也就是向量的遍历

模块二:借阅者模块

一、概要设计

总共有2个功能

       1.借书。

       2.还书。

借阅者通过学号登录

二、详细设计

LendList * LendDataToList(){   //将读者的借阅信息转换为链表 
  LendList *allList = new LendList;
  allList->next = NULL;
  LendList *r = allList;
  ifstream myfile;
  myfile.open("ReaderDate.txt",ios::in);
  string temp;
  if(!myfile.is_open()){
    cout<<"文件打开失败!"<<endl;
    return NULL;
  }
  //先判断一下文件是否为空
  ifstream judge;
  judge.open("ReaderDate.txt",ios::in);
  char ch;
  judge>>ch;
  if(judge.eof()){
    return allList;
  }
  //判断完毕 
  while(getline(myfile,temp)){
    LendList *list = new LendList;
    vector<LendBook> v;
    list->next =NULL;
    string s;
    stringstream is(temp);
    int i=0;
    LendBook lendbook;
    while(is>>s){
      if(i==0){
        list->stuNum = s;
      }
      else{
        lendbook.time = s.substr(0,19);
        lendbook.name = s.substr(19,s.length());
        v.push_back(lendbook);
      }
      i++;
    }
    list->v=v;
    r->next = list;
    list->next = NULL;
    r = list;
  }
  myfile.close();
  return allList;
}

创建读者数据链表的过程与创建图书链表的过程相似。不同的是这里用到了string的substr()函数。因为我设计的读者文件是这样的:

时间与借阅书籍放在同一个string变量中,而时间的字数是固定的,所以用substr函数较为方便。在进行文件转换的前面顺便进行文件判空,即如果没有数据就提醒使用者。

void reviceReaderDate(LendList *&m){     //修改读者文件信息 
  if(m==NULL){
    cout<<"存储失败!!"<<endl;
    return ;
  }
  ofstream myfile;
  myfile.open("ReaderDate.txt",ios::out);
  LendList *r = m->next;
  while(r!=NULL){
    ostringstream oss;
    oss<<r->stuNum<<" ";
    vector<LendBook>v;
    v = r->v;
    LendBook lendbook;
    for (vector<LendBook>::iterator it = v.begin(); it != v.end(); it++) {
      lendbook = *it;
      oss<<lendbook.time<<lendbook.name<<" ";
    }
    oss<<"\n";
    myfile<<oss.str();
    r=r->next;
  }
}

这是在对读者链表的数据进行修改后,把链表数据存储到文件中的函数,与上文修改图书文件的操作基本一致。

void Lend(List *&m,LendList *&s,string stuNum){    //读者借书 
  cout<<"-----您正在借书界面-----"<<endl<<"随时输入“999999”即可退出借书界面"<<endl<<"您可能需要先预览书籍?输入“1”预览,输入“0”直接进入借书界面:";
  int choice;
  while (!(cin >>choice)){
    cin.clear();
    while (cin.get() != '\n'){
      continue;
    }//跳过错误输入
    cout << "请输入一个数字:"<<endl;
  }
  if(choice==999999){
    cout<<"退出成功!"<<endl;
    return ;
  }
  if(choice==1){
    List *r = m->next;
    while(r!=NULL){
      cout<<r->book->name<<"  现存量为:"<<r->book->nowStock<<endl;
      r=r->next;
    }
    cout<<endl;
  }
  cout<<"请输入你想借的书的书名:"<<endl;
  string str;
  cin>>str;
  
  if(str=="999999"){
    cout<<"退出成功!!!"<<endl;
    return ;
  }
  
  List *r = m->next;
  while(r!=NULL){
    if(r->book->name==str){
      break;
    }
    r=r->next;
  }
  if(r==NULL){
    cout<<"你想借出的书籍不存在,此项即将退出,试一试重新输入。"<<endl;
    return ;
  }
  if(r->book->nowStock<=0){
    cout<<"很遗憾!您想借出的书籍目前暂时没有库存了,请过几天再来试试看吧。"<<endl<<"或许你还想借另外的书籍,输入“1”即可继续借书,输入0退出此项:"<<endl;
    while (!(cin >>choice)){
      cin.clear();
      while (cin.get() != '\n'){
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    if(choice==1){
      Lend(m,s,stuNum);
    }
    else{
      cout<<"    退出借书界面成功!!"<<endl; 
    }
  }
  else{
    cout<<"一次最多借一本书!"<<endl<<"输入“1”确认借出,输入“0”退出借书功能:"<<endl;
    while (!(cin >>choice)){
      cin.clear();
      while (cin.get() != '\n'){
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    string time = timeNow();  //现在时间 
    ostringstream oss;
    oss<<" 于"<<time<<"被学号为"<<stuNum<<"的同学借走 ";
    string record01 =oss.str();
    
    if(choice==1){
      r->book->nowStock--;
      r->book->isLend=true;
      r->book->record.push_back(record01);
    }
    else{
      return ;
    }
    cout<<"借出成功!借书最大归还时限为一个月,记得及时归还哦。"<<endl;
    reviseFile(m);
    LendList *pp = new LendList;
    //先遍历,查找该学号学生是否有过借书记录
    LendList *rr = s->next;
    LendBook lendbook;
    while(rr!=NULL){
      if(rr->stuNum==stuNum){
        break;
      }
      rr=rr->next;
    }
    lendbook.name = r->book->name;
    lendbook.time = time;
    if(rr!=NULL){
      rr->v.push_back(lendbook);
    }
    else{
      pp->stuNum = stuNum;
      vector<LendBook>vec;
      vec.push_back(lendbook);
      pp->v = vec;
      //遍历至最后一位插入
      rr = s->next;
      while(rr->next!=NULL){
        rr=rr->next;
      }
      rr->next = pp;
      pp->next = NULL;
    }
    reviceReaderDate(s);
  }
}

读者借书的函数。这个函数会修改两个文件的信息。在修改读者文件之前,先遍历链表查找有没有学号对应的读者信息。如果有,则直接在后面插入,如果没有则另外创建一个结点。

void Back(List *&m1,LendList *&m2,string stuNum){   //读者还书 
  cout<<"-----您现在在还书界面-----"<<endl<<"任何时候输入“999999”即可退出本界面    "<<endl;
  long stuNumLong;
  LendList *r = m2->next;
  while(r!=NULL){
    if(r->stuNum==stuNum){
      break;
    }
    r=r->next;
  }
  if(r==NULL||r->v.size()==0){
    cout<<"您没有需要归还的书籍!或许你想在此借书?输入”1“可以进入借书界面,输入”0“此项即将退出。"<<endl;
    int choice;
    while (!(cin >>choice)){
      cin.clear();
      while (cin.get() != '\n'){
        continue;
      }//跳过错误输入
      cout << "请输入一个数字:"<<endl;
    }
    if(choice==1){
      Lend(m1,m2,stuNum);
    }
    else{
      cout<<"------退出成功!------"<<endl;
      return ;
    }
  }
  else{
    cout<<"您需要归还的书籍如下:"<<endl;
    vector<LendBook>v=r->v;
    LendBook lendbook;
    for (vector<LendBook>::iterator it = v.begin(); it != v.end(); it++) {
      lendbook = *it;
      cout<<lendbook.name<<" ";
    }
    bool exit;
    string name;
    isEqual(r,exit,name);
    if(exit){
      return ;
    }
//    cout<<name;
//    return ;   //这里输入的name是正确的 
    vector<LendBook>v1 = r->v;
    vector<LendBook>v2;
    LendBook book;
    for (vector<LendBook>::iterator it = v.begin(); it != v.end(); it++) {
      book = *it;
      if(book.name!=name){
        v2.push_back(book);
      }
    }
    r->v = v2;
    List *r2 = m1->next;
    while(r2!=NULL){
      if(r2->book->name==name){
        r2->book->nowStock++;
        if(r2->book->nowStock>r2->book->allStock){
          r2->book->allStock=r2->book->nowStock;
        }
        ostringstream oss;
        string time = timeNow();
        oss<<" 于"<<time<<"被学号为"<<stuNum<<"的同学归还 ";
        r2->book->record.push_back(oss.str());
        break;
      }
      r2=r2->next;
    }
    reviseFile(m1);
    reviceReaderDate(m2);
    cout<<"------还书成功!------"<<endl;
    return ;
  }
}
bool isEqual(LendList *&r,bool &exit,string &name){   //还书函数的辅助函数(判断读者输入的书名是否存在 
  bool pass = false;
  vector<LendBook>v= r->v;
  cout<<endl<<"输入您想归还的书籍的名称:";
  cin>>name;
  
  if(name=="999999"){
    cout<<"退出借书页面成功!";
    exit = true;
    return true;
  }
  
  LendBook lendbook;
  for (vector<LendBook>::iterator it = v.begin(); it != v.end(); it++) {
    lendbook = *it;
    if(lendbook.name == name){
      pass = true;
      break;
    }
  }
  if(pass){
    return true;
  }
  else{
    cout<<"您输入的书名好像不存在哦,试一试重新输入"<<endl; 
    isEqual(r,exit,name);
  }
}

这是读者借书的函数。isEqual()函数是判断读者输入的书名是不是存在。而还书操作,意味着要把读者文件中相应的借阅信息删掉一次,借阅信息存储在向量中,如何做到删掉?我的方法是重新声明一个向量,把原向量除了归还书籍以外的所有书籍信息都写进新建向量中。

模块三 初始界面模块

void inputPassword(string &str, int size) {   //在登录界面输入密码且让密码不可见 
    char c;
    int count = 0;
    char *password = new char[size]; // 动态申请空间
    while ((c = getch()) != '\r') {
        if (c == 8) { // 退格
            if (count == 0) {
                continue;
            }
            putchar('\b'); // 回退一格
            putchar(' '); // 输出一个空格将原来的*隐藏
            putchar('\b'); // 再回退一格等待输入
            count--;
        }
        if (count == size - 1) { // 最大长度为size-1
            continue;
        }
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {  // 密码只可包含数字和字母
            putchar('*');  // 接收到一个字符后, 打印一个*
            password[count] = c;
            count++;
        }
    }
    password[count] = '\0';
    str = password;
    delete[] password; // 释放空间
    cout << endl;
}

这个函数是使管理员在登录输入密码时,控制台上的密码显示为”*“,且超过设定长度时不会再继续输入。参见:

(76条消息) c++输入隐藏密码的实现_Waydrow的博客-CSDN博客_c++密码隐藏

void inputInfo(){    //管理员登录界面 
  cout<<"请输入用户名:"<<endl;
  string name;
  cin>>name;
  
  if(name=="999999"){
    cout<<"退出成功!" <<endl;
    return ;
  }
  
  cout<<"请输入登录密码:(最大不超过6位数)"<<endl;
  string password;
  inputPassword(password,7);
  
  if(password=="999999"){
    cout<<"退出成功!"<<endl; 
    return ;
  }
  
  ifstream myfile;
  myfile.open("ManagerDate.txt",ios::in);
  string temp;
  bool passOK=false;
  bool nameOK=false;
  while(getline(myfile,temp)){
    passOK = false;
    nameOK = false;
    string s;
      stringstream is(temp);
      int i=0;
      while (is >> s){
        string str = s;
        if(i==1){
          if(password==str){
            passOK=true;
        }
          break;
      }
      else if(i==0){
        if(name==str){
          nameOK=true;
        }
      }
      i++;
      }
      if(passOK&&nameOK){
        cout<<"登录成功!"<<endl<<"请选择操作吧!"<<endl;
      return ;
    }
  }
  myfile.close();
  if(!(passOK&&nameOK)){
    cout<<"密码或用户名输入错误!请尝试重新输入:"<<endl;
    inputInfo();
  }
}

这是管理员登录时的界面。”ManagerDate.txt“文件是这样的:

前面是用户名,后面是密码。当用户输入一个用户名和密码后,遍历文件,如果两者都符合,则判定输入争取,否则递归调用,直至输入正确

void inputNum(bool &ok,string &stuNum){  //学生登录界面 
  cout<<"请输入您的学号:"<<endl;
  long stuNumLong;
  while (!(cin >>stuNumLong)){
    cin.clear();
    while (cin.get() != '\n'){
        continue;
    }//跳过错误输入
    cout << "请输入一个数字:"<<endl;
  }
  
  if(stuNumLong==999999){
    cout<<"退出成功!!"<<endl;
    ok = false;
    return ;
  }
  stringstream sstr;
  sstr<<stuNumLong;
  sstr>>stuNum;
  string regex[] = {"2021","2020","2019","2018"};
  if(stuNum.length()>8){
    cout<<"学号最长为8位数!"<<endl;
    inputNum(ok,stuNum); 
  }
  bool is=false;
  string sub = stuNum.substr(0,4);
//  cout<<sub;
  for(int i=0;i<4;i++){
    if(sub==regex[i]){
      is=true;
      break;
    }
  }
  if(!is){
    cout<<"不存在该学号!!"<<endl;
    inputNum(ok,stuNum);
  }
  if(is){
    ok = true;
    return ;
  }
}

学生登录的界面。学号设定为现在的第一到大四的学生之间,即首四位是2018-2021.且学号长为8;

三、总结

#include<iostream>
#include<vector>
#include <time.h>
#include <sstream>
#include<fstream>
#include<string.h>
#include<conio.h>

这是需要导入的头文件。

另外要注意本程序的文件编码格式设定为:ANSI。

.cpp和.exe以及文件下载:

链接: https://pan.baidu.com/s/1Z1FnENcA-ZDCfYnWxyAfcQ 提取码: 99nw 复制这段内容后打开百度网盘手机App,操作更方便哦

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
3月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
79 0
|
2月前
|
C++
【C++案例】一个项目掌握C++基础-通讯录管理系统
这篇文章通过一个通讯录管理系统的C++项目案例,详细介绍了如何使用C++实现添加、显示、删除、查找、修改和清空联系人等功能。
42 3
|
3月前
|
存储 C++
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
|
3月前
|
Rust 安全 C++
系统编程的未来之战:Rust能否撼动C++的王座?
【8月更文挑战第31天】Rust与C++:现代系统编程的新选择。C++长期主导系统编程,但内存安全问题频发。Rust以安全性为核心,通过所有权和生命周期概念避免内存泄漏和野指针等问题。Rust在编译时确保内存安全,简化并发编程,其生态系统虽不及C++成熟,但发展迅速,为现代系统编程提供了新选择。未来有望看到更多Rust驱动的系统级应用。
61 1
|
3月前
|
存储 算法 数据可视化
【C++】C++旅游管理系统(源码+论文)【独一无二】
【C++】C++旅游管理系统(源码+论文)【独一无二】
|
3月前
|
搜索推荐 数据处理 文件存储
【C++】C++ 培训报名系统 (源码+论文)【独一无二】
【C++】C++ 培训报名系统 (源码+论文)【独一无二】
|
3月前
|
存储 C++
【C++】C++公司人事管理系统(源码)【独一无二】
【C++】C++公司人事管理系统(源码)【独一无二】
|
3月前
|
存储 数据挖掘 C语言
【C/C++】C/C++车辆交通违章管理系统(源码+数据文件)【独一无二】
【C/C++】C/C++车辆交通违章管理系统(源码+数据文件)【独一无二】
|
3月前
|
存储 数据可视化 C++
【C++】C++-机房收费管理系统(源码+注释)【独一无二】
【C++】C++-机房收费管理系统(源码+注释)【独一无二】
|
3月前
|
数据可视化 C++
【C++】C++商店销售管理系统(源码+论文)【独一无二】
【C++】C++商店销售管理系统(源码+论文)【独一无二】