C语言实现简单的通讯录
1.功能总览
- 菜单
- 添加联系人
- 显示已有联系人
- 查找指定联系人
- 删除指定联系人
- 修改指定联系人
- 对已有联系人进行排序
2.主函数的实现
int main()
{
int input = 1;
while (input)
{
Menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
Add();
break;
case 2:
Show();
break;
case 3:
Search();
break;
case 4:
Del();
break;
case 5:
Modify();
break;
case 6:
Sort();
break;
case 0:
printf("exit\n");
break;
default:
printf("error\n");
}
}
return 0;
}
input
接收用户输入信息- 由不同函数完成指定功能
- 当输入为
0
退出程序
使用了库函数,需引用头文件
<stdio.h>
3.菜单的创建
在菜单中,需指引用户输入内容以便进入特定函数:
void Menu()
{
printf("********************************\n");
printf("***** 1.Add 2.Show *****\n");
printf("***** 3.Search 4.Del *****\n");
printf("***** 5.modify 6.sort *****\n");
printf("***** 0.exit *****\n");
printf("********************************\n");
}
效果:
4.通讯录的建立与初始化
4.1建立
一个联系人包含不同类型的信息,所以我使用了结构体来储存信息:
struct Peo
{
char name[NAME_MAX];
int age;
char tele[TELE_MAX];
};
这里创建了一个结构体类型Peo
,可用于储存联系人的姓名、年龄、电话。
一个通讯录应包含多个联系人信息,因此用数组储存,而为了完成后续操作,我们需要记录已有联系人的数量,因此可以再创建一个结构体:
struct Contact
{
struct Peo peo[MAX];
int num;
};
此时可在主函数中创建通讯录:
struct Contact con;
注:由于后续数据可能修改,因此我们使用了
define
:#define MAX 100 #define NAME_MAX 20 #define TELE_MAX 12
MAX
指最多存储的联系人数量
NAME_MAX
指联系人名字最大长度
TELE_MAX
指联系人电话号码最长长度
4.2 初始化
虽然创建变量后会自动初始化为0
,但我们仍可以创建一个函数来初始化通讯录:
void Init(struct Contact* p)
{
assert(p);
p->num = 0;
memset(p->peo, 0, sizeof(p->peo));
}
此时可在主函数中初始化通讯录:
Init(&con);
注:使用了
assert
断言,需引用头文件<assert.h>
5.具体功能
5.1添加联系人
void Add(struct Contact* p)
{
assert(p);
if (p->num == MAX)
{
printf("已满\n");
return;
}
printf("名字:");
scanf("%s", p->peo[p->num].name);
printf("年龄:");
scanf("%d", &p->peo[p->num].age);
printf("电话:");
scanf("%s", p->peo[p->num].tele);
p->num++;
printf("添加成功\n");
}
注:需判断通讯录是否已满,以免溢出
5.2显示已有联系人
void Show(const struct Contact* p)
{
assert(p);
printf("%-*s\t%-*s\t%-*s\n", NAME_MAX, "名字", 4, "年龄", TELE_MAX, "电话");
for (int i = 0; i < p->num; i++)
{
printf("%-*s\t", NAME_MAX, p->peo[i].name);
printf("%-*d\t", 4, p->peo[i].age);
printf("%-*s\n", TELE_MAX, p->peo[i].tele);
}
}
效果:
关于printf
的用法可以看看我写的printf函数详细介绍和使用技巧
5.3查找指定联系人
void Search(const struct Contact* p)
{
assert(p);
printf("输入要查找的名字:");
char name[NAME_MAX] = { 0 };
scanf("%s", name);
int tgt = find_by_name(p, name);
if (tgt == -1)
{
printf("要查找的名字不存在\n");
return;
}
printf("%-*s\t%-*s\t%-*s\n", NAME_MAX, "名字", 4, "年龄", TELE_MAX, "电话");
printf("%-*s\t", NAME_MAX, p->peo[tgt].name);
printf("%-*d\t", 4, p->peo[tgt].age);
printf("%-*s\n", TELE_MAX, p->peo[tgt].tele);
}
在查找,删除,修改中我们都需按照名字查找指定联系人,因此可以再分装一个函数find_by_name
:
static int find_by_name(const struct Contact* p, char* name)
{
assert(p);
for (int i = 0; i < p->num; i++)
{
if (strcmp(name, p->peo[i].name) == 0)
{
return i;
}
}
return -1;
}
找到了返回下标,找不到返回-1
5.4删除指定联系人
void Del(struct Contact* p)
{
assert(p);
printf("输入要删除的名字:");
char name[NAME_MAX] = { 0 };
scanf("%s", name);
int tgt = find_by_name(p, name);
if (tgt == -1)
{
printf("要删除的名字不存在\n");
return;
}
for (int i = tgt; i < p->num - 1; i++)
{
//memmove(p->peo + i, p->peo + i + 1, sizeof(p->peo[0]));
p->peo[i] = p->peo[i + 1];
}
p->num--;
printf("删除成功\n");
}
在修改的操作中,我使用的方法是将修改人之后的人依次提前:
最开始我用的memmove
:
memmove(p->peo + i, p->peo + i + 1, sizeof(p->peo[0]));
后来发现可以直接赋值:
p->peo[i] = p->peo[i + 1];
5.5修改指定联系人
void Modify(struct Contact* p)
{
assert(p);
printf("输入要修改的名字:");
char name[NAME_MAX] = { 0 };
scanf("%s", name);
int tgt = find_by_name(p, name);
if (tgt == -1)
{
printf("要修改的名字不存在\n");
return;
}
printf("名字:");
scanf("%s", p->peo[tgt].name);
printf("年龄:");
scanf("%d", &p->peo[tgt].age);
printf("电话:");
scanf("%s", p->peo[tgt].tele);
}
5.6对已有联系人进行排序
int sort_by_name(const void* n1, const void* n2)
{
return strcmp(((struct Peo*)n1)->name, ((struct Peo*)n2)->name);
}
void Sort(struct Contact* p)
{
assert(p);
qsort(p->peo, p->num, sizeof(p->peo[0]), sort_by_name);
printf("排序成功\n");
}
这里直接用的qsort
,并使用strcmp
按照名字排序
6.可优化的点
更多的功能
联系人的最大数量不能自定义
可动态内存分配,如:
使用malloc
初始化:p->peo = (Peo*)calloc(3,sizeof(Peo));
使用
realloc
增容;Peo* p = (Peo*)realloc(p->peo, (p->capacity + 2) * sizeof(Peo));
程序运行在内存上,一旦退出存储的信息将全部清空
可加入文件的使用
希望本篇文章对你有所帮助!
本人仅仅是个C语言初学者,如有任何意见,欢迎各位提出!