C语言实现通讯录第一个版本——静态版本
文章目录
一、通讯录整体介绍
本篇博客所实现的是通讯录第一个版本——静态版本,内存大小一旦确定不能灵活的更改它的大小,可以简单实现通讯录的基本功能。我们将通讯录的程序按功能分别写在一个工程的三个文件中,使得程序结构更加清楚,下面就分别讲这三个文件是如何相互作用实现通讯录的。
二、头文件
头文件我们命名为contacts.h,主要用来写函数的声明和结构体的定义。
代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX 100
#define MAX_name 10
struct PeoInfo
{
char name[10];
char sex[5];
char tele[12];
int age;
char adder[30];
};
struct Contact
{
struct PeoInfo data[MAX];
int sz;
};
我们在这个头文件中定义了两个结构体,利用了结构体相互嵌套,从而实现了通讯录每个成员。
二、功能实现
我们将通讯录所要实现的功能写在一个文件下,命名为static contacts.c
代码如下(示例):
#define _CRT_SECURE_NO_WARNINGS 1
#include"contacts.h"
void InitContact(struct Contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, MAX * sizeof(struct PeoInfo));
}
void AddContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加新用户");
return;
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].adder);
pc->sz++;
printf("添加新用户成功!");
}
void ShowContact(struct Contact* pc)
{
int i = 0;
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < (pc->sz); i++)
{
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].adder);
}
}
static int FindByName(const struct Contact* pc, char name[])
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
void DelContact(struct Contact* pc)
{
char name[MAX_name];
printf("请输入你要删除人的姓名->");
scanf("%s\n", name);
int ret = FindByName(pc, name);
if (-1 == ret)
{
printf("未找到指定的用户");
}
else
{
for (int j = ret; j < pc->sz - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("成功删除用户");
}
}
void SearchContact(const struct Contact* pc)
{
char name[MAX_name];
printf("请输入要查找的人的名字:>");
scanf("%s", name);
//查找一下指定的人是否存在
int ret = FindByName(pc, name);
if (ret == -1)
printf("要查找的人不存在\n");
else
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].adder);
}
}
void ModifyContact(struct Contact* pc)
{
printf("请输入要修改人的姓名:");
char name[MAX_name];
int ret = FindByName(pc, name);
if (-1 == ret)
{
printf("未查找到联系人");
return;
}
printf("请输入用户的姓名:");
scanf("%s\n", pc->data[ret].name);
printf("请输入性别:>");
scanf("%s\n", pc->data[ret].sex);
printf("请输入年龄:>");
scanf("%d\n", &(pc->data[ret].age));
printf("请输入电话:>");
scanf("%s\n", pc->data[ret].tele);
printf("请输入地址:>");
scanf("%s\n", pc->data[ret].adder);
printf("成功修改\n");
}
//int CompAge(const void* e1, const void* e2)
//{
// return (((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age);
//}
//void qsortcontact(struct Contact* pc)
//{
// qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CompAge);
//}
int CompName(const void* e1, const void* e2)
{
return strcmp(((struct PeoInfo*)e1)->name ,((struct PeoInfo*)e2)->name);
}
void qsortByName(struct Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CompName);
}
在这个文件里面我们设计了通讯录的6大功能:
1.增加联系人
2.删除联系人
3.查找联系人
4.修改联系人
5.展示通讯录
6.通讯录排序
1.增加联系人
代码如下:
void AddContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == MAX)
{
printf("通讯录已满,无法添加新用户");
return;
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->sz].adder);
pc->sz++;
printf("添加新用户成功!");
}
我们先判断通讯录是否已经满了,如果已经满了就打印通讯录已满,如果没满,我们依次输入通讯录用户的信息到data结构体数组中去,同时通讯录的大小进行++操作。
2.删除联系人
static int FindByName(const struct Contact* pc, char name[])
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (0 == strcmp(pc->data[i].name, name))
{
return i;
}
}
return -1;
}
void DelContact(struct Contact* pc)
{
char name[MAX_name];
printf("请输入你要删除人的姓名->");
scanf("%s\n", name);
int ret = FindByName(pc, name);
if (-1 == ret)
{
printf("未找到指定的用户");
}
else
{
for (int j = ret; j < pc->sz - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sz--;
printf("成功删除用户");
}
}
既然我们要实现删除联系人,第一步就要先找到联系人,所以我们设计了 FindByName函数,用来实现查找联系人的功能,我们这个函数的返回类型设置成int型,如果找到就返回他的位置,如果没找到就返回-1同时打印未找到联系人,因为姓名是字符串,两个字符串比较要用到strcmp函数,切记要使用头文件#include<string.h>,如果找到了我们就利用循环让删除位置后面的数据向前都移动来覆盖要删除的联系人,达到删除的效果。
3.查找联系人
代码如下:
void SearchContact(const struct Contact* pc)
{
char name[MAX_name];
printf("请输入要查找的人的名字:>");
scanf("%s", name);
//查找一下指定的人是否存在
int ret = FindByName(pc, name);
if (ret == -1)
printf("要查找的人不存在\n");
else
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[ret].name,
pc->data[ret].sex,
pc->data[ret].age,
pc->data[ret].tele,
pc->data[ret].adder);
}
}
我们之前为了实现删除联系人的功能编写了一个FindByName函数,这里我们继续调用这个函数,并在这个函数的基础上加上打印信息的功能来完成查找联系人的功能,因为每个人的信息都不太一样,直接打印出来会显得很乱,所以我们利用\t制表来打印联系人的各项数据。
4.修改联系人
代码如下:
void ModifyContact(struct Contact* pc)
{
printf("请输入要修改人的姓名:");
char name[MAX_name];
int ret = FindByName(pc, name);
if (-1 == ret)
{
printf("未查找到联系人");
return;
}
printf("请输入用户的姓名:");
scanf("%s\n", pc->data[ret].name);
printf("请输入性别:>");
scanf("%s\n", pc->data[ret].sex);
printf("请输入年龄:>");
scanf("%d\n", &(pc->data[ret].age));
printf("请输入电话:>");
scanf("%s\n", pc->data[ret].tele);
printf("请输入地址:>");
scanf("%s\n", pc->data[ret].adder);
printf("成功修改\n");
}
修改功能实现也很容易,就是先找到我们想修改的联系人所在的位置,然后重新输入数据来替换之前的信息,从而就可以达到修改联系人的功能,需要注意的是我们要用一个变量来接收FindByName的函数的返回值,然后根据返回值确定到底要修改那个位置的联系人。
5.展示通讯录
void ShowContact(struct Contact* pc)
{
int i = 0;
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "姓名", "性别", "年龄", "电话", "地址");
for (i = 0; i < (pc->sz); i++)
{
printf("%-20s\t%-5s\t%-5d\t%-12s\t%-30s\n", pc->data[i].name,
pc->data[i].sex,
pc->data[i].age,
pc->data[i].tele,
pc->data[i].adder);
}
}
6.通讯录排序
方法一:按照年龄排序
int CompAge(const void* e1, const void* e2)
{
return (((struct PeoInfo*)e1)->age - ((struct PeoInfo*)e2)->age);
}
void qsortcontact(struct Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CompAge);
}
我们可以按照通讯录成员的年龄对其进行排序,我们会使用到qsort函数,qsort函数的定义如下:
方法二:姓名排序
int CompName(const void* e1, const void* e2)
{
return strcmp(((struct PeoInfo*)e1)->name ,((struct PeoInfo*)e2)->name);
}
void qsortByName(struct Contact* pc)
{
qsort(pc->data, pc->sz, sizeof(struct PeoInfo), CompName);
}
三、测试文件
我们将主函数写在测试文件中,测试文件我们命名为test.c
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include"contacts.h"
void menu()
{
printf("**************************************\n");
printf("***** 1. add 2. del *****\n");
printf("***** 3. search 4. modify *****\n");
printf("***** 5. show 6. sort *****\n");
printf("***** 0. exit *****\n");
printf("**************************************\n");
}
int main()
{
int intput = 0;
struct Contact con;
InitContact(&con);
do
{
menu();
printf("请输入->");
scanf("%d", &intput);
switch (intput)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
SearchContact(&con);
break;
case 4:
ModifyContact(&con);
break;
case 5:
ShowContact(&con);
break;
case 6:
qsortByName(&con);
break;
case 0:
printf("退出成功!\n");
break;
default:
printf("输入无效,重新输入");
break;
}
} while (intput);
return 0;
}
测试文件包括我们的主函数以及通讯录菜单的实现,涉及的就是函数功能的调用。
总结
本篇博客针对通讯录静态版本进行讲解,功能相对简单容易实现,但是局限性也很明显,就是不能容易的改变通讯录的大小,这就涉及到动态内存管理,随后我将会继续更新以动态内存的方式创建通讯录,如果这篇博客对你有用的话,可以私信我,关注持续更新,希望我和大家一同进步~