C进阶:通讯录(动态版本 + 文件操作)附源码(上)

简介: C进阶:通讯录(动态版本 + 文件操作)附源码

一.通讯录思路

1.创建结构体类型,其中包含通讯录中联系人的信息;

  该信息可以包括:姓名,年龄,性别,电话,地址等;

2.创建一个结构体存储通讯录;

3.写一个简易的菜单来表明通讯录的功能;

  包括但不限于: 添加add,删除del,查找search,修改modigy,排序sort,打印通讯录print等;

4.通过函数来实现这些功能;

二.三个文件的建立

对于较复杂的一些代码,我们最好分文件写,这样可以使代码更清晰,可读性也更高;

在写通讯录的代码之前,我们需要先建立三个文件,分别是:

1.头文件 :   contact.h (用于函数的声明等)

2.源文件 :contact.c (用于函数的实现)

3.源文件 :   test.c (用于主函数的书写)


三.所需要使用的变量的创建(包含在头文件contact.h中)

为了后面方便改动,我们定义宏来确定一些大小;

代码:

1. //所需头文件的包含
2. #include <stdio.h>
3. #include <string.h>
4. #include <stdlib.h>
5. 
6. //一些定义的表示大小的宏
7. #define MAX_NAME 20
8. #define MAX_SEX  10
9. #define MAX_TEL  20
10. #define MAX_ADDR 30
11. 
12. #define DEFAULT_SZ 3  //默认通讯录容量
13. #define INC_SZ     2  //每次增容的大小
14. 
15. 
16. //定义每个联系人的信息
17. typedef struct peoinfo
18. {
19.   char name[MAX_NAME]; //姓名
20.   int age;  //年龄
21.   char sex[MAX_SEX];  //性别
22.   char tel[MAX_TEL];  //电话
23.   char addr[MAX_ADDR];  //地址
24. }peoinfo;
25. 
26. 
27. //存储每个联系人
28. typedef struct contact
29. {
30.   peoinfo* data;  //定义指针变量,方便后续动态内存开辟,进行通讯录扩容操作
31.   int sz;     //通过下标访问数组
32.   int capacity;  // 记录通讯录容量
33. }contact;

四.主函数的书写 (包含在 test.c 中)

1.首先要写个简易的菜单来展示通讯录功能;

2.然后利用 do ..... while结构实现通讯录的操作;

3.还要创建一个通讯录变量 contact con ;

4. 写一个函数 ( Innitcontact (函数的实现在 contact.c 中)(包含文件的读取)) 初始化通讯录变量 con (在此时进行动态内存开辟,使用 calloc/malloc 函数)

主函数代码:

1. //头文件的包含
2. #include "contact.h"
3. 
4. 
5. //菜单
6. void menu()
7. {
8.  printf("*****************************************************************\n");
9.  printf("**********          1.add                 2.del        **********\n");
10.   printf("**********          3.search              4.modify     **********\n");
11.   printf("**********          5.see                 6.sort       **********\n");
12.   printf("**********                    0.exit                   **********\n");
13.   printf("*****************************************************************\n");
14. 
15. 
16. }
17. //利用枚举变量使代码表达的意思更清晰
18. enum option
19. {
20.   EXIT, //默认从0开始
21.   ADD,  //1
22.   DEL,  //2
23.   SEARCH,  //3
24.   MODIFY,  //4
25.   SEE,  //5
26.   SORT  //6
27. };
28. 
29. int main()
30. {
31.   int input = 0;
32.   contact con;   //通讯录变量创建
33.   //初始化联系人数组,包含从文件中读取联系人信息
34.   Innitcontact(&con);
35.   do
36.   {
37.     menu();
38.     printf("请选择:>");
39.     scanf("%d", &input);
40.     switch (input)
41.     {
42.     case ADD:
43.       addcontact(&con);  //添加
44.       break;
45.     case DEL:
46.       delcontact(&con);  //删除
47.       break;
48.     case SEARCH:
49.       searchcontact(&con);  //查找
50.       break;
51.     case MODIFY:
52.       modifycontact(&con);  //修改
53.       break;
54.     case SEE:
55.       printcontact(&con);  //打印通讯录
56.       break;
57.     case SORT:
58.       sortcontact(&con);  //排序
59.       break;
60.     case EXIT:
61.       savecontact(&con);  //保存通讯录,将联系人信息写入文件中
62.       destroycontact(&con);  //销毁通讯录
63.       printf("退出通讯录\n");
64.       break;
65.     default:
66.       printf("选择错误,重新选择\n");
67.       break;
68.     }
69.   } while (input);
70.   return 0;
71. }

Innitcontact 函数:

