//chuangyong 头文件模块 const int MaxLen=200; //最多可存放200个联系人信息 char fName[20]="";//磁盘文件:通信录文件名 int Len; //全局变量,通信录中当前联系人总数 //1. 通讯录数据结构设计 typedef struct Telephone { char name[20]; //姓名 int group;//群组:1.朋友 2.同事 3.家人 4.其他 char home[15];//住宅电话 char mobile[15];//手机 char email[20];//Email char add[20];//地址 char memo[20];//备注 }Tel; //指针数组结构,排序时用 typedef struct index { int len; //数组长度 Tel *tel[MaxLen]; //指针数组, }Index; //显示模块 void List(Tel tel[],Index lianxren); //按lianxren中指针数组的排序方式显示所有联系人。 void dayingbiaotou(void); //打印表头 void dayingbiaowei(void);//打印表尾 void PrintOne(Tel r,int i); //仅打印一个联系人r的信息,序号为i void Print(Tel r); //打印表头及一个联系人的信息 void huanyin();//欢迎界面 int Menu(void); //主菜单,显示第一级菜单:查看通信录(1)、更新通信录(2)、备份通信录(3)、退出(0)。 int Menu2(void); //更新通信录子菜单,显示:新增联系人(21)、编辑联系人(22)、删除联系人(23)、返回主菜单(20)。 //文件处理模块 void New(Tel tel[],Index *lianxren); //新增联系人。加到数组中第一个空着的位置。之后需要重新排序 void Edit(Tel tel[],Index *lianxren); //编辑联系人。需要重新排序 void Delete(Tel tel[],Index *lianxren); // 删除联系人。逻辑删除,仅将姓名赋空串。删除后需要重新排序 void Input(Tel *r,Tel tel[],int menu); //输入一个联系人的信息,由menu识别:是新增(11)还是修改(13) int chongcha(char *name,Tel tel[],char *orignal);//查重。在新增联或编辑系人前,检查是否有重名的情况。 int Select(); //选择联系人序号,避免出错 int Load(Tel tel[],Index *lianxren); //读取。将通信录文件fName读入内存。排序 int Save(Tel tel[]); //保存。将通信录以fName(全局变量)为名保存到磁盘。此时做物理删除:姓名为空串的联系人表示已删除,不存入通信录文件。 int Copy(void); //备份通信录。复制通信录文件。 void pingypaix(Tel tel[],Index *lianxren); //按音序排序。 void xuanzpaixi(Index *p); //对指针数组选择排序 //主文件模块 #include<> #include<> #include<> #include<> #include "" #include "" #include "" int main() { huanyin(); int select=0; Tel tel[MaxLen]; //最多存放200个联系人 Index lianxren;//按音序排序的指针数组 Load(tel,&lianxren); //从通信录文件读取信息 //循环显示菜单,供用户选择 do{ if(select<10 || select==20)//选的是主菜单项<10,或由子菜单返回20。接着显示主菜单 select=Menu(); else if(select>20 && select<30)//选的是子菜单2的项,继续显示子菜单2 select=Menu2(); switch(select) { case 1://按音序查看通信录 List(tel,lianxren); printf("\n\n\t按任意键继续... ..."); getch(); //等待用户看清屏幕, break; case 21: //新增联系人 New(tel,&lianxren); break; case 22: //编辑联系人 Edit(tel,&lianxren); break; case 23: //删除联系人 Delete(tel,&lianxren); break; case 20: //返回主菜单 break; case 3: //备份通信录 system("cls"); //没有子菜单,先清除上一级菜单, Save(tel); //用户可能更新过,先保存当前tel到通信录文件 Copy(); break; case 0: //退出程序 break; } }while(select!=0); Save(tel); //退出系统前,将内存数据存入通信录文件 return 0; } // 菜单模块。与程序其他模块独立。通过返回的菜单代码与操作对应 // 欢迎部分 void huanyin() { char A[100]={"欢迎使用本通讯录 本程序由 飞尧 编写 o(∩_∩)o...!回车进入!"}; int i,j,k; for(i=0;i<6;i++) { printf("\n"); } puts(" ******************************************************\n"); printf("\t\t"); for(i=0;A[i]!='\0';i++) { if(i==49)printf("\n\n\t\t\t"); printf("%c",A[i]); for(j=0;j<10000;j++) for(k=0;k<2000;k++) ; } puts("\n\n\n\t\t\t 07计科C班 王崇尧"); puts("\n ******************************************************\a"); getch(); } //主菜单,显示第一级菜单:查看通信录(1)、更新通信录(2)、备份通信录(3)、退出(0)。 int Menu(void) { int i; char menu; do{ system("cls"); //清屏, for(i=0;i<6;i++) { printf("\n"); } puts("\n **********主菜单*********"); puts(" * *"); puts(" * 1. 查看通信录 *"); puts(" * 2. 更新通信录 *"); puts(" * 3. 备份通信录 *"); puts(" * 0. 退出程序 *"); puts(" * *"); puts(" *************************\n"); printf("\t 请选择:"); menu = getche(); switch( menu ) { case '0': puts("\n\n\t退出程序!"); menu=menu-'0'; break; // 跳出循环 case '1': case '3': menu=menu-'0'; break; case '2': menu=Menu2(); break; default: puts("\n\n\t选择错误!"); menu='9'; } }while(menu=='9');//要返回菜单代码,'0'、'1'、20,21,22,23、'3'都是有效值 return menu; } //更新通信录子菜单,显示:新增联系人(21)、编辑联系人(22)、删除联系人(23)、返回(20)。 int Menu2() { char menu; int i; do{ system("cls"); //清屏, for(i=0;i<6;i++) { printf("\n"); } puts("\n ********更新通信录*******"); puts(" * *"); puts(" * 1. 新增联系人 *"); puts(" * 2. 编辑联系人 *"); puts(" * 3. 删除联系人 *"); puts(" * 0. 返回主菜单 *"); puts(" * *"); puts(" *************************\n"); printf("\t 请选择:"); menu = getche(); //输入一个字符,不回显,不需要敲入回车, switch( menu ) { case '0': puts("\n\n\t返回主菜单!"); break;// 跳出循环 case '1': case '2': case '3': break; default: puts("\n\n\t选择错误!"); menu='9'; } }while(menu=='9'); //要返回菜单代码,'0'、'1'、'2'、'3'都是有效值 return 20+menu-'0'; } //浏览部分 void List(Tel tel[],Index lianxren) //按lianxren的排序方式显示所有结点。 { int i; //i:数组下标 if(Len==0) { printf("\n\t没有联系人"); return ; } dayingbiaotou(); for(i=0; i=MaxLen) { printf("\n\n\t通信录已满!"); return ; } //找到tel中第一个空的位置t while( strcmp(tel[t].name,"")!=0 ) t++; Input(&tel[t],tel,21);//新增联系人(21),输入联系人信息 Len++; //联系人增1 pingypaix(tel,lianxren);//重新排序 } void Edit(Tel tel[],Index *lianxren) //编辑联系人。需要重新排序 { int i; List(tel,*lianxren);//按音序排序的顺序修改 if(Len==0) return ; i=Select(); Print( *(lianxren->tel[i]) ); //显示用户选中的联系人i Input( lianxren->tel[i] ,tel,23); //编辑(23)时输入联系人信息 pingypaix(tel,lianxren); //重新排序 } void Delete(Tel tel[],Index *lianxren) // 删除联系人。逻辑删除,仅将姓名赋空串。删除后需要重新排序 { int i; char select; //用户选择:是否继续输入除姓名以外的信息 List(tel,*lianxren);//按音序排序的顺序删除 if(Len==0) return ; i=Select(); Print( *(lianxren->tel[i]) );//显示用户选中的联系人i printf("\n\t确定要删除此人?(y/n)"); select=getche(); if(select=='Y' || select=='y') { strcpy(lianxren->tel[i]->name,"");//删除联系人信息(逻辑删除):将姓名赋空串,表示无人 Len--; //联系人减1 pingypaix(tel,lianxren);//重新排序 } } void Input(Tel *r,Tel tel[],int menu) //输入一个联系人的信息,由们menu识别:是新增(11)还是修改(13) { int select; char name[20],orignal[20]; if(menu==21)//新增,原来没名字 strcpy(orignal,""); else //编辑,原来有名字 strcpy(orignal,r->name ); printf("\n\n\t请输入联系人姓名:"); do{ scanf("%s", name); }while(chongcha(name,tel,orignal)); //重名检查。修改时,可以与原来的姓名相同 strcpy(r->name,name); printf("\t是否继续输入(y/n)?"); select=getche(); if(select=='y' || select=='Y') { //群组 printf("\n\t群组(1.朋友 2.同事 3.家人 4.其他),请输入序号:"); scanf("%d",& (r->group)); while( r->group<1 ||r->group>4) { printf("\n\t输入错误!请重新输入群组序号(1.朋友 2.同事 3.家人 4.其他):"); scanf("%d",& (r->group)); } printf("\t住宅电话:"); scanf("%s",r->home ); printf("\t手机:"); scanf("%s",r->mobile ); printf("\tEmail:"); scanf("%s",r->email ); printf("\t地址:"); scanf("%s",r->add); printf("\t备注:"); scanf("%s",r->memo ); } else if(menu==21) //新增联系人(menu=21)时,用户未输入,设置缺省值 { r->group=4; //缺省群组:其他 strcpy(r->home , ""); strcpy(r->mobile , ""); strcpy(r->email , ""); strcpy(r->add , ""); strcpy(r->memo , ""); } } int chongcha(char *name,Tel tel[],char *original)//查重。在新增或编辑联系人前,检查是否有重名的情况。 { int i,j; //i:数组下标 j: 除姓名为空串以外的实际人数 int dup=0; //重名标志:1 重名,0没有重名 if(strcmp(name,original)!=0)//name不是原来的名字, for(i=0,j=0; jLen) { printf("\n\t输入错误!请按序号选择联系人:"); if(c==0) fflush(stdin); //输入不成功,清空与输入流stdin有关的输入缓冲区的内容, c=scanf("%d",&i); } return i-1; } //排序部分 void pingypaix(Tel tel[],Index *lianxren) //按音序排序。 { int i,j; //i:数组下标 j: 除姓名为空串以外的实际人数 if( Len==0 ) return ; //初始化排序指针数组 lianxren->len=0; for(i=0,j=0; jtel[j]=&tel[i]; j++; i++; lianxren->len++; } //选择排序 xuanzpaixi( lianxren ); } void xuanzpaixi(Index *p) //对指针数组选择排序 { int i,j,n=p->len; int min; Tel *temp; if( n==0 ) return ;//没有联系人,不需要排序 //选择排序 for(i=0; itel[j]->name , p->tel[min]->name )<0) min=j; } //交换 最小元素min,当前无序序列第一个元素i if(min!=i) { temp=p->tel[i]; p->tel[i]=p->tel[min]; p->tel[min]=temp; } }//end of for i }