前言
1、通讯录是什么
通讯录是一种用于记录联系人信息的列表或数据库。它可以包含各种类型的联系方式和个人信息,例如:姓名,年龄,性别,电话,地址等等信息。
2、所需技术
本次我们使用C语言来实现这个静态版本的通讯录,需要我们能够熟练使用C语言的基本语法,特别是在结构体这一方面需要足够了解,然后使用分文件模式编写,才能顺利地编写出这个通讯录。这里也要介绍一个C语言的库函数qsort(),我们将利用它来进行通讯录的快速排序。
一、头文件部分
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define N 100
typedef struct peo
{
char name[10];
int age;
char sex[5];
char tele[20];
}peo;
typedef struct mem
{
peo m[N];
int c;
}mem;
void chu(mem* pcon);
void add(mem* pcon);
void del(mem* pcon);
void search(mem* pcon);
void show(mem* pcon);
void gai(mem* pcon);
void sort(mem* pcon);
在头文件中,我们将需要使用到的头文件以及函数的声明放在这里,然后我们定义了一个peo的结构体,这个结构体代表了通讯录中的每一个人的信息,这里我定义了姓名,年龄,性别,电话。然后再定义了一个结构体mem,这个结构体就代表了一个通讯录,里面有一个peo类型的数组以及一个整形变量存储当前存储的个数。我们定义了一个N为100,将其作为mem中peo数组的大小,固定了其大小,所以是一个静态版本的通讯录。
二、目录部分
int main()
{
enum
{
toexit,
toadd,
todel,
tofind,
togai,
toshow,
tosort
};
int input = 0;
mem con;
chu(&con);
do
{
printf("********************************\n");
printf("**************目录**************\n");
printf("***1.添加 2.删除***\n");
printf("***3.查找 4.修改***\n");
printf("***5.显示 6.排序***\n");
printf("**************0.退出************\n");
printf("********************************\n");
scanf("%d", &input);
switch (input)
{
case toadd:
add(&con);
break;
case todel:
del(&con);
break;
case tofind:
search(&con);
break;
case togai:
gai(&con);
break;
case toshow:
show(&con);
break;
case tosort:
sort(&con);
break;
case toexit:
printf("退出程序!\n");
break;
default:
printf("输入错误!\n");
}
} while (input);
return 0;
}
目录部分跟之前一样,使用do…while语句嵌套switch语句做目录,然后定义一个mem类型变量con来代表通讯录。不过这里有一点需要特别说明的是我们这里在case后面的判断部分使用了枚举变量:
enum
{
toexit,
toadd,
todel,
tofind,
togai,
toshow,
tosort
};
需要注意的是,枚举变量里第一个变量代表0,第二个代表1,以此类推。所以我们使用枚举变量来代替传统的case 1这种写法可以提高我们代码的可读性,比如第一个toexit一看就能明白是退出,第二个toadd一看也能明白是添加的意思。
三、内容部分
初始化我们的通讯录,这里我们使用了一个assert()断言函数,当里面的条件为假(false)时,运行时就会报错,便于我们发现错误。这里就是对传入的pcon变量进行断言,假如我们不小心传入了一个空指针,那么这里就会报错,帮助我们定位错误。
void chu(mem* pcon)
{
assert(pcon);
pcon->c = 0;
memset(pcon->m, 0, N);
}
添加联系人信息的add()函数。
void add(mem* pcon)
{
assert(pcon);
if (pcon->c < N)
{
printf("请输入姓名:");
scanf("%s", pcon->m[pcon->c].name);
printf("请输入年龄:");
scanf("%d", &pcon->m[pcon->c].age);
printf("请输入性别:");
scanf("%s", pcon->m[pcon->c].sex);
printf("请输入电话:");
scanf("%s", pcon->m[pcon->c].tele);
printf("添加成功\n");
pcon->c++;
return;
}
else
{
printf("数量已满\n");
return;
}
}
查询联系人的两个函数,这里是根据联系人名字来查找。
int find(mem* pco,char n[])
{
assert(pco);
int i = 0;
for (i = 0; i < pco->c; i++)
{
if (strcmp(pco->m[i].name, n) == 0)
{
return i;
}
}
return -1;
}
void search(mem* pcon)
{
assert(pcon);
char n[10] = { 0 };
printf("请输入查找对象姓名\n");
scanf("%s", n);
int a = find(pcon, n);
if (a == -1)
{
printf("无查找对象\n");
return;
}
else
{
printf("%-10s %-4s %-5s %-20s\n", "姓名", "年龄", "性别", "电话");
printf("%-10s %-4d %-5s %-20s\n", pcon->m[a].name, pcon->m[a].age, pcon->m[a].sex, pcon->m[a].tele);
return;
}
}
这是展示所有联系人的show()函数,也可以叫做打印函数,我们对通讯录进行遍历然后根据设定的格式依次打印每个联系人的信息。
void show(mem* pcon)
{
assert(pcon);
int i = 0;
printf("%-10s %-4s %-5s %-20s\n", "姓名","年龄","性别","电话");
for (i = 0; i < pcon->c; i++)
{
printf("%-10s %-4d %-5s %-20s\n", pcon->m[i].name, pcon->m[i].age, pcon->m[i].sex, pcon->m[i].tele);
}
}
删除连续人的del()函数,根据联系人的名字进行删除。
void del(mem* pcon)
{
assert(pcon);
if (pcon->c == 0)
{
printf("无删除对象\n");
return;
}
else
{
char n[10] = { 0 };
printf("请输入删除对象姓名\n");
scanf("%s", n);
int a = find(pcon, n);
if (a == -1)
{
printf("无删除对象\n");
return;
}
else
{
int i = 0;
for (i = a; i < pcon->c - 1; i++)
{
pcon->m[i] = pcon->m[i + 1];
}
printf("删除对象成功\n");
pcon->c--;
}
}
}
更改联系人信息的gai()函数,根据名字进行查询,查询到后重新输入信息进行修改。
void gai(mem* pcon)
{
assert(pcon);
if (pcon->c == 0)
{
printf("无更改对象\n");
}
else
{
char n[10] = { 0 };
printf("请输入更改对象姓名\n");
scanf("%s", n);
int a = find(pcon, n);
if (a == -1)
{
printf("无更改对象\n");
return;
}
else
{
printf("请输入姓名:");
scanf("%s", pcon->m[a].name);
printf("请输入年龄:");
scanf("%d", &pcon->m[a].age);
printf("请输入性别:");
scanf("%s", pcon->m[a].sex);
printf("请输入电话:");
scanf("%s", pcon->m[a].tele);
printf("更改成功\n");
return;
}
}
}
排序sort()函数,由于我们使用的是数组来存储信息,在内存中是连续存储的,所以我们这里使用一个库函数qsort来帮助我们进行快速排序。
qsort函数
第一个参数是一个指针,代表指向数组中要排序的第一个对象的指针,转换为void*。
第二个参数是一个无符号整形的变量,代表数组中由基指向的需要进行排序的元素个数。
第三个参数也是一个无符号整形变量,代表需要进行排序的每一个部分的大小。
第四个参数是一个函数指针,指向比较两个元素的函数的指针。qsort会反复调用此函数来比较两个元素。它应遵循以下原型:
int compar(const voidp1,const voidp2);
当返回值<0,代表p1指向的元素位于p2指向的元素之前,即p1<p2;
当返回值=0,代表p1指向的元素与p2指向的元素相等,即p1=p2;
当返回值>0,代表p1指向的元素位于p2指向的元素之后,即p1>p2;
由于这里我们需要对结构体自定义类型进行排序,所以我们要重写一下排序规则然后将其作为参数传递给qsort函数。
int cmp1(const void* c1,const void* c2)
{
return strcmp(((peo*)c1)->name, ((peo*)c2)->name);
}
int cmp2(const void* c1, const void* c2)
{
return strcmp(((peo*)c1)->tele, ((peo*)c2)->tele);
}
void sort(mem* pcon)
{
printf("请选择排序规则:1.姓名 2.电话\n");
int n = 0;
scanf("%d", &n);
if (n == 1)
{
qsort(pcon->m, pcon->c, sizeof(pcon->m[0]), cmp1);
printf("排序成功\n");
return;
}
else if (n == 2)
{
qsort(pcon->m, pcon->c, sizeof(pcon->m[0]), cmp2);
printf("排序成功\n");
return;
}
else
{
printf("输入错误,取消排序\n");
return;
}
}
这样我们就利用了qsort函数帮助我们进行了快速排序,这里我只写了两个比较函数,分别是根据姓名和电话进行快速排序。
总结
这样一个简易静态版的通讯录就做好了,编写这个通讯录可以说运用到了C语言的大部分基本语法,是一个学习完初阶C语言后的不错练手项目。这里我们只编写了通讯录常见的增、删、查、改部分,我们完全可以根据自己的需要进行功能的拓展。同时在下一次我会介绍一个动态版本的通讯录,即存储的数量是动态变化开辟的,并且将运用文件的相关知识将联系人的相关信息存储在文件中。
如需源码,可在我的gitee上找到,下面是链接。
通讯录静态源码
如对您有所帮助,可以来个三连,感谢大家的支持。
每文推荐
孙燕姿–逆光
韩安旭–不在
任然–雀跃
学技术学累了时可以听歌放松一下