1. //将文件中的联系人信息读入
2. void download(contact* pc)
3. {
4.  FILE* pf = fopen("D:\\C\\c-code\\CONTACT\\CONTACT\\contact.txt", "r");  //以只读的方式打开文件
5.  if (pf == NULL)  //判断文件是否打开成功
6.  {
7.    perror("fopen");
8.    return;
9.  }
10. 
11.   peoinfo tmp = { 0 };
12.   while (fread(&tmp, sizeof(peoinfo), 1, pf))
13.   {
14.     inccapacity(pc);  //增容函数
15.     pc->data[pc->sz] = tmp;  //将联系人信息写入 data 中
16.     pc->sz++;  //记录写入联系人的数量
17.   }
18.   fclose(pf);  //关闭文件
19.   pf = NULL;
20. }
21. 
22. //动态初始化联系人
23. void Innitcontact(contact* pc)
24. {
25.   pc->data = (peoinfo*)calloc(DEFAULT_SZ, sizeof(peoinfo));  //动态内存开辟,实现通讯录的动态
26.   if (pc->data == NULL)  //判断内存开辟是否成功
27.   {
28.     perror("Innitcontact");
29.     return;
30.   }
31.   pc->sz = 0;  //初始化通讯录实时容量,也可用作下标
32.   pc->capacity = DEFAULT_SZ;  //初始化容量
33.   download(pc);  //加载文件中联系人的信息
34. }

五.通讯录功能的实现(在 contact.c 中)

1.添加联系人 addcontact

在添加联系人之前,我们先要判断通讯录是否已满,若已满则调用增容函数,之后在进行联系人信息的添加;

增容函数 inccapacity  代码:

1. //是否增容
2. void inccapacity(contact* pc)
3. {
4.  if (pc->sz == pc->capacity)
5.  {
6.    printf("通讯录已满,开始增容\n");
7.      peoinfo* ptr = (peoinfo*)realloc(pc->data,(DEFAULT_SZ+INC_SZ)*sizeof(peoinfo));  //利用 realloc 进行内存的再次动态开辟,实现通讯录的增容
8. 
9.    if(ptr == NULL)  //判断内存是否开辟成功
10.     {
11.       printf("增容失败\n");
12.       perror("inccapacity");
13.       return;
14.     }
15.     else
16.     {
17.       pc->data = ptr;   //将扩容后的通讯录首地址赋给原来的通讯录
18.       pc->capacity += INC_SZ;  //容量增加
19.       printf("增容成功\n");
20.     }
21.   }
22. }

添加联系人函数 addcontact 代码:

1. //添加联系人
2. void addcontact(contact* pc)
3. {
4.  int input = 0;
5.  do
6.  {
7. 
8.    printf("按1继续,按0返回:>");  //利用 do ... while 结构实现联系人的多次添加
9.    scanf("%d", &input);
10. 
11.     switch (input)
12.     {
13.     case 1:
14.       inccapacity(pc);  //判断容量是否已满,若已满,则进行增容
15.       printf("开始添加\n");  //联系人各种信息的录入
16.       printf("请输入姓名:>");
17.       scanf("%s", pc->data[pc->sz].name);
18.       printf("请输入年龄:>");
19.       scanf("%d", &(pc->data[pc->sz].age));
20.       printf("请输入性别:>");
21.       scanf("%s", pc->data[pc->sz].sex);
22.       printf("请输入电话:>");
23.       scanf("%s", pc->data[pc->sz].tel);
24.       printf("请输入地址:>");
25.       scanf("%s", pc->data[pc->sz].addr);
26.       pc->sz++;  //添加成功后,通讯录实时容量增加1
27.       printf("添加成功\n");
28.       break;
29.     case 0:
30.       printf("返回\n");
31.       return;
32.       break;
33.     default:
34.       printf("选择错误,重新选择\n");
35.       break;
36.     }
37.   } while (input);
38. }

2.删除联系人  delcontact

1.在删除前我们需要先判断通讯录中是否有数据,若没有则无法删除;

2.输入要删除的对象,所以我们需要写一个姓名的查找函数,返回其所在的下标,供后续删除使用;

3.删除联系人,即从返回的下标开始,使其之后的每一个元素向前移动一个位置;

查找函数  find  代码:

1. //查找联系人
2. int find(char tmp[], contact* pc)
3. {
4.  int i = 0;
5.  for (i = 0; i < pc->sz; i++)
6.  {
7.    if (strcmp(tmp, pc->data[i].name) == 0)  //因为姓名是字符串,所以利用字符串比较函数
8.    {
9.      return i;  //查找成功返回其下标
10.     }
11.   }
12.   return -1;  //失败则返回-1
13. }

delcontact  代码:

