交流群:462197261站长百科站长论坛热门标签收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
点击这里给我发消息
  • 当前位置:
  • 基于C语言实现个人通讯录管理系统

    之前利用C语言完成了一个关于个人通讯录管理系统的课题,主要是关于联系人的添加、查找、删除、修改、输出以及文件的写入与读出,还有一个甜点功能—模拟通话,它的实现原理也很容易理解,文章末尾会介绍到。

    主框架:

    1、函数声明

    关于这里的函数声明,主要是为了可以清楚的了解整个系统的功能,这里不做过多介绍。还有结构体链表的创建,贯穿了各个功能代码部分,必不可少。

    2、联系人的添加

    这部分主要涉及联系人的姓名、地址、电话、QQ号和邮箱(当然需要其他功能可自行添加),考虑到数组操作不便前提下,使用链表的尾插法,通过不断开创新的结点,然后不断将新的结点的地址指向尾结点,使尾结点不断后移,而新创的结点时按照添加的先后顺序进行连接(参考下图可快速理解,此图片来源于网络),当然其中某些项的条件限制也是必不可少的。比如:电话、QQ号、邮箱

    int Addpeo()  //添加联系人
    {
     int t,n,a;
     char flag='y';  //仅作为第一次执行条件 
     ptcs p=head,q; 
     while(flag!='n'&&flag!='N')  //判断是否继续添加 
     {
     q=(ptcs)malloc(sizeof(pcs));  //申请内存
     p->next=q;  //赋予下一个节点 
     p=q;    
     q->next=NULL;  //尾结点地址赋空值 ,尾插法 
     printf("\n\t请输入:\n");
     printf("\t\t姓名:");  
     scanf("\t\t%s",q->chat.name);
     printf("\t\t地址:");
     scanf("\t\t%s",q->chat.add);
     printf("\t\t手机号:");
     scanf("\t\t%s",q->chat.tel);
     do
     {
     n=0;  //仅做记录 
     if(strlen(q->chat.tel)!=11)  //计算手机号的长度 ,判断是否输入规范 
     {  
     n=1;
     printf("\t\t您输入的手机号格式不存在,请重新输入:");
     scanf("\t\t%s",q->chat.tel);
     }
     else 
     {
     for(t=0;t<11;t++)
     {
      if(q->chat.tel[t]<'0'||q->chat.tel[t]>'9')
      {
      n=1;
      printf("\t\t您输入的手机号格式不合理,请重新输入:");
      scanf("\t\t%s",q->chat.tel);
      break;
      }
     }
     }
     }while(n);
     //输入QQ号 
     printf("\t\tQQ号:");
     scanf("\t\t%s",q->chat.tecent);
     do
     {
     n=0;
     if(strlen(q->chat.tecent)>10)  //以10位QQ号为准,判断是否符合规范 
     {  
     n=1;
     printf("\t\t您输入的QQ号格式不存在,请重新输入:");
     scanf("\t\t%s",q->chat.tecent);
     }
     else 
     {
     for(t=0;t<10;t++)
     {
      if(q->chat.tecent[t]<'0'||q->chat.tecent[t]>'9')
      {
      n=1;
      printf("\t\t您输入的QQ号格式不合理,请重新输入:");
      scanf("\t\t%s",q->chat.tecent);
      break;
      }
     }
     }
     }while(n);
     //输入邮箱
     printf("\t\tEmail:");  
     scanf("\t\t%s",q->chat.email);
     do
     {
     //判断邮箱 @符号输入规范(这里不限定邮箱号码位数) 
     a=0;
     for(t=0;q->chat.email[t]!='\0';t++)
     {
     if(q->chat.email[t]=='@')
      a++;  //@数为1 
     }
     if(a!=1)  
     {
     printf("\t\t输入的邮箱格式不合理,请重新输入:");
     scanf("\t\t%s",q->chat.email);
     }
     }while(a!=1); //是否输入@ ,为1则终止循环 
     printf("\n\t是否继续添加?(Y/N)");  
     scanf("\t%c",&flag); 
     }
     return 0;
    }

    3、联系人的查询

    这步使用的是遍历查询,共设置了三种方式,在定义链表指针的前提下,通过遍历链表进行信息的对比,从而判断联系人是否存在,如果存在就直接显示给用户,不存在就直接退回功能选项。

    int Query()
    {
     int m,n;  //m记录选项 
     char flag='y';
     ptcs p=head->next;  
     while(flag!='n'&&flag!='N') //是否继续查询 
     {
     printf("\n");
     printf("\t*************查询方式**************\n");
     printf("\t-----------------------------------\n");
     printf("\t   1.按姓名查找   \n");
     printf("\t   2.手机号查找   \n");
     printf("\t   3.按QQ号码查找   \n");
     printf("\t   4.返回     \n");
     printf("\t-----------------------------------\n");
     printf("\n\t请选择查询方式:");
     scanf("\t%d",&m);  
     do
     {
     n=0; 
     if(m!=1&&m!=2&&m!=3&&m!=4)
     { 
     n=1;
     printf("\t您输入的查询方式不存在,请重新输入:");
     scanf("\t%d",&m); 
     }
     }while(n);  //是否输入正确 
     if(!p)  //判断链表是否为空 
     {
     printf("\t该通讯录为空!\n");
     return 0;
     }
     if(m==1)
     {
     char nm[15];  //要查询的联系人
     printf("\t请输入您要查询的联系人姓名:");
     scanf("\t%s",nm);
     //若链表不为空,且联系人不相符,则继续往后遍历 
     while(p!=NULL&&strcmp(p->chat.name,nm)!=0)
     p=p->next;  //遍历链表
     if(!p)
     {
     printf("\t您要查询的联系人不存在!\n");
     return 0;
     }
     printf("\t地址:%s\n",p->chat.add);
     printf("\t手机号:%s\n",p->chat.tel);
     printf("\tQQ号:%s\n",p->chat.tecent);
     printf("\tEmail:%s\n",p->chat.email);
     }
     if(m==2)
     {
     char te[20];  //要查询的手机号码
     printf("\t请输入您要查询的手机号:");
     scanf("\t%s",te);
     while(p!=NULL&&strcmp(p->chat.tel,te)!=0)
     p=p->next;
     if(!p)
     {
     printf("\t您要查询的联系人不存在!\n");
     return 0;
     }
     printf("\t姓名:%s\n",p->chat.name);
     printf("\t地址:%s\n",p->chat.add);
     printf("\tQQ号:%s\n",p->chat.tecent);
     printf("\tEmail:%s\n",p->chat.email);
     }
     if(m==3)
     {
     char qq[15];  //要查询的qq号
     printf("\t请输入您要查询的QQ号:");
     scanf("\t%s",qq);
     while(p!=NULL&&strcmp(p->chat.tecent,qq)!=0)
     p=p->next;
     if(!p)
     {
     printf("\t您要查询的联系人不存在!\n");
     return 0;
     }
     printf("\t姓名:%s\n",p->chat.name);
     printf("\t地址:%s\n",p->chat.add);
     printf("\t手机号:%s\n",p->chat.tecent);
     printf("\tEmail:%s\n",p->chat.email);
     }
     if(m==4)
     return 0;
     printf("\t是否继续查询?(Y/N)");  //Y则继续执行while循环,否则退出 
     scanf("\t%c",&flag);
     }
     return 0;
    }

    4、联系人的删除

    这部分提供按姓名删除,通过遍历链表查询到指定节点,使用指针使该节点的上一个节点直接指向下一个节点,以此来实现对联系人的删除操作。详解图奉上

    int Delete()
    {
     char nm[20];  //要删除的联系人姓名
     char flag='y';
     ptcs p=head->next,bh,pre;  //bh,pre均为过度节点指针 
     if(!p)  //判断链表是否为空 
     {
     printf("\t该通讯录为空!\n");
     return 0;
     }
     while(flag!='n'&&flag!='N')
     {
     p=head->next;
     printf("\t请输入您要删除的联系人姓名:");
     scanf("\t%s",nm);
     while(p!=NULL&&strcmp(p->chat.name,nm)!=0)  //比较输入的联系人是否正确 
     {
     pre=p;
     p=p->next; //往后遍历链表,直至找到联系人,并赋给p 
     }
     if(!p)
     {
     printf("\t该联系人不存在!\n");
     return 0;
     }
     bh=p->next;  //将next值赋给bh,指向要删除的联系人的下一个地址 
     if(p==head->next)  
     head->next=bh;
     else 
     pre->next=bh;  //使当前联系人的上一个地址,直接指向联系人的下一个地址 
     printf("\t该联系人已删除!\n");
     printf("\t是否继续删除?(Y/N)");
     scanf("\t%c",&flag);
     }
     return 0;
    }

    5、联系人信息的修改

    关于联系人的修改,它其实是对链表的某一节点进行修改,通过遍历链表查询到指定节点并直接进行修改,修改过程中依旧沿用部分格式限定条件,若输入某项不符合要求,则一直重复输入,直到该项输入符合要求为止。话不多说,上代码

    //修改姓名
    int changename(ptcs p)
    {
     scanf("\t%s",p->chat.name);
     printf("\t修改成功!\n"); 
     return 0;
     }
    
    //修改地址 
    int changeadd(ptcs p)
    {
     scanf("\t%s",p->chat.add);
     printf("\t修改成功!\n"); 
     return 0;
     } 
     
    //修改手机号内容
    int changetel(ptcs p)
    {
     int n,t;
     scanf("\t%s",p->chat.tel);
     do
     {
     n=0;
     if(strlen(p->chat.tel)!=11)
     {  
     n=1;
     printf("\t您输入的手机号格式不存在,请重新输入:");
     scanf("\t%s",p->chat.tel);
     }
     else 
     {
     for(t=0;t<11;t++)
     {
     if(p->chat.tel[t]<'0'||p->chat.tel[t]>'9')
     {
      n=1;
      printf("\t您输入的手机号格式不合理,请重新输入:");
      scanf("\t%s",p->chat.tel);
      break;
     }
     }
     }
     }
     while(n);
     printf("\t修改成功!\n"); 
     return 0;
    }
    
    //修改QQ号码 
    int changeQQ(ptcs p)
    {
     int n,t;
     scanf("%s",p->chat.tecent);
     do
     {
     n=0;
     if(strlen(p->chat.tecent)!=10)
     {  
     n=1;
     printf("\t您输入的QQ号格式不存在,请重新输入:");
     scanf("\t%s",p->chat.tecent);
     }
     else 
     {
     for(t=0;t<10;t++)
     {
     if(p->chat.tecent[t]<'0'||p->chat.tecent[t]>'9')
     {
      n=1;
      printf("\t您输入的QQ号格式不合理,请重新输入:");
      scanf("\t%s",p->chat.tecent);
      break;
     }
     }
     }
     }
     while(n);
     printf("\t修改成功!\n"); 
     return 0;
    }
    
    //修改电子邮箱 
    int changeEmail(ptcs p)
    {
     int t,a;
     scanf("\t%s",p->chat.email);
     do
     {
     a=0;
     for(t=0;p->chat.email[t]!='\0';t++)
     {
     if(p->chat.email[t]=='@')
     a++;
     }
     if(a!=1)
     {
     printf("\t输入的邮箱格式不合理,请重新输入:");
     scanf("\t%s",p->chat.email);
     }
     }
     while(a);
     printf("\t修改成功!\n"); 
     return 0;
    }

    6、联系人的输出

    关于输出就是按照输入的顺序依次将联系人输出

    //输出通讯录列表 
    int Display()
    {
     ptcs p=head->next;  
     if(!p)  //判断链表是否为空 
     {
     printf("\t该通讯录为空!\n");
     return 0;
     }
     printf("\n\t**********************************通讯录列表*************************************\n\n");
     printf("\t姓名\t地址\t\t\t手机号\t\tQQ号\t\tEmail\n");
     printf("\t---------------------------------------------------------------------------------\n");
     while(p)
     {
     printf("\t%-8s%-24s%-16s%-16s%-20s\n",p->chat.name,p->chat.add,p->chat.tel,p->chat.tecent,p->chat.email);
     p=p->next;  //继续往后遍历输出 
     printf("\t---------------------------------------------------------------------------------\n");
     }
     return 0;
    }

    7、文件的写入与读出

    通过新建一个文件并且指定文件的权限,将数据写入到指定文件中,以此实现对文件的整体写入操作。它的读出操作是通过访问已建立的文件,使用fgets函数获取文件中的信息并保存在指定的字符数组中,之后逐个进行输出。

    //将数据写入文件
    int fwrite()
    {
     ptcs p=head->next;
     FILE* fp;
     char filename[30];
     if(!p)
     {
     printf("\t该通讯录为空!");
     return 0;
     }
     printf("\t请输入所写入的文件名:");
     scanf("\t%s",filename);
     if((fp=fopen(filename,"a+"))==NULL)
     {
     printf("\t无法打开文件!\n");
     system("pause");  //暂停 
     return 0;
     }
     fprintf(fp,"**********************************通讯录列表*************************************\n\n");
     fprintf(fp,"姓名\t地址\t\t\t手机号\t\tQQ号\t\tEmail\n");
     fprintf(fp,"---------------------------------------------------------------------------------\n");
     while(p)
     {
     fprintf(fp,"%-8s%-24s%-16s%-16s%-20s\n",p->chat.name,p->chat.add,p->chat.tel,p->chat.tecent,p->chat.email);
     p=p->next;   
     fprintf(fp,"---------------------------------------------------------------------------------\n");
     }
     fprintf(fp,"\n**********************************共%d个联系人************************************\n",cacu(head->next));
     fclose(fp);   //关闭文件 
     printf("\t写入成功!\n"); 
     return 0;
    }
    
    //读取文件 
    int fread()
    {
     char str[100];
     char filename[30];
     FILE* fp;  //定义文件指针 
     printf("\t请输入要读出的文件名:");
     scanf("\t%s",filename);
     if((fp=fopen(filename,"a+"))==NULL)  
     {
     printf("\t无法打开文件!\n");
     system("pause");
     return 0;
     }
     while((fgets(str,100,fp))!=NULL)  //fgets获取文件中的信息 ,存入str中 
     { 
     printf("\t%s",str);  //输出文件中的信息 
     }
     return 0;
    }

    8、模拟通话

    通过调用time函数来获取随机数(从1970.1.1算起),根据当前系统时间,利用相关函数产生一个随机数的种子,再利用对应函数产生一个随机数,随后判断是否与通讯录中联系人的项数相符,若相符,则直接将该联系人的信息写入指定文件中,若不相符,则在该文件中写入未知联系人。

    //呼叫或被呼叫 
    int call()
    {
     int n;
     ptcs p=head->next;
     //用时间做种,每次产生随机数不一样,随着系统时间的改变而改变
     srand((unsigned) time(NULL));  
     n=rand()%(cacu(p)+5)+1;  //产生一个从1到联系人总数+5之间的一个随机数
     return n;
    }
    
    int save(int n,char *filename)//保存通话记录 
    {
     FILE* fp;
     ptcs p=head->next;
     int i=1;
     if((fp=fopen(filename,"a+"))==NULL)
     {
     printf("\t通话记录将失去!\n");
     system("pause");
     return 0;
     }
     if(n<=cacu(p))
     {
     while(i<n)
     {
     p=p->next;
     i++;
     }
     //输出对应联系人信息 
     fprintf(fp,"%-16s%-16s%-16s%-20s\n",p->chat.name,p->chat.tel,p->chat.tecent,p->chat.email);
     fprintf(fp,"----------------------------------------------------------------------\n");
     }
     else 
     fprintf(fp,"未知号码\n");
     fclose(fp); //关闭文件 
     return 0;
    }

    附上系统功能运行图:

    说明:为什么选择使用链表结构呢?主要是因为在添加联系人之前并不会指定添加的个数,因此它是一个动态添加的过程,链表大小可变,扩展性强,并且针对于联系人的删除操作,使用链表不需要改变内存地址,只需要修改节点指针的指向以及节点的值即可,而数组大小固定,不适合于动态的存储,并且在对数组元素进行操作的过程中,这个元素以后的所有元素的内存地址都要移动,操作起来比较麻烦。

    整体源码可参考:C语言实现个人通讯录管理系统

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持北冥有鱼。


    广而告之:
    热门推荐:
    深入解析Backbone.js框架的依赖库Underscore.js的作用

    backbone必须依赖underscore.js才能够使用,它必须通过underscore中的函数来完成访问页面元素、处理元素的基本操作。 注:backbone可以很好的与其它js库一起工作,所以说它是一个库,而不是框架。 Underscore并没有对原生对象进行扩展,而是调用_()方法进行封装,一旦封装完成···

    javascript事件冒泡和事件捕获详解

    事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。 <div id="outer"> <p id="inner">Click me!</p> </div> 上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处···

    php数组函数序列之each() - 获取数组当前内部指针所指向元素的键名和键值,并将指针移到下一位

    each()定义和用法 each() 函数生成一个由数组当前内部指针所指向的元素的键名和键值组成的数组,并把内部指针向前移动。 返回的数组中包括的四个元素:键名为 0,1,key 和 value。单元 0 和 key 包含有数组单元的键名,1 和 value 包含有数据。 如果内部指针越过了数···

    Angular中$broadcast和$emit的使用方法详解

    要在控制器之间传递变量变化需要使用angular中的$broadcast和$emit方法来传递,同时使用$on来接收事件并作出响应。 broadcast译为广播,即上级传递下级。 示例代码: <script src="../angular.js"></script> <script> angular.module("app", []) .contr···

    浅谈javascript 函数表达式和函数声明的区别

    javascript中声明函数的方法有两种:函数声明式和函数表达式. 区别如下: 1).以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的. 2).以函数声明的方法定义的函数,函数可以在函数声明之前调用,而函数表达式的函数只能在声明之后调用. 3).以函数声明的方法···

    PHP反射类ReflectionClass和ReflectionObject的使用方法

    PHP中的扩展反射类,该扩展用来分析php程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。看一个这样的问题,php类的成员变量没有在类中声明,而是在函数中声明,有什么不同?复制代码 代码如下:class test{    private $name; &n···

    JavaScript学习笔记整理

    如下所示: //实现枚举类型,扑克牌应用 function creatEnum(p){ //构造函数 var Enumeration = function(){throw 'can not Instantiate Enumerations';}; //重写原型并将原型赋值给变量proto var proto = Enumeration.prototype = { constructor:Enumeration, ···

    dedecms织梦会员通过邮箱找回密码方法

    首先打开文件: /member/resetpassword.php 这是织梦会员找回密码的核心文件! 在148行有这么一句: showmsg('对不起,临时密码错误', '-1');   看来问题就在这了! 但是怎么引起的呢,别急继续看代码 ···

    Vue + Webpack + Vue-loader学习教程之相关配置篇

    前言 之前已经介绍过了Vue + Webpack + Vue-loader的相关功能介绍,大家可以点击这篇文章了解详情。下面就来看看相关配置篇,感兴趣的可以参考学习。 使用预处理器 在 Webpack 中,所有的预处理器需要和一个相应的加载器一同使用。vue-loader 允许你用其它的 Webpack 加载器去···

    vue axios数据请求get、post方法及实例详解

    我们常用的有get方法以及post方法,下面简单的介绍一下这两种请求方法 vue中使用axios方法我们先安装axios这个方法 npm install --save axios 安装之后采用按需引入的方法,哪个页面需要请求数据就在哪个页面里引入一下。 import axios from 'axios' 引入之后我们就可以进行数···