目录
[1 基本格式](#1 基本格式)
[2 结构体的声明](#2 结构体的声明)
[3 初始化 销毁 扩容 插入 删除](#3 初始化 销毁 扩容 插入 删除)
[4 增加联系人](#4 增加联系人)
[5 查看通讯录](#5 查看通讯录)
[6 删除联系人](#6 删除联系人)
[7 查找联系人](#7 查找联系人)
[8 修改联系人](#8 修改联系人)
[9 整体代码](#9 整体代码)
引言:
有了前面顺序表的基础,我们可以尝试利用顺序表实现通讯录,日常使用中,通讯录可以实现的功能有增加联系人,删除联系人,查找联系人,修改联系人,查看联系人等,我们通过本章的学习实现以上五种功能(默认通讯录包含的元素有 名称 性别 年龄 电话号码 地址 )
1 基本格式
通讯录算是一个小的程序了,人们在使用之前都习惯于有菜单,所以我们使用do-while循环,加上switch语句,可以打印菜单,并且用户可以多次选择执行的操作:
void menu()
{
printf("************通讯录***************\n");
printf("***1 增加联系人 2 删除联系人***\n");
printf("***3 查看通讯录 4 修改联系人***\n");
printf("***5 查找联系人 0 退出通讯录***\n");
}
int main()
{
int input = 0;
Seq con;
ConInit(&con);
do
{
menu();
printf("请输入您的操作:\n");
scanf("%d", &input);
switch (input)
{
case 1:
ContactAdd(&con);//增加联系人
break;
case 2:
ContactDel(&con);//删除联系人
break;
case 3:
ContactPrint(&con);//查看通讯录
break;
case 4:
ContactMod();//修改联系人
break;
case 5:
ContactFind();//查找联系人
break;
case 0:
printf("正在退出通讯录......\n");
break;
default:
printf("操作无效,重新输入:\n");
break;
}
} while (input);
ConDestroy(&con);
return 0;
}
case 对应的语句就是我们要执行的操作,大的操作有增删查改以及查找五个操作,那么在实现之前,顺序表的结构体类型,结构体的初始化,空间扩容,空间的销毁等都是要先写上的,为了方便起见,我们使用两个.c文件,一个.h文件,提高代码的整洁度,一个是contact.c文件,一个是contact.h文件(contact是通讯录的意思),同上篇文章一样,函数的声明,结构体的定义放在头文件里面,函数的具体实现放在contact.c文件里面。
2 结构体的声明
#pragma once
#define NAME_MAX 100
#define TEL_MAX 12
#define GENDER_MAX 10
#define ADDR_MAX 100
typedef struct Contact
{
int age;
char name[NAME_MAX];
char tel[TEL_MAX];
char gender[GENDER_MAX];
char addr[ADDR_MAX];
}Con;
typedef Con Datatype;
typedef struct St
{
Datatype* arr;
int size;//有效数据个数
int capacity;//空间大小
}Seq;
在contact头文件里面我们创建好联系人对应的结构体变量Contact,为了方便起见重命名为Con,随后我们创建好一个结构体变量用来给联系人开辟空间,这里可能有点绕,重命名Contact的目的是为了之后数据的易转换,像int全转为float类型,重命名St的目的是为了之后传参方便,我们传参传的是结构体本身,可以理解为Seq*指针指向的arr是Datatype类型的,而Datatype类型又是Con结构的,Con结构体就是我们需要的联系人数据类型,开辟空间的时候就是以整个结构体开辟空间的。
3 初始化 销毁 扩容 插入 删除
void ConInit(Seq* pcon)//初始化
{
pcon->arr = NULL;
pcon->size = pcon->capacity = 0;
}
void ConDestroy(Seq* pcon)//销毁
{
assert(pcon);
pcon->arr = NULL;
pcon->size = pcon->capacity = 0;
free(pcon->arr);
}
初始化和销毁和顺序表的初始化销毁是一样的,当然,引用的头文件不能忘记,指针断言,空间释放都是不能忘记的。
插入数据的时候,我们这里为了方便起见,就用尾部插入,删除我们使用的是指定位置删除,因为之后的删除联系人需要系统需要知道联系人的位置,所以采用的是指定位置删除:
void ConCheckCapacity(Seq* pcon)//扩容
{
if (pcon->capacity == 0)
{
pcon->arr = (Datatype*)malloc(4 * sizeof(Datatype));
pcon->capacity = 4;
}
if (pcon->capacity == pcon->size)
{
Datatype* tem = (Datatype*)realloc(pcon->arr, 2 * pcon->capacity * sizeof(Datatype));
if (tem != NULL)
{
pcon->arr = tem;
pcon->capacity *= 2;
}
else
{
perror("realloc fail!");
return;
}
}
}
void ConPushBack(Seq* pcon, Datatype x)//尾插
{
assert(pcon);
ConCheckCapacity(pcon);
pcon->arr[pcon->size++] = x;
}
void ContactErase(Seq* pcon, int pos)//指定删除
{
assert(pcon);
assert(pos >= 0 && pos < pcon->size);
for (int i = pos; i < pcon->size - 1; i++)
{
pcon->arr[i] = pcon->arr[i + 1];
}
pcon->size--;
}
这五个基本操作可以说是为了后面的几大功能做铺垫,且与之前的顺序表并无两样。
4 增加联系人
增加联系人之前,我们已经做好了初始化 判断扩容 插入等基本操作,现在增加联系人可以说是易如反掌了:
我们添加联系人之前,我们需要先创建好一个联系人,这时候就用上了之前重命名的Con结构体了,然后就是大同小异的输入,输出,最后使用尾插函数,把这个联系人存储进去就行了。
void ContactAdd(Seq* pcon)//增加联系人
{
Con contact;
printf("输入联系人姓名:");
scanf("%s", contact.name);
printf("输入联系人性别:");
scanf("%s", contact.gender);
printf("输入联系人年龄:");
scanf("%d", contact.age);
printf("输入联系人电话:");
scanf("%s", contact.tel);
printf("输入联系人地址:");
scanf("%s", contact.addr);
ConPushBack(pcon, contact);
printf("添加成功!");
}
5 查看通讯录
查看通讯录无非就是打印通讯录,那么只需要用上最基本的for循环就行了:
void ContactPrint(Seq* pcon)//查看通讯录
{
assert(pcon);
printf("姓名 性别 年龄 电话号码 地址\n");
for (int i = 0; i < pcon->size; i++)
{
printf("%s %s %d %s %s", pcon->arr[i].name,
pcon->arr[i].gender,
pcon->arr[i].age,
pcon->arr[i].tel,
pcon->arr[i].addr);
}
printf("\n");
}
为了界面整洁我们可以在打印联系人数据的时候打印出联系人的基本框架出来:
最后就是换行符不要忘记就行。
6 删除联系人
在执行删除联系人之前应该先遍历整个通讯录看有没有这个联系人,如果没有,也就不存在删除的说法,所以下一个实现的函数是查找联系人,联系人有多种数据,其中重叠可能性最小的是姓名,即我们可以使用姓名来查找联系人,因为查找联系人是为了之后的删除,修改联系人做准备,查找联系人的返回值可以有正负,i -1,i就表示找到了,存在这个联系人,下标为i,-1就表示没有找到,不存在这个联系人:
int FindByname(Seq* pcon,char name[NAME_MAX])//通过姓名寻找
{
for (int i = 0; i < pcon->size; i++)
{
if (strcmp(name, pcon->arr[i].name) == 0)
{
return i;
}
}
return -1;
}
我们是通过联系人姓名来寻找的,所以首先遍历空空间,利用strcmp的返回值来判断是否存在
void ContactDel(Seq* pcon)//删除联系人
{
assert(pcon);
char name[NAME_MAX];
printf("请输入要删除的联系人的姓名:");
scanf("%s", name);
int tem = FindByname(pcon, name);
if (tem < 0)
{
printf("要删除的联系人不存在!");
return;
}
ContactErase(pcon, tem);
printf("删除成功!\n");
}
删除就是利用的返回值,大于0呢,就删除,小于0就直接返回。
7 查找联系人
查找联系人用到的函数其实就是FIndByname函数,只不过加了一点点改变而已,通过返回值进行判断,然后进行打印就行了:
void ContactFind(Seq* pcon)//查找联系人
{
assert(pcon);
char name[NAME_MAX];
printf("请输入联系人姓名:");
scanf("%s", name);
int tem = FindByname(pcon, name);
if (tem >= 0)
{
printf("找到了!\n");
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%s %s %d %s %s\n", pcon->arr[tem].name,
pcon->arr[tem].gender,
pcon->arr[tem].age,
pcon->arr[tem].tel,
pcon->arr[tem].addr);
}
else
{
printf("联系人不存在!\n");
}
}
8 修改联系人
修改联系人的基础是在于能否找到,所以还是需要FindByname函数,找到这个联系人之后,我们就需要利用返回的下标,来实现修改联系人数据:
void ContactMod(Seq* pcon)//修改联系人
{
assert(pcon);
char name[NAME_MAX];
printf("请输入要修改的联系人的姓名:");
scanf("%s", name);
int tem = FindByname(pcon, name);
if (tem >= 0)
{
printf("存在该联系人,请修改:\n");
printf("输入联系人姓名:");
scanf("%s", pcon->arr[tem].name);
printf("输入联系人性别:");
scanf("%s", pcon->arr[tem].gender);
printf("输入联系人年龄:");
scanf("%d", pcon->arr[tem].age);
printf("输入联系人电话:");
scanf("%s", pcon->arr[tem].tel);
printf("输入联系人地址:");
scanf("%s", pcon->arr[tem].addr);
printf("修改成功!\n");
}
else
{
printf("不存在该联系人!\n");
}
}
在每次函数开头的时候,我们都应该使用assert断言,因为我们不知道程序执行到这一步的时候指针有没有变成空指针,在使用完FindByname的时候,我们利用下标进行修改,修改为无非就是进行重新输入。
9 整体代码
以上就就是顺序表实现通讯录的全部过程,整体代码如下:
contact头文件:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define NAME_MAX 100
#define TEL_MAX 12
#define GENDER_MAX 10
#define ADDR_MAX 100
typedef struct Contact
{
int age;
char name[NAME_MAX];
char tel[TEL_MAX];
char gender[GENDER_MAX];
char addr[ADDR_MAX];
}Con;
typedef Con Datatype;
typedef struct St
{
Datatype* arr;
int size;//有效数据个数
int capacity;//空间大小
}Seq;
void ConInit(Seq* pcon);//初始化
void ConDestroy(Seq* pcon);//销毁
void ConCheckCapacity(Seq* pcon);//扩容
void ConPushBack(Seq* pcon, Datatype x);//尾插
void ContactErase(Seq* pcon, int pos);//指定删除
void ContactAdd(Seq* pcon);// 增加联系人
void ContactPrint(Seq* pcon);//查看通讯录
void ContactDel(Seq* pcon);//删除联系人
void ContactMod(Seq* pcon);//修改联系人
void ContactFind(Seq* pcon);//查找联系人
contact.c文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
void ConInit(Seq* pcon)//初始化
{
pcon->arr = NULL;
pcon->size = pcon->capacity = 0;
}
void ConDestroy(Seq* pcon)//销毁
{
assert(pcon);
pcon->arr = NULL;
pcon->size = pcon->capacity = 0;
free(pcon->arr);
}
void ContactErase(Seq* pcon, int pos)//指定删除
{
assert(pcon);
assert(pos >= 0 && pos < pcon->size);
for (int i = pos; i < pcon->size - 1; i++)
{
pcon->arr[i] = pcon->arr[i + 1];
}
pcon->size--;
}
void ConCheckCapacity(Seq* pcon)//扩容
{
if (pcon->capacity == 0)
{
pcon->arr = (Datatype*)malloc(4 * sizeof(Datatype));
pcon->capacity = 4;
}
if (pcon->capacity == pcon->size)
{
Datatype* tem = (Datatype*)realloc(pcon->arr, 2 * pcon->capacity * sizeof(Datatype));
if (tem != NULL)
{
pcon->arr = tem;
pcon->capacity *= 2;
}
else
{
perror("realloc fail!");
return;
}
}
}
void ConPushBack(Seq* pcon, Datatype x)//尾插
{
assert(pcon);
ConCheckCapacity(pcon);
pcon->arr[pcon->size++] = x;
}
void ContactAdd(Seq* pcon)//增加联系人
{
Con contact;
printf("输入联系人姓名:");
scanf("%s", contact.name);
printf("输入联系人性别:");
scanf("%s", contact.gender);
printf("输入联系人年龄:");
scanf("%d", &contact.age);
printf("输入联系人电话:");
scanf("%s", contact.tel);
printf("输入联系人地址:");
scanf("%s", contact.addr);
ConPushBack(pcon, contact);
printf("添加成功!\n");
}
void ContactPrint(Seq* pcon)//查看通讯录
{
assert(pcon);
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
for (int i = 0; i < pcon->size; i++)
{
printf("%s %s %d %s %s\n", pcon->arr[i].name,
pcon->arr[i].gender,
pcon->arr[i].age,
pcon->arr[i].tel,
pcon->arr[i].addr);
}
printf("\n");
}
int FindByname(Seq* pcon,char name[NAME_MAX])//通过姓名寻找
{
for (int i = 0; i < pcon->size; i++)
{
if (strcmp(name, pcon->arr[i].name) == 0)
{
return i;
}
}
return -1;
}
void ContactDel(Seq* pcon)//删除联系人
{
assert(pcon);
char name[NAME_MAX];
printf("请输入要删除的联系人的姓名:");
scanf("%s", name);
int tem = FindByname(pcon, name);
if (tem < 0)
{
printf("要删除的联系人不存在!");
return;
}
ContactErase(pcon, tem);
printf("删除成功!\n");
}
void ContactMod(Seq* pcon)//修改联系人
{
assert(pcon);
char name[NAME_MAX];
printf("请输入要修改的联系人的姓名:");
scanf("%s", name);
int tem = FindByname(pcon, name);
if (tem >= 0)
{
printf("存在该联系人,请修改:\n");
printf("输入联系人姓名:");
scanf("%s", pcon->arr[tem].name);
printf("输入联系人性别:");
scanf("%s", pcon->arr[tem].gender);
printf("输入联系人年龄:");
scanf("%d", pcon->arr[tem].age);
printf("输入联系人电话:");
scanf("%s", pcon->arr[tem].tel);
printf("输入联系人地址:");
scanf("%s", pcon->arr[tem].addr);
printf("修改成功!\n");
}
else
{
printf("不存在该联系人!\n");
}
}
void ContactFind(Seq* pcon)//查找联系人
{
assert(pcon);
char name[NAME_MAX];
printf("请输入联系人姓名:");
scanf("%s", name);
int tem = FindByname(pcon, name);
if (tem >= 0)
{
printf("找到了!\n");
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%s %s %d %s %s\n", pcon->arr[tem].name,
pcon->arr[tem].gender,
pcon->arr[tem].age,
pcon->arr[tem].tel,
pcon->arr[tem].addr);
}
else
{
printf("联系人不存在!\n");
}
}
主函数.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "Contact.h"
void menu()
{
printf("************通讯录***************\n");
printf("***1 增加联系人 2 删除联系人***\n");
printf("***3 查看通讯录 4 修改联系人***\n");
printf("***5 查找联系人 0 退出通讯录***\n");
}
int main()
{
int input = 0;
Seq con;
ConInit(&con);
do
{
menu();
printf("请输入您的操作:\n");
scanf("%d", &input);
switch (input)
{
case 1:
ContactAdd(&con);//增加联系人
break;
case 2:
ContactDel(&con);//删除联系人
break;
case 3:
ContactPrint(&con);//查看通讯录
break;
case 4:
ContactMod(&con);//修改联系人
break;
case 5:
ContactFind(&con);//查找联系人
break;
case 0:
printf("正在退出通讯录......\n");
break;
default:
printf("操作无效,重新输入:\n");
break;
}
} while (input);
ConDestroy(&con);
return 0;
}
感谢阅读!