目录
一、前言
二、通讯录的实现
1.关于通讯录的前期准备
(1)关于全局变量的定义
(2)菜单的实现
(3)关于联系人结构体的创建
(4)实现菜单选项的功能
2、通讯录的功能实现
(1)初始化通讯录
(2)增加联系人
(3)删除联系人
(4)打印通讯录
(5)查找联系人
(6)修改联系人
(7)排序通讯录
总结:
test.c
contact.c
contact.h
感谢阅读!!!
一、前言
本文将会用c语言实现一个通讯录的系统,并且存储若干人的信息,每个人的信息包括:姓名,性别,年龄,电话号码,住址。此通讯录系统的功能包括: 1.增加联系人 2.删除对应的联系人 3.查找联系人 4.修改联系人的信息 5.排序此通讯录 6.打印出通讯录每个人的信息
二、通讯录的实现
1.关于通讯录的前期准备
(1)关于全局变量的定义
为了实现这些变量,并且方便后期的处理数组大小,所以我们可以利用宏来实现这个功能
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
(2)菜单的实现
首先关于一个通讯录,建立一个菜单是很重要的,菜单能够实现和用户的交互。
因此我们需要建立一个菜单,并且菜单立马应该包括通讯录立马该有的功能,以便于用户的操作
代码如下:
void menu()
{
printf("**************************************\n");
printf("***** 1.add 2.del *****\n");
printf("***** 3.search 4.modify *****\n");
printf("***** 5.show 6sort *****\n");
printf("***** 0.exit *****\n");
printf("**************************************\n");
}
效果大致这样就可以;
(3)关于联系人结构体的创建
这里我们需要利用结构体来实现实现前言中的通讯录功能以及联系人信息,我将利用两个结构体来构建我们需要的东西。(大小设置为1000)(最多存放1000个人的信息)
struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
struct contact
{
struct PeoInfo date[MAX];
int size;
};
(4)实现菜单选项的功能
我们需要根据菜单里面的选项来选择进行我们需要实现的功能,比如我们想假如一个用户信息,我们就输入1就会进行用户假如的操作,我们想退出程序我们输入0就可以退出。我选择利用枚举变量的形式来实现,讲操作变成数字,利用switch选择语句来实现各自的功能。
使用枚举的好处就是方便了我们补充函数内容的时候方便得知那个数字对应那个功能
enum option
{
EXIT,//0
ADD,//1
DEL,//2
SEARCH,//3
MODIFY,//4
SHOW, //5
SORT,//6
};
然后使用switch的时候便会方便许多,如下
int input = 0;
//创建结构体数组
struct contact con;
//初始化结构体数组
Initcon(&con);
do {
menu();
printf("请输入你的选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
Addcontact(&con);
break;
case DEL:
Delcontact(&con);
break;
case SEARCH:
Searchcontact(&con);
break;
case MODIFY:
Modifycontact(&con);
break;
case SHOW:
Showcontact(&con);
break;
case SORT:
SortContact(&con);
break;
case EXIT:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入:>\n");
break;
}
} while (input);
我们case的后面不在是1 2 3 而是对应功能的名字,是不是很方便呢
2、通讯录的功能实现
(1)初始化通讯录
第一步初始化的话,我们要知道要将通讯录初始化什么内容,初始化的目的就是为了避免因不进行初始化导致存的是随机值,从而造成不必要的麻烦,一般的初始化就是放0或者为空;这里我们可以浅浅用一个memset函数来实现,当然别忘了引用string的头文件,然后sz的初始化很简单就是初始化为0。
memset(ps->date, 0, sizeof(ps->date));
ps->size = 0;
代码就是这么简单,但是我们为了书写的时候便于看,一般分多个项目进行写一个小游戏;
这里只展示函数的实现部分(下同)
void Initcon(struct contact* ps)
{
assert(ps!=NULL);
memset(ps->date, 0, sizeof(ps->date));
ps->size = 0;
}
(2)增加联系人
首先第一步我们完成第一步就可以创建关于加入联系人的函数,这个很简单我们只需要访问通讯录结构体里面的数组中的每个元素然后输入对应值就可以了
void Addcontact(struct contact* ps)
{
assert(ps != NULL);
if (ps->size == MAX)
{
printf("通讯录已满,无法再进行添加\n");
}
else
{
printf("情输入姓名:>");
scanf("%s", ps->date[ps->size].name);
printf("情输入年龄:>");
scanf("%d", &(ps->date[ps->size].age));
printf("情输入性别:>");
scanf("%s", ps->date[ps->size].sex);
printf("情输入电话:>");
scanf("%s", ps->date[ps->size].tele);
printf("情输入地址:>");
scanf("%s", ps->date[ps->size].addr);
ps->size++;//千万要记得++
printf("录入信息完成\n");
}
}
(3)删除联系人
这个操作也不算复杂,我的思路是,首先我们先利用刚刚查找的嘞个查找下标的函数,查找到我们需要寻找删除联系人的坐标,然后对他进行删除,删除之后呢我们需要把后面的元素挨个往前移动,这就要利用for循环,但是对于for循环的次数要多加注意,因为稍不小心就会导致数组越界。
static int Find_by_name(const struct contact* ps, char name[MAX_NAME])
{//static修饰可以使其函数仅可以再本。c生效
//避免了污染
assert(ps != NULL);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->date[i].name, name) == 0)
return i;
}
return -1;
}
void Delcontact(struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要删除联系人的姓名:>");
scanf("%s", name);
//查找
//找到返回pos下标
//找不到返回-1
int pos=Find_by_name(ps, name);
if (pos == -1)
{
printf("要删除的联系人不存在\n");
}
else
{
int j = 0;
for (j = pos; j <ps->size ; j++)//
//*******
{
ps->date[j] = ps->date[j + 1];
}
ps->size--;
printf("删除成功\n");
}
}
这个代码其中有一个地方加了 static 这一部分就很妙,就好比如如果别的。c文件再写的时候跟这个函数有关系,就可以避免发生关系,就会使得 Find_by_name这个函数只会在本文件下生效,避免了污染,就好比生物上的物种感染,你可以不用,但不能没有,避免发生麻烦;
(4)打印通讯录
打印通讯录也很简单,利用一个for循环根据sz的大小遍历结构体中的数组每个元素并且打印即可
在正常情况下打印这一步一定要尽早实现,因为,我们每写完一项功能,我们自己认为没问题,并且也可以跑的情况下,我们无法得知跟我们想要实现的功能有什么差别,这时候都需要打印一下,实践出真理;
代码如下:
void Showcontact(const struct contact* ps)
{
assert(ps != NULL);
int i = 0;
if (ps->size == 0)
{
printf("通讯录内容为空,无法打印\n");
}
else
{
for (i = 0; i < ps->size; i++)
{
printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");//为了打印出来的内容对其,显得好看对其的打印要一直
printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",//就先这跟上面的一样才好看
ps->date[i].name,
ps->date[i].age,
ps->date[i].sex,
ps->date[i].tele,
ps->date[i].addr);
}
}
}
(5)查找联系人
查找联系人这边我们需要构建一个函数,这个函数需要去根据我们想要寻找的姓名去在通讯录中寻找这个人所对应的位置,加入找到了就可以返回对应位置的下标,否则返回-1。找到之后就和打印通讯录的操作差不多打印出来就好了。然而查找可以通过多种方式,年龄啊,电话啊,这里使用的是姓名
void Searchcontact(const struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要查找联系人的姓名:>");
scanf("%s", name);
int pos = Find_by_name(ps, name);
if (pos == -1)
{
printf("要查找的联系人不存在\n");
}
else
{
printf("信息如下:\n");
printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
ps->date[pos].name,
ps->date[pos].age,
ps->date[pos].sex,
ps->date[pos].tele,
ps->date[pos].addr);
}
}
(6)修改联系人
所有,我们可以先让用户输入想要修改人的信息,然后再重新在add所有信息
void Modifycontact(struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要修改联系人的姓名:>");
scanf("%s", name);
int pos = Find_by_name(ps, name);
if (pos == -1)
{
printf("要修改的联系人不存在\n");
}
else
{
printf("情输入姓名:>");
scanf("%s", ps->date[pos].name);
printf("情输入年龄:>");
scanf("%d", &(ps->date[pos].age));
printf("情输入性别:>");
scanf("%s", ps->date[pos].sex);
printf("情输入电话:>");
scanf("%s", ps->date[pos].tele);
printf("情输入地址:>");
scanf("%s", ps->date[pos].addr);
printf("修改信息完成\n");
}
}
但是这样写代码不免显得我们不是很nb,直接替换所有的内容,这样也会让一些本来就不用修改的信息又被修改了一遍,这太不专业了。
我们不妨先查找到需要修改人,然后先让用户查找到需要修改的这个人然后选择是修改什么信息,然后重新输入改后的信息,这个其实就和菜单选项实现很相似,我们需要利用枚举变量,跟do。。。while
enum Information
{
ERRO,
NAME,
AGE,
SEX,
TELE,
ADDR,
};
void Modifycontact(struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要修改联系人的姓名:>");
scanf("%s", name);
int pos = Find_by_name(ps, name);
if (pos == -1)
{
printf("要修改的联系人不存在\n");
}
else
{
int input = 0;
do
{
printf("请输入你想修改此用户的哪项信息\n");
printf(" 0.退出 1.姓名 2.年龄 3.性别 4.电话 5.地址:>\n");
scanf("%d", &input);
switch (input)
{
case NAME:
printf("情输入姓名:>");
scanf("%s", ps->date[pos].name);
break;
case AGE:
printf("情输入年龄:>");
scanf("%d", &(ps->date[pos].age));
break;
case SEX:
printf("情输入性别:>");
scanf("%s", ps->date[pos].sex);
break;
case TELE:
printf("情输入电话:>");
scanf("%s", ps->date[pos].tele);
break;
case ADDR:
printf("情输入地址:>");
scanf("%s", ps->date[pos].addr);
break;
case ERRO:
printf("修改完成\n");
break;
default:
printf("输入错误,请重新输入:>\n");
break;
}
} while (input);
}
}
值得注意的是
这里的第一个没有写EXIT,而是ERRO是因为我们第一次使用枚举的时候已经定义过EXIT了再次定义会有错误,重定义
效果如下
(7)排序通讯录
这一步如果单靠我们自己实现是很麻烦的,但是c语言的库函数里面右qsort,使用该库函数实现起来就非常的简单
int con_name(const void* e1, const void* e2)
{
return (strcmp(((struct contact*)e1)->date->name, ((struct contact*)e2)->date->name));
}//这里一定要记得强制类型转换
void SortContact(struct contact* ps)
{
assert(ps);
if (ps->size == 0)
{
printf("通讯录为空,无法排序\n");
return;
}
qsort(ps->date, ps->size, sizeof(ps->date[0]), con_name);
printf("排序成功\n");
Showcontact(ps);
}
重要的内容说三遍
再写con_name时要记得强制类型转换!
再写con_name时要记得强制类型转换!
再写con_name时要记得强制类型转换!
总结:
test.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
void menu()
{
printf("**************************************\n");
printf("***** 1.add 2.del *****\n");
printf("***** 3.search 4.modify *****\n");
printf("***** 5.show 6sort *****\n");
printf("***** 0.exit *****\n");
printf("**************************************\n");
}
int main()
{
int input = 0;
//创建结构体数组
struct contact con;
//初始化结构体数组
Initcon(&con);
do {
menu();
printf("请输入你的选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
Addcontact(&con);
break;
case DEL:
Delcontact(&con);
break;
case SEARCH:
Searchcontact(&con);
break;
case MODIFY:
Modifycontact(&con);
break;
case SHOW:
Showcontact(&con);
break;
case SORT:
SortContact(&con);
break;
case EXIT:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入:>\n");
break;
}
} while (input);
return 0;
}
contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"contact.h"
void Initcon(struct contact* ps)
{
assert(ps!=NULL);
memset(ps->date, 0, sizeof(ps->date));
ps->size = 0;
}
void Addcontact(struct contact* ps)
{
assert(ps != NULL);
if (ps->size == MAX)
{
printf("通讯录已满,无法再进行添加\n");
}
else
{
printf("情输入姓名:>");
scanf("%s", ps->date[ps->size].name);
printf("情输入年龄:>");
scanf("%d", &(ps->date[ps->size].age));
printf("情输入性别:>");
scanf("%s", ps->date[ps->size].sex);
printf("情输入电话:>");
scanf("%s", ps->date[ps->size].tele);
printf("情输入地址:>");
scanf("%s", ps->date[ps->size].addr);
ps->size++;
printf("录入信息完成\n");
}
}
void Showcontact(const struct contact* ps)
{
assert(ps != NULL);
int i = 0;
if (ps->size == 0)
{
printf("通讯录内容为空,无法打印\n");
}
else
{
for (i = 0; i < ps->size; i++)
{
printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
ps->date[i].name,
ps->date[i].age,
ps->date[i].sex,
ps->date[i].tele,
ps->date[i].addr);
}
}
}
static int Find_by_name(const struct contact* ps, char name[MAX_NAME])
{//static修饰可以使其函数仅可以再本。c生效
//避免了污染
assert(ps != NULL);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->date[i].name, name) == 0)
return i;
}
return -1;
}
void Delcontact(struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要删除联系人的姓名:>");
scanf("%s", name);
//查找
//找到返回pos下标
//找不到返回-1
int pos=Find_by_name(ps, name);
if (pos == -1)
{
printf("要删除的联系人不存在\n");
}
else
{
int j = 0;
for (j = pos; j <ps->size ; j++)//
//*******
{
ps->date[j] = ps->date[j + 1];
}
ps->size--;
printf("删除成功\n");
}
}
void Searchcontact(const struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要查找联系人的姓名:>");
scanf("%s", name);
int pos = Find_by_name(ps, name);
if (pos == -1)
{
printf("要查找的联系人不存在\n");
}
else
{
printf("信息如下:\n");
printf("%-20s\t%-3s\t%-5s\t%-12s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s\t%-3d\t%-5s\t%-12s\t%-20s\n",
ps->date[pos].name,
ps->date[pos].age,
ps->date[pos].sex,
ps->date[pos].tele,
ps->date[pos].addr);
}
}
//void Modifycontact(struct contact* ps)
//{
// assert(ps != NULL);
// char name[MAX_NAME];
// printf("请输入要修改联系人的姓名:>");
// scanf("%s", name);
// int pos = Find_by_name(ps, name);
// if (pos == -1)
// {
// printf("要修改的联系人不存在\n");
// }
// else
// {
// printf("情输入姓名:>");
// scanf("%s", ps->date[pos].name);
// printf("情输入年龄:>");
// scanf("%d", &(ps->date[pos].age));
// printf("情输入性别:>");
// scanf("%s", ps->date[pos].sex);
// printf("情输入电话:>");
// scanf("%s", ps->date[pos].tele);
// printf("情输入地址:>");
// scanf("%s", ps->date[pos].addr);
// printf("修改信息完成\n");
// }
//}
void Modifycontact(struct contact* ps)
{
assert(ps != NULL);
char name[MAX_NAME];
printf("请输入要修改联系人的姓名:>");
scanf("%s", name);
int pos = Find_by_name(ps, name);
if (pos == -1)
{
printf("要修改的联系人不存在\n");
}
else
{
int input = 0;
do
{
printf("请输入你想修改此用户的哪项信息\n");
printf(" 0.退出 1.姓名 2.年龄 3.性别 4.电话 5.地址:>\n");
scanf("%d", &input);
switch (input)
{
case NAME:
printf("情输入姓名:>");
scanf("%s", ps->date[pos].name);
break;
case AGE:
printf("情输入年龄:>");
scanf("%d", &(ps->date[pos].age));
break;
case SEX:
printf("情输入性别:>");
scanf("%s", ps->date[pos].sex);
break;
case TELE:
printf("情输入电话:>");
scanf("%s", ps->date[pos].tele);
break;
case ADDR:
printf("情输入地址:>");
scanf("%s", ps->date[pos].addr);
break;
case ERRO:
printf("修改完成\n");
break;
default:
printf("输入错误,请重新输入:>\n");
break;
}
} while (input);
}
}
int con_name(const void* e1, const void* e2)
{
return (strcmp(((struct contact*)e1)->date->name, ((struct contact*)e2)->date->name));
}
void SortContact(struct contact* ps)
{
assert(ps);
if (ps->size == 0)
{
printf("通讯录为空,无法排序\n");
return;
}
qsort(ps->date, ps->size, sizeof(ps->date[0]), con_name);
printf("排序成功\n");
Showcontact(ps);
}
contact.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
enum option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT,
};
enum Information
{
ERRO,
NAME,
AGE,
SEX,
TELE,
ADDR,
};
struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
struct contact
{
struct PeoInfo date[MAX];
int size;
};
void Initcon(struct contact* ps);
void Addcontact(struct contact* ps);
void Showcontact(const struct contact* ps);
void Delcontact(struct contact* ps);
void Searchcontact(const struct contact* ps);
void Modifycontact(struct contact* ps);