// student.h: interface for the student class.
//
//
#ifndef __student__h__
#define __student__h__
#include <iostream>
using namespace std;
class student
{
friend class subscriber;
friend istream& operator>>(istream&, student&);
friend ostream& operator<<(ostream&, student&);
public:
student(){num = -1; next = NULL;}
~student(){}
public:
string name;
int num;
student *next;
};
class subscriber
{
public:
subscriber(){head = NULL;}
~subscriber(){}
public:
void create(); //创建链表
void insert(); //添加链表
void del(); //删除元素
void print(); //输出全部信息
void search(); //查找信息
void savef(); //保存信息
void loadf(); //加载信息
private:
int NumOfLIst(); //链表节点数
void deleteall(); //删除全部
private:
student* head;
};
#endif
// student.cpp: implementation of the student class.
//
//
#include "stdafx.h"
#include "student.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
istream& operator>>(istream& input, student& t)
{
input>>t.name >> t.num;
return input;
}
ostream& operator<<(ostream& output, student& t)
{
output<<"姓名:"<< t.name<<" 学号:"<<t.num<<endl;
return output;
}
const string strfname = "st.dat";
//创建链表
void subscriber::create()
{
student *p1, *p2;
int i;
int num_node;
cout << "输入创建学生数: "; //输入要创建的学生数
fflush(stdin);
cin >> num_node;
deleteall(); //创建新的前先把已有的全部删除,防止内存泄露
p1 = p2 = new student; //这里创建了一个节点
cout << "请输入姓名,学号,中间用空格隔开: " << endl;
fflush(stdin);
cin >> p1->name >> p1->num; //把输入的数据保存到指针指向的地址中
head = p1;
for (i = 1; i<num_node; i++)
{
p1 = new student;
cin >> p1->name >> p1->num; //循环输入数据直到信息条数到输入人数
p2->next = p1;
p2 = p1;
}
p2->next = NULL;
}
//添加链表
void subscriber::insert()
{
if (head == NULL)
{
create();
}
else{
student *p1, *p2;
string p3;
int p4, i = 0, n;
cout << "输入增加学生数:";
cin >> n;
while (i < n)
{
cout << "请输入姓名,学号,中间用空格隔开:" << endl;
cin >> p3 >> p4;
p2 = head;
while (p2->next != NULL) //从头开始查找数据直到找到同名或到数据末尾
{
while (p4 == p2->num) //判断是否有同一学号的数据
{
cout << "已有记录" << endl;
bool n;
cout << "输入1,重新输入\n输入0,返回主菜单" << endl;
cin >> n;
if (n == 1)
{
cout << "输入1,重新输入\n输入0,返回主菜单" << endl;
cin >> p3 >> p4; //重新输入
}
else
return; //跳出
}
p2 = p2->next;
}
p1 = new student;
p1->name = p3;
p1->num = p4; //查找循环
p2->next = p1;
p2 = p1;
p1->next = NULL;
i++;
}
}
}
//删除链表元素
void subscriber::del()
{
if (head == NULL) // 若列表为空的情况
cout << "列表为空" << endl;
else{
cout << "输入学生姓名" << endl;
student *p1, *p2;
string p3;
cin >> p3;
p1 = head;
if (p1->name.compare(p3) == 0)
{
head = p1->next; //若所输入的数据是head,head删除操作
delete p1;
return;
}
else
{
p2 = p1;
p1 = p2->next;
while (p1 != NULL)
{
if (p1->name.compare(p3) == 0) //若没有在head找到,则在中部循环查找
{
p2->next = p1->next; //查找到后执行中部删除操作
delete p1;
return;
}
p2 = p1;
p1 = p2->next;
}
cout << "查无此人" << endl; //若没有找到匹配的数据
}
}
}
//查找链表元素
void subscriber::search()
{
if (head == NULL)
{
cout << "列表为空" << endl; //若列表为空的情况
}
else{
bool f;
student *p1, *p2;
cout << "姓名查找输入1" << endl; //选择要执行的操作
cout << "学号查找输入0" << endl;
cin >> f;
if (f)
{
string p3;
cout << "输入要查找的学生姓名:" << endl;
cin >> p3;
p1 = head;
p2 = p1->next;
while (p2 != NULL)
{
if (p1->name.compare(p3) == 0)
{
cout << p1->name << " " << p1->num << endl; //按姓名查找
return;
}
p1 = p2;
p2 = p1->next;
}
cout << "查无此人" << endl;
}
else{
int p3;
cout << "输入要查找的学生学号:" << endl;
cin >> p3;
p1 = head;
p2 = p1->next;
while (p2 != NULL)
{
if (p3==p1->num)
{
cout << p1->name << " " << p1->num << endl; //按学号查找
return;
}
p1 = p2;
p2 = p1->next;
}
cout << "查无此人" << endl;
}
}
}
//输出全部信息
void subscriber::print()
{
student *p;
p=head;
if(head==NULL) //链表为空;
{
cout<<"文件为空!"<<endl;
return;
}
else{
cout << "输出所有学生信息:" << endl;
while (p != 0)
{
cout << p->name <<" "<< p->num << endl;
p = p->next;
}
}
}
//保存链表信息
void subscriber::savef()
{
student *p;
string a;
ofstream Name_file("Name_list.txt"); //标识符命名
p = head;
for (; p->next != NULL; p = p->next)
Name_file << p->name << " " << p->num << endl; //输出流操作
Name_file << p->name << " " << p->num << endl;
Name_file.close(); //关闭文件,结束文件操作
}
//加载链表信息
void subscriber::loadf()
{
ifstream Name_file("Name_list.txt");
if (!Name_file)
{
cerr << "没有存档" << endl; //错误报告
return;
}
else{
student *p1, *p2;
deleteall(); //创建新的前先把已有的全部删除,防止内存泄露
p1 = p2 = new student; //这里创建了一个节点
fflush(stdin);
Name_file >> p1->name >> p1->num;
head = p1;
cout << p1->name << " " << p1->num << endl; //逐个按组进行数据加载
p1 = new student;
while (Name_file >> p1->name >> p1->num) //循环操作输入流
{
cout << p1->name << " " << p1->num << endl;
p1 = new student;
p2->next = p1;
p2 = p1;
}
p2->next = NULL;
}
Name_file.close(); //结束文件操作
}
//链表节点数
int subscriber::NumOfLIst()
{
int n=0;
student *p;
p=head;
while (p!=0 )
{
n++;
p=p->next;
}
return n;
}
//删除全部
void subscriber::deleteall()
{
student *p1,*p2;
p1 = head;
while(p1)
{
p2 = p1;
p1 = p1->next;
delete p2;
}
}
// My_2013_5.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
#include "student.h"
using namespace std;
void main()
{
char ch;
subscriber *mysub = new subscriber;
while(1)
{
cout << "\t \t学生信息系统" << endl;
cout << "\t1. 创建学生信息" << endl;
cout << "\t2. 添加学生信息" << endl;
cout << "\t3. 删除学生信息" << endl;
cout << "\t4. 查找学生信息" << endl; //主菜单
cout << "\t5. 显示学生信息" << endl;
cout << "\t6. 保存学生信息" << endl;
cout << "\t7. 加载学生信息" << endl;
cout << "\t8. 退出管理系统" << endl;
cout<<"输入选项: ";
fflush(stdin);
cin>>ch;
switch(ch)
{
case '1':
mysub->create();
break;
case '2':
mysub->insert();
break;
case '3':
mysub->del();
break;
case '4':
mysub->search(); //选项操作
break;
case '5':
mysub->print();
break;
case '6':
mysub->savef();
break;
case '7':
mysub->loadf();
break;
case '8':
break;
default:
cout<<"\n请输入1-8"<<endl;
break;
}
if(ch == '8')
break;
}
delete mysub;
mysub = NULL;
}
感觉还是有点多,术语会的也不是太多,自己也算是刚刚接触C++,毕竟自己第一次写那么长的代码就传一下啦,其中,功能中的加载功能仍有bug,加载后,虽然可以在窗口中显示,但是无法正常读入地址中。不过还是附上帮助下那些之前基本没用过C++的同学吧,个人之前也只用过C,感觉C++和C感觉上其实也是很像的,可能是老师设定的要求吧。
接下来就是代码的介绍了 由于本人是没接触几天的新手 所以有什么错误和疑问都可以随便发言,只要不乱喷就行介绍也是我要交给老师的报告里截了一段的介绍
结构中在保证了添加多条信息的功能上又增加了判断是否有学号相同的记录的功能,并在发现有记录后给用户两个选择:返回主菜单或者重新输入。通过在int类型下p4 与在利用指针查找文件结尾的同时进行比较,当有p4(所输入的学号)与文件中有相同学号时提示“已有记录”并允许进行下一步操作。若无相同学号的时候则在数据末尾加上新增的学生信息。做到这里,学生信息添加功能就算是解决了。
在做学生信息删除时考虑到为简化程序步骤,所以在程序开头处进行判断数据是否为空,若为空,则输出“列表为空”并返回;若不为空,则else。在else中由于头删除与数据中部删除有很大差异,所以把头删除与中部删除分开进行,又因为中部删除与尾删除差异不是很大(由于尾部数据的下一个的地址中存放的是代表结束的NULL)先对数据中的head进行判断,若是与输入的学生姓名相同,则进行头删除操作,若不相同的话则进行对数据的查找,当发现有与输入的学生姓名相匹配的数据时则进行删除操作并跳出程序,返回程序主界面。当进行了所有数据的查找后没有找到相匹配的数据时会在命令框中输出“查无此人“的字样。由于在查找时用的指针*p1,*p2,在查找过程中是保持一前一后的形式(如p1 = p2->next)所以刚编写的时候有些混乱,曾经试过两个互相交替或间隔一个地进行查找,最后还是使用了p1位于p2的下一个,p2跟进的形式。
按顺序编写的程序,所以在下一个是查找,创新要求中有要求到使用学号查找,所以把按姓名查找与按学号查找两个功能合并到了一起。由于做判断数字与字母方面比较麻烦,所以设计了当输入4进入查找时先对数据进行了判断,是否是空,若为空则输出”列表为空“,否则要求用户输入1/0来选择是按照姓名查找还是按学号查找。由于按姓名查找与按学号查找十分地相似,所以真正写的只是按姓名查找,而按照学号查找只是copy了一下姓名查找的那部分并更改了p3的数据类型和进行比较的内容。总体来说算是最顺利的一部分,可能是与删除部分也比较像的原因,所以是一遍AC的。
下一个是把内存中的数据内容保存到目录下的txt文本中。之前对文件了解不是很深,而且C与C++的外部文件操作差别还是有些大:C中是完全是以数据的形式进行输出和保存,而C++中是以流的形式进行的输出。所以在网上查找了一部分资料,了解到了fstream.h文件的运用。在保存文件中主要是用到了ifstream 与 ofstream 函数。把cout显示在窗口比作文件,ofstream输出流到文件中,格式也仿照std::cout << “….” << std::endl;的形式命名了Name_list.txt为Name_file,通过输出流Name_file << (目标标识符) <<endl;并在最后用Name_file.close();关闭文件,结束写入。虽然一开始看到网上各种讲得都比较长和混乱,同学们也觉得写起来比较困难,但是在理解了流的运用后写出的程序还是比较简短精炼的,也没有出现各种奇怪的bug。
最后到了从保存的txt文本中加载和读取数据功能的程序的编写。本人也认为对很少造作文件是非常难,非常容易出bug的地方。
这个片段已经是更改过很多很多遍后最终的样子,尽管更改过很多遍但是还是会出显一些小bug。在开始的时候想了一个判断是否已有存档的判断,然后再进行正常的加载和显示。程序这部分最后采用的是仿照了创建链表里的片段,先对内存进行了清空(deleteall())再进行数据的导入,并在导入一组数据后输出以显示在窗口中。与保存功能中相似,所用的是Name_file >> “….”; 并在每次保存后为下一个新建地址留出空间为保存下一组数据做准备。
在student.cpp中存在函数NumOfLIst()不是很了解这个函数,在查看了全代码后发现没有用到这个老师给的这个已经定义的函数。