//global.cpp
int num=0;
//main.cpp
#include<iostream>
#include"add_list.h"
using namespace std;
int main()
{
linkman man[N];//linkman类型数组man,最多存15个人信息
char na[N]={0};//存储每个人姓名第一个字母,这种赋值属于字符数组的赋值,区别去字符串的初始化
int sign[N]={0};//存储联系人编号
in_data(man,na);//读取数据,并获得联系人数目num
count i;
for(i=0;i<num;i++)//给每个联系人一个编号
sign[i]=i;
in_turn(na,sign);//对联系人按姓名从小到大排序
show_data(man,sign);//显示排序后的联系人
show_function(man,na,sign);//功能界面
}
//add_list.h
extern int num;
struct linkman
{
char name[10];
char tel_num[12];//以11位手机号为例说明
char kind;//联系人分类变量
char e_mail[30];//邮箱限制在30个字节
};
void in_data(linkman *p,char *q);
#define N 40
typedef int count;
void show_data(linkman *p,int *q);//显示联系人函数
void show_menu();//功能显示菜单
void show_function(linkman *p,char *q,int *r);//功能实现函数
void add_man(linkman *p,char *q,int *r);//添加联系人函数
void out_data(linkman *p,char *q,int *r);//程序退出时将数据保存入文件
void in_turn(char *p,int *q);//将姓名按字母排序,q数组则存放排序后的联系人编号
int com_name(linkman *p,char *q);//比较输入姓名与已存姓名是否有相同的
void edit_man(linkman *p);//修改联系人信息
void del_man(linkman *p,char *q,int *r);//删除联系人
void call(linkman *p);
//add_list.cpp
#include<iostream>
#include<fstream>
#include"add_list.h"
using namespace std;
void in_data(linkman *p,char *q)
{
ifstream infile;
infile.open("linkman.txt",ios::in);//只读方式打开,文件必须存在
if(!infile.is_open())
{
cout<<"open error";
exit(1);
}
count i=0;
/***********************************************/
char ch;//姓名前的第一个字母
//***********规定:存入姓名的时候必须先存首字母,方便后续按姓名排序
//***********这里要求先存的首字母应该是另外单独放个数组,只作为排序参考而不显示,文件中要存放
if(!infile.get(ch))//读取EOF,函数返回值为0,执行if,退出程序
{
cout<<"文件为空!";
//exit(1);//文件为空,不退出,回到功能界面
}
else
{
infile.seekg(0,ios::beg);//不是空文件,则将指针移动到文件头,开始读取
while(!infile.eof())//在指向EOF时,还会执行一次,所以,最后一个联系人是空的,什么内容也没有,这个问题暂时先不管
{
infile>>q[i]>>p[i].name>>p[i].tel_num>>p[i].kind>>p[i].e_mail;//先将姓名第一个字符存入na数组
i++;
}
num=i;//确定实际联系人数量,不用减一,因为这里读取字符串的情况不会多执行一次
//show_data(p,q,r);//显示联系人数据//此时联系人还未进行编号,不能显示
}
infile.close();
cout<<"当前文件中有"<<num<<"个联系人"<<endl;
cout<<"数据读取完成"<<endl;
}
void show_data(linkman *p,int *q)//p指向联系人数组,q指向编号数组sign
{
count i;
cout<<num<<endl;
for(i=0;i<num;i++)
{
cout<<"第"<<i<<"个联系人"<<endl;
cout<<p[q[i]].name<<‘\t‘<<p[q[i]].tel_num<<‘\t‘<<p[q[i]].kind<<‘\t‘<<p[q[i]].e_mail<<‘\n‘;
}
cout<<"联系人数据显示完成!"<<endl;
}
void show_menu()
{
cout<<‘\t‘<<"手机通讯录系统"<<‘\t‘<<endl;
cout<<"1.添加联系人"<<‘\t‘<<"2.查看联系人"<<‘\n‘;
cout<<"3.拨打电话"<<‘\t‘<<"4.编辑联系人"<<‘\n‘;
cout<<"5.删除联系人"<<‘\t‘<<"6.退出"<<‘\n‘;
}
void show_function(linkman *p,char *q,int *r)
{
char i;
//in_data(p,q);//读取文件数据放到主函数显示功能界面前
while(1)
{
show_menu();//显示功能菜单
cin>>i;
switch(i)
{
case ‘1‘:add_man(p,q,r);break;//p这里多次传递地址,都是结构体数组首地址
case ‘2‘:show_data(p,r);break;//显示联系人数据
case ‘3‘:call(p);break;//拨打电话
case ‘4‘:edit_man(p);break;//修改联系人数据,
case ‘5‘:del_man(p,q,r);break;//删除联系人
case ‘6‘:out_data(p,q,r);break;//退出前保存数据到文件
}
if(i==‘6‘)
break;//如果选择的是退出功能,则在保存数据后退出,否则循环继续
}
}
void add_man(linkman *p,char *q,int *r)
{
char ch[10];//存储新输入的姓名
int n;
cout<<num<<endl;
cout<<"欢迎来到添加联系人界面:"<<endl;
cout<<"姓名:";
cin>>ch;//输入需要添加的姓名
n=com_name(p,ch);//判断姓名是否已经存在
if(n>=0&&n<num)//姓名存在
{
cout<<endl<<"此姓名已经存在"<<endl;
return;//姓名存在,直接返回
}
else if(n==-1)//姓名不存在则执行以下的添加信息操作
{
strcpy(p[num].name,ch);//输入名字
cout<<"姓名首字母:";
cin>>q[num];//输入姓名首字母
r[num]=num;//添加联系人的编号
//漏掉了这一句,由于之前初始化的时候,sign数组初值全部为零,也就是代表文本中第一个联系人,刘中华
//在没有给联系人标号时,排序自然跟他没关系,输出的时候也输出不到他,按我的程序输出的时候,人数是对的
//但是,只是多输出了第一个人而已
cout<<endl;
cout<<"手机号:";
cin>>p[num].tel_num;
cout<<endl;
cout<<"类别:";
cin>>p[num].kind;
cout<<endl;
cout<<"电子邮箱:";
cin>>p[num].e_mail;
cout<<endl<<"新增联系人成功";
num+=1;
in_turn(q,r);//添加联系人后排序,再显示
show_data(p,r);
cout<<"添加后的联系人数目"<<num<<endl;
return;
}
}
void out_data(linkman *p,char *q,int *r)//q指向na字符数组,r指向sign整型数组
{
ofstream outfile;//定义文件流对象
outfile.open("linkman1.txt",ios::out);//以输出方式打开文件,只写操作,新建文件或清空文件内容(文件存在)
count i;
for(i=0;i<num;i++)
{
outfile<<q[i]<<‘\t‘<<p[r[i]].name<<‘\t‘<<p[r[i]].tel_num<<‘\t‘<<p[r[i]].kind<<‘\t‘<<p[r[i]].e_mail;
if(i!=num-1)
outfile<<‘\n‘;//最后一行不输出回车
}
cout<<"数据保存完成"<<endl;
outfile.close();
}
/*********************************************************************************
/* 关于排序后数据的变化说明:排序后,变化的只是na数组,和sign数组中的内容,联系人数组还是
/*原来的顺序,只是在显示的时候按照sign所存的编号顺序即可,文本中存的是什么顺序,内存中man
/*数组的存放也是那个顺序,从i到num
**********************************************************************************/
void in_turn(char *p,int *q)//p对应na字符数组,q对应sign整型数组,按由小到大排序
{
count i,j,k;
char ch;int mid; //中转变量
for(i=0;i<num-1;i++)//趟数n-1
{
k=0;
for(j=num-1;j>0;j--,k++)//每趟比较次数
{
if(p[k]>p[k+1])
{
ch=p[k];
p[k]=p[k+1];
p[k+1]=ch;//姓名首字母交换完成
mid=q[k];
q[k]=q[k+1];
q[k+1]=mid;//联系人编号交换完成
}
}
}
}
int com_name(linkman *p,char *q)//p指向man数组,q指向输入的姓名数组
{
int n=-1;
count i;
for(i=0;i<num;i++)
{
n=strcmp(p[i].name,q);//字符串比较函数,可以按排序后的联系人顺序比较也可以直接比较,记住相同的联系人编号即可
if(n==0)
{
cout<<"此姓名已经存在"<<endl;//姓名存在,返回联系人的编号i,这个不影响数据的编辑修改,
//只是显示的时候按照排序后的顺序显示即可
return i;//姓名已经存在返回i到num的一个整数
}
}
if(n!=0)
{
cout<<"此姓名不存在"<<endl;
return -1;//这里模仿文件指针位置,姓名不存在返回-1,
}
}
void edit_man(linkman *p)
{
cout<<"输入待编辑联系人姓名:";
char ch[10];
cin>>ch;
int n;
n=com_name(p,ch);//判断姓名是否存在,n则代表了联系人的标号,是第几个联系人
if(n>=0&&n<num)//姓名存在
{
cout<<endl<<"此姓名存在"<<endl;
cout<<"输入电话号码:";
cin>>p[n].tel_num;
cout<<endl<<"输入联系人类别:";
cin>>p[n].kind;
cout<<endl<<"输入电子邮箱:";
cin>>p[n].e_mail;
cout<<endl<<"信息修改完成"<<endl;
}
else
return;//姓名不存在直接返回
}
/******************************************************************
/*删除应该有两种思路,一种,从要删除的文职开始,后面的依次往前覆盖,另一种
/*用先输出,再读入的方式,这里用第一种的话,na数组的内容与man数组不对应,需要寻找,
/*较麻烦,用第二种
********************************************************************/
void del_man(linkman *p,char *q,int *r)//q指向sign整型数组
{
count i;
int n,k;
ofstream outfile;
outfile.open("linkman.txt",ios::out);
if(!outfile.is_open())
{
cout<<"打开失败"<<endl;
return;
}
cout<<"输入要删除的联系人姓名:";
char ch[10];//存储输入的姓名
cin>>ch;
n=com_name(p,ch);//n代表了联系人的编号
cout<<"要删除的联系人编号"<<n<<endl;
if(n>=0&&n<num)//姓名存在
{
k=0;
for(i=0;i<num;i++)
{
cout<<"r[i]值"<<r[i]<<"n值"<<n<<endl;
if(n!=r[i])//需要删除的数据不输出
{
outfile<<q[i]<<‘\t‘<<p[r[i]].name<<‘\t‘<<p[r[i]].tel_num<<‘\t‘<<p[r[i]].kind<<‘\t‘<<p[r[i]].e_mail;
k++;
}
cout<<"k值"<<k<<endl;
if(n!=r[i]&&k!=num-1)//k在这里代表的是行数,总共有num-1行,而不是最后一行的标号num-2
{
cout<<i<<" "<<k<<"输出回车"<<endl;
outfile<<‘\n‘;
}
}
num-=1;//删除数据后的联系人数目
cout<<"删除后数据输出完成"<<endl;//这个时候再读一次数据,那么就没有之前要删除的数据了
outfile.close();//输出完毕,关闭文件
in_data(p,q);//重新读取应该要将原来数据全部清空,我这里没有清空数据,用人数num控制显示,其实后面还是有数据的
cout<<"删除后的数据读取完成"<<endl;//此时就应该没有要删除的数据了
}
else
return;//姓名不存在直接返回
}
void call(linkman *p)
{
cout<<"请输入对方姓名:";
char ch[10];
cin>>ch;
int n;//存放所拨打联系人的编号
n=com_name(p,ch);
if(n>=0&&n<num)//姓名存在
{
cout<<"正在呼叫……"<<endl;
cout<<" "<<ch<<" "<<endl;
cout<<p[n].tel_num<<endl;
}
}
手机通讯录(结构体实现,链表还不会!)