通讯录管理系统

#include<stdio.h>

#include <string.h>

#include <stdlib.h> #define MAX 100

#define TRUE 1

#define FALSE 0

#define Status int

#define fname  “txl.txt” typedef struct            //成员信息

{

 char ID[12];

 char name[12];

 char mphone[12];

 char addr[40];

 char tel[16];

}DataType; typedef struct node          //数据结点

{

 DataType data;

 struct node *next;

}Node; typedef Node *Llist;        //结点指针 char *menu_1[] = {

 “**********菜单*********\n”,

 “1.添加好友信息\n”,

 “2.列表好友信息\n”,

 “3.搜索好友信息\n”,

 “4.删除好友信息\n”

 “0.退出程序\n”,

 “***********************\n”

}; /*********************************************************************************************

函数名称:fgets_wrapper

参数:buffer输入缓冲区指针;buflen最大输入字符数,实际最大输入buflen-1; fp输入流

功能:重新封装fgets函数;

      解决fgets输入时最大长度超过buflen-1个字符后输入缓冲区遗留问题及输入包含’\n’问题

区别: scanf(“%s”,buffer) 输入字符串不能有空格;

      gets(buffer)输入字符串超过buffer长度导致溢出错误;

   fgets(buffer,buflen,fp)最大输入buflen-1个字符,’\n’会被输入;输入被截断后输入缓冲区有遗留

***********************************************************************************************/

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)

{

 if (fgets(buffer, buflen, fp) != 0)

 {

 size_t len = strlen(buffer);

 if (len > 0 && buffer[len-1] == ‘\n’)

 {

  buffer[len-1] = ‘\0’;

 }

 //清空剩余的数据

 else

 {

  int ch;

  while ((ch = getc(fp)) != EOF && ch != ‘\n’);

 }

 return buffer;

 }

 return 0;

} char menu(char *str[], int len)     //菜单函数,让用户选择功能

{

 char sel;

 int i;

 for (i = 0; i<len; i++)

 {

  printf(“%s”,str[i]);

 }

 printf(“请输入您的选择:”);

 scanf(” %c”,&sel);

    getchar();

 return sel;

} Status InitList(Llist *L)       //初始化链表

{

 *L = (Llist)malloc(sizeof(Node));   //分配头结点的内存空间

 if ( NULL == *L)       //分配失败

 {

  return FALSE;

 }

 else                     //分配成功

 {

  (*L)->next = NULL;

  return TRUE;

 }

} Status ListLength(Llist L)      //测量链表长度(返回成员个数)

{

 int i = 0;

 Llist p;

 p = L->next;

    while (NULL != p)

 {

  i++;

  p = p->next;

 }

 return i;

} Status ListEmpty(Llist L)   //判断链表是否为空

{

 if ( 0 == ListLength(L))

 {

  return TRUE;

 }

 else

 {

  return FALSE;

 }

} Status ListInsert(Llist *L, int i, DataType e)  //将e插入链表的第i个位置

{

 int j = 1;

 Llist p,q;

 if (i < 1 || i > ListLength(*L)+1)

 {

  return FALSE;

 }

 p = (*L);

 while (NULL != p && j<i)     //p指向要插入位置的前一个

 {

  p = p->next;

  j++;

 }

 q = (Llist)malloc(sizeof(Node));  //分配一个节点空间,将数据放入节点,再将节点插入链表

 if ( NULL == q)

 {

  printf(“内存分配失败,按回车键退出…\n”);

  getchar();

  exit(0);

 }

 q->data = e;

 q->next = p->next;

 p->next = q;

 return TRUE;

} Status GetElem(Llist L,int i, DataType *e)    //取链表中第i个位置的数据

{

 int j = 1;

 Llist p;

 if (i < 1 || i > ListLength(L))

 {

  return FALSE;

 }

 p = L;

 while (NULL != p && j<i)     //p指向要取数据位置的前一个

 {

  p = p->next;

  j++;

 }

 p = p->next;

 *e = p->data;

 return TRUE;

} Status ListDelete(Llist *L,int i, DataType *e)   //删除链表中第i个位置的数据

{

 int j = 1;

 Llist p,q;

 if ( i < 1 || i > ListLength(*L))

 {

  return FALSE;

 }

 p = (*L);

 while (NULL != p && j < i)     //p指向要删除数据位置的前一个

 {

  p = p->next;

  j++;

 }

 q = p->next;            //先将要删位置的next赋给前一个位置的next

 p->next = q->next;        //将删除位置数据用e返回,释放删除的节点

 *e = q->data;

 free(q);

 return TRUE;

} Status ClearList(Llist *L)    //清空链表