1. //删除联系人
2. void delcontact(contact* pc)
3. {
4.  char tmp[MAX_NAME];  
5.  int pos = 0, i = 0;
6.  if (pc->sz == 0)  //判断通讯录有无数据
7.  {
8.    printf("通讯录为空,无法删除\n");
9.    return;
10.   }
11.   while (1)
12.   {
13.   again:
14.     printf("请输入要删除的人的姓名:>");
15.     scanf("%s", tmp);
16.     pos = find(tmp, pc);  //查找要删除人的下标
17.     if (pos == -1)
18.     {
19.       printf("要删除的人不存在,重新输入\n");
20.       goto again;
21.     }
22.     else
23.       break;
24.   }
25.   printf("开始删除\n");
26.   for (i = pos; i < pc->sz - 1; i++)  //从返回的下标 pos 开始 ,之后的每个元素向前移动一位
27.   {
28.     pc->data[i] = pc->data[i + 1];
29.   }
30.   pc->sz--;  //删除成功即通讯录的实时容量减去1
31.   printf("删除成功\n");
32. }

3.查询联系人 searchcontact

1.在查询前需要判断通讯录中是否有数据,若无数据,则无法查询;

2.可以调用前面的查找函数;

3.查询到后打印该联系人信息,并提示查询成功;

searchcontact 代码:

1. //查找联系人
2. void searchcontact(contact* pc)
3. {
4.  char name[MAX_NAME];
5.  int pos = 0;
6.  if (pc->sz == 0)    //判断通讯录中是否有数据
7.  {
8.    printf("通讯录为空,无法查询\n");
9.    return;
10.   }
11.   while (1)
12.   {
13.     again:
14.     printf("请输入要查找人的姓名:>");
15.     scanf("%s", name);
16.     pos = find(name, pc);  //调用 fing 函数,并返回其下标
17.     if (pos == -1)
18.     {
19.       printf("查无此人,重新查询\n");  //查询失败则继续
20.       goto again;
21.     }
22.     else
23.       break;
24.   }
25.   printf("查询成功\n");
26.   printf("%-20s\t%-5s\t%-10s\t%-20s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");   //打印该联系人的信息
27.   printf("%-20s\t%-5d\t%-10s\t%-20s\t%-30s\n", pc->data[pos].name,
28.                          pc->data[pos].age,
29.                          pc->data[pos].sex,
30.                          pc->data[pos].tel,
31.                          pc->data[pos].addr);
32. 
33. }

4.修改联系人信息  modifycontact

1.判断通讯录中是否有数据,若无数据,则无法修改;

2.输入要修改人的姓名,调用函数 find ,返回其下标;

3.开始修改,即从新录入该联系人信息;

modifycontact  代码:

1. //修改联系人
2. void modifycontact(contact* pc)
3. {
4.  if (pc->sz == 0)  //判断通讯录是否有数据
5.  {
6.    printf("通讯录为空,无法修改\n");
7.    return;
8.  }
9.  char name[MAX_NAME];
10.   int pos = 0;
11.   while (1)
12.   {
13.     again:
14.     printf("请输入要修改的联系人的姓名:>");
15.     scanf("%s", name);
16.     pos = find(name, pc);  //返回要修改的联系人的下标
17.     if (pos == -1)
18.     {
19.       printf("要修改的联系人不存在,重新输入\n");
20.       goto again;
21.     }
22.     else
23.       break;
24.   }
25.   printf("开始修改\n");  //修改联系人信息
26.   printf("请输入姓名:>");
27.   scanf("%s", pc->data[pos].name);
28.   printf("请输入年龄:>");
29.   scanf("%d", &(pc->data[pos].age));
30.   printf("请输入性别:>");
31.   scanf("%s", pc->data[pos].sex);
32.   printf("请输入电话:>");
33.   scanf("%s", pc->data[pos].tel);
34.   printf("请输入地址:>");
35.   scanf("%s", pc->data[pos].addr);
36.   printf("修改成功\n");
37. }

5.打印通讯录  printcontact

这并不难,直接看代码:

1. //打印通讯录
2. void printcontact(contact* pc)
3. {
4.  int i = 0;
5.  printf("%-20s\t%-5s\t%-10s\t%-20s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");  //打印的格式可以根据个人喜好来
6.  for (i = 0; i < pc->sz; i++)
7.  {
8.    printf("%-20s\t%-5d\t%-10s\t%-20s\t%-30s\n", pc->data[i].name,
9.                           pc->data[i].age,
10.                            pc->data[i].sex,
11.                            pc->data[i].tel,
12.                            pc->data[i].addr);
13.   }
14. }

6.排序通讯录  sortcontact

1.首先判断通讯录中的数据是否足以支持排序,若没有数据,或就1个数据,那么都无需排序;

2.利用排序算法,完成通讯录的排序;

3.需要有交换元素的步骤,那么就需要创建中间变量(在 contact.h 中创建)来实现交换;

4.该变量可以设置成结构体变量,成员包括与data 同类型的变量 sort  ,既然与 data 同类型那么就需要对其初始化;

sort 变量的创建:

1. typedef struct sort
2. {
3.  peoinfo* sort;
4. }sort;

sortcontact 代码:

1. //排序通讯录
2. void sortcontact(contact* pc)
3. {
4.  if (pc->sz < 2)
5.  {
6.    printf("通讯录数据不足,无法排序\n");  //判断是否支持排序
7.    return;
8.  }
9.  int i = 0, j = 0;
10.   sort S;  //变量的创建
11.   S.sort= (peoinfo*)calloc(pc->capacity, sizeof(peoinfo));  //sort 的初始化
12.   if (S.sort == NULL) //判断动态内存是否开辟成功
13.   {
14.     perror("sortcontact");
15.     return;
16.   }
17.   printf("开始排序\n");
18.   for (i = 0; i < pc->sz - 1; i++)   //排序算法
19.   {
20.     for (j = i + 1; j < pc->sz; j++)
21.     {
22.       if (strcmp(pc->data[i].name, pc->data[j].name) > 0)
23.       {
24.         S.sort[i] = pc->data[i];  //交换元素
25.         pc->data[i] = pc->data[j];
26.         pc->data[j] = S.sort[i];
27.       }
28.     }
29.   }
30.   printf("排序成功\n");
31.   free(S.sort);  //排序成功后释放所开辟的内存
32.   S.sort = NULL;  //将指针置空,防止使用野指针
33. }

六.退出通讯录 (即input==0时)

1.在退出通讯录之前需要保存通讯录的数据,写一个保存函数  savecontact

2.保存好后销毁通讯录,写一个销毁函数 destroycontact

3.退出通讯录;

保存函数  savecontact

1. //保存文件中的联系人信息
2. void savecontact(contact* pc)
3. {
4.  FILE* pf = fopen("D:\\C\\c-code\\CONTACT\\CONTACT\\contact.txt", "w");  //以只写的方式打开文件
5.  if (pf == NULL)  //判断文件是否打开成功
6.  {
7.    perror("savecontact");
8.    return;
9.  }
10.   int i = 0;
11.   for (i = 0; i < pc->sz; i++)   
12.   {
13.     fwrite(pc->data + i, sizeof(peoinfo), 1, pf);  //向文件中写入通讯录的数据
14.   }
15.   fclose(pf);  //数据写完后,关闭文件
16.   pf = NULL;
17. }

销毁函数 destroycontact

1. //销毁通讯录
2. void destroycontact(contact* pc)
3. {
4.  pc->sz = 0;
5.  pc->capacity = DEFAULT_SZ;  //容量回复默认值
6.  free(pc->data);  //释放之前开辟的内存
7.  pc->data = NULL;  //指针置空,防止野指针的出现
8. }


目录
相关文章
|
8月前
|
存储 编解码 C语言
【c语言】通讯录(动态版+文件+背景音乐)含源码
【c语言】通讯录(动态版+文件+背景音乐)含源码
65 0
|
7月前
|
文件存储 C语言
【C语言】通讯录系统实现 (保姆级教程,附源码)
【C语言】通讯录系统实现 (保姆级教程,附源码)
216 0
|
1月前
|
程序员 C语言
【C语言实战项目】通讯录(动态增容版)
【C语言实战项目】通讯录(动态增容版)
26 0
|
11月前
C进阶:通讯录(动态版本 + 文件操作)附源码(下)
C进阶:通讯录(动态版本 + 文件操作)附源码(下)
51 0
|
1月前
|
存储 C语言
【C语言进阶篇】模拟实现通讯录 (内附源码)
【C语言进阶篇】模拟实现通讯录 (内附源码)
51 1
|
11月前
|
存储 算法
【数据结构与算法】顺序表增删查改的实现(动态版本+文件操作)附源码
【数据结构与算法】顺序表增删查改的实现(动态版本+文件操作)附源码
59 0
【数据结构与算法】顺序表增删查改的实现(动态版本+文件操作)附源码
|
10月前
手把手教你写通讯录(含动态版) 2
手把手教你写通讯录(含动态版)
|
10月前
|
小程序 JavaScript 数据库
云开发(微信-小程序)笔记(十一)---- 分页,不简单啊
云开发(微信-小程序)笔记(十一)---- 分页,不简单啊
91 0
|
10月前
|
前端开发 JavaScript 定位技术
iOS 逆向编程(十六)DZMCycript 脚本使用(封装了常用的快捷函数,后续会继续添加)
iOS 逆向编程(十六)DZMCycript 脚本使用(封装了常用的快捷函数,后续会继续添加)
110 0
进阶版通讯录(动态版)
进阶版通讯录(动态版)