{

 int i = 0;

 Llist p,q;

 if (NULL == (*L)->next)

 {

  return TRUE;

 }

 p = q = (*L)->next;

 do

 {

     p = p->next;

  free(q);

  i++;

  q = p;

 }while(NULL != p);      //删除一个free一个,将头节点的指针置空

 (*L)->next = NULL;

 printf(“cleared item = %d\n”,i);       

 return TRUE;

} Status Input(Llist L, DataType *e)   //输入函数 

{

 Llist p;

 int i = 0;                     

 p = L->next;

 printf(“请输入ID:”);

 fgets_wrapper(e->ID, 12, stdin);

 for (p; NULL != p; p = p->next)        //判断输入ID是否存在,存在则重新输入

 {

  if (!strcmp(p->data.ID, e->ID))

  {

   printf(“此ID已存在,请重新输入ID\n”);

   Input(L,e);

   i++;

  }

 }

 if (1 == i)                    //通过i的值判断程序是否往下执行

 {

  return TRUE;

 }

 else

 {

  printf(“请输入姓名:”);

  fgets_wrapper(e->name, 12, stdin);

  printf(“请输入手机号:”);

  fgets_wrapper(e->mphone, 12, stdin);

  printf(“请输入住址:”);

  fgets_wrapper(e->addr, 40, stdin);

  printf(“请输入电话:”);

  fgets_wrapper(e->tel, 16, stdin);

 }

 printf(“按回车键继续…\n”);

 getchar();

 return TRUE;

} Status Output(DataType e)   //输出函数

{

 printf(“好友ID:%s\n”, e.ID);

 printf(“姓名:%s\n”, e.name);

 printf(“手机号码:%s\n”, e.mphone);

 printf(“家庭住址:%s\n”, e.addr);

 printf(“公司电话:%s\n”, e.tel);

 return TRUE;

} void ListSort(Llist L)      //按姓名冒泡排序

{

 DataType temp;

 Llist p,q;

 for(p = L; NULL != p->next; p = p->next)

 {

 

  for(q = p->next; NULL != q; q = q->next)

  {

   if(strcmp(p->data.name,q->data.name)>0)

   {

    temp = p->data;

    p->data = q->data;

    q->data = temp; 

   }

  }

 }

} Status List(Llist L)    //列表信息   先调用排序,再依次输出

{

 ListSort(L);

 int i;

 Llist p;

 if ( NULL == L->next)

 {

  printf(“当前还没有任何记录\n”);

  printf(“按回车键继续…\n”);

  getchar();

 }

 else

 {

  p = L->next;

  i = 1;

  while( NULL != p)

     {

   printf(“第%d条记录\n”,i);

   Output(p->data);

   printf(“\n”);

   p = p->next;

   i++;

     }

  printf(“按回车键继续…\n”);

  getchar();

 }

 return TRUE;

} Status * LocateList(Llist L, char *str)    //在链表中找名字与实参相同的数据,返回数据的位置

{          //返回的数组中名字不相同的位置的值为-1,

 int i,j;

 Llist p;

 p = L->next;

 j = 0;

 int *a;

 a = (int *)malloc(sizeof(Node));  //为每一个Node大小的成员分配一个指针

 *(a+0) = -1;          //*(a+0)值为-1 不变,不使用

 if (NULL == L->next)

 {

  return a;

 }

 else

 {

  i = 1;

  while(NULL != p)

  {

   if(!strcmp(str, p->data.name))  //相同则将位置i赋到数组的对应位置

   {

    j++;

    *(a+j) = i;

    i++;

    p = p->next;

   }

   else                          //不同则将该位置对应的数组值置-1

   {

    j++;

    *(a+j) = – 1;

    i++;  

    p = p->next;

   }

  }

   return a;

 }

} Status LocateList_num(Llist L, char * str)      //在链表中找ID与实参相同的数据,返回数据的位置

{

 int i;

 Llist p;

 p = L->next;

 if (NULL == L->next)

 {

  return -1;

 }

  i = 1;

  while(NULL != p)

  {

   if (!strcmp(str, p->data.ID))  //找到返回位置i,没找到返回-1

   {

    return i;

   }

   else

   {

    p = p->next;

    i++;

   }

  }

  return -1;

} Status Query(Llist L)      //按姓名搜索信息

{

 char name[12];

 int i;

 DataType e;

 Status flag = 0;           //标志flag判断是否搜索到信息

 int *q;

 printf(“请输入姓名:”);

 fgets_wrapper(name, 12, stdin);

 q = LocateList(L,name);

 for(i = 0; i <= ListLength(L); i++)        //只有一个输出一个    有多个同名则同名信息全部输出

 {

   if (-1 != *(q+i))

   {

       printf(“查询到记录,显示如下:\n”);

    GetElem(L, *(q+i), &e);

    Output(e);

    flag = 1;                   //查询到信息,将flag置1

    printf(“\n”);

   }

 }

 if(0 == flag)

 {

  printf(“查无此人,按回车键继续…”);

  getchar();

 }

 else

 {

  printf(“按回车键继续…\n”);

  getchar();

 }

 return TRUE;

} Status Delete(Llist *L)       //按姓名删除信息,同名则按ID删除

{

 char name[12];

 char ID[12];

 int *str;

 DataType e;

 int i = 0, j = 0;

 printf(“请输入姓名:”);

 fgets_wrapper(name, 12, stdin);

    str = LocateList(*L,name);       //接收按姓名定位的返回值(数组)

 for(i = 1; i <= ListLength(*L); i++)

 {

  if (-1 != *(str+i))

  {

   j++;                       //判断返回数组中值为-1的个数

  }

 }

 if(0 == j)                         //0个则没找到该信息

 {

  printf(“无此人,按回车键继续…\n”);

  getchar();

 }

 else if(j == 1)                    

 {

  for(i = 1;i <= ListLength(*L);i++)

  {

   if (-1 != *(str+i))                   //找到一个,确定其位置,先输出一下再删除

   {

    printf(“有此人,信息如下:\n”);   

    GetElem(*L, *(str+i), &e);

    Output(e);

    ListDelete(L, *(str+i), &e);

    printf(“已删除\n”);

    printf(“按回车键继续\n”);

    getchar();

   }

  }

 }

 else                                

 {

  for(i = 1; i <= ListLength(*L); i++)          //有同名信息,逐个输出

  {

   if (-1 != *(str+i))

   {

    printf(“有此人,信息如下:\n”);

    GetElem(*L, *(str+i), &e);

    Output(e);

   }

  }

  printf(“有多个同名好友,按ID号删除\n”);  

  printf(“请输入ID:”);

  fgets_wrapper(ID, 12, stdin);

  j = LocateList_num(*L, ID);       //获取要删除ID的位置,先输出再删除即可

  if (-1 != j)

  {

   GetElem(*L, j, &e);

   Output(e);

   ListDelete(L, j, &e);

   printf(“已删除\n”);

   printf(“按回车键继续…\n”);

   getchar();

  }

  else

  {

   printf(“查无此人,按回车键继续…\n”);

   getchar();

  }

 }

 return TRUE;

} Status Readfile(Llist *L)        //将文件里的数据读到链表中

{

 FILE *fp;

 DataType e;

 int i,size;

 if((fp = fopen(fname,”a+”)) == NULL)   //打开文件   标准I/O返回值为指针

 {

  perror(“打开文件失败”);

  return FALSE;

 }

    fseek(fp, 0, SEEK_END);           //将文件指针移到文件尾

    size = ftell(fp) / sizeof(DataType);     // 计算文件中数据的个数  ftell计算文件大小,除以数据类型的大小

 rewind(fp);                    //将文件指针移到文件头  与fseek(fp,0,SEEK_SET)功能一致

 for(i = 0; i < size; i++)

 {

  fread(&e, sizeof(DataType), 1, fp);     //将数据一个一个读到e中

  ListInsert(L, ListLength(*L)+1, e);      //将e尾插进链表

 }

 fclose(fp);                         //标准I/O需要关闭文件

 return TRUE;

}

Status Writefile(Llist *L)          //将数据从链表中写入文件

{

 FILE *fp;

 DataType e;

    Llist p = (*L)->next;

 if((fp = fopen(fname,”w+”)) == NULL)     //打开文件

 {

  perror(“打开文件失败”);

  return FALSE;

 }

    while(p != NULL)                     //将数据逐个写入文件

    { 

  e = p->data;            

  fwrite(&e, sizeof(DataType), 1, fp); 

        p = p->next;

    }

    fclose(fp);              //关闭文件

 return TRUE;

}

int main(int argc, char *argv[])

{

 Llist txl;

 Status flag;

 DataType e;

 char sel;

 flag = InitList(&txl);         //判断链表初始化是否成功

 if (!flag)

 {

  printf(“内存分配失败,按回车键退出…\n”);

  getchar();

  exit(0);

 }

 if(FALSE == Readfile(&txl))       //判断读文件是否成功

 {

  printf(“文件打开失败\n”);

  exit(1);

 }

 while (1)

 {

  sel = menu(menu_1, 7);   //调用菜单函数

  switch (sel)

  {

   // 数据尾插进入链表

   case ‘1’:memset(&e,0,sizeof(DataType));Input(txl,&e);ListInsert(&txl,ListLength(txl)+1,e);printf(“添加成功\n”);break;

   case ‘2’:List(txl);break;

   case ‘3’:Query(txl);break;

   case ‘4’:Delete(&txl);break;

   case ‘0’:printf(“谢谢使用本软件,按回车键退出…\n”);Writefile(&txl);getchar();exit(0);break;

   default:printf(“错误输入\n”);break;

  }

 }

 return 0;

}

点赞