C语言实现通讯录(进阶版 - 动态内存管理)
上次我们实现了一个可以存储1000个人信息的静态版本的通讯录,那就会衍生出两个情况。
1.如果联系人信息很少的话,会造成很大的内存浪费
2.如果联系人超过1000个人,就无法进行存储
所以,我们需要把通讯录改成动态版本
提供方法:
1.添加联系人信息
2.删除指定联系人信息
3.查找指定联系人信息
4.修改指定联系人信息
5.显示所有联系人信息
6.清空所有联系人
7.以名字排序所有联系人
0.退出通讯录
通讯录实现
前言
这次写的会比较简略,可以对通讯录1.0版本进行参考
通讯录1.0
正文开始
一、通讯录菜单的实现
程序与用户的交互,需要一个菜单来进行引导,所以我们第一步先实现菜单
需要把菜单的功能列举出来让用户可以进行下一步操作
void mean()//菜单的实现
{
printf("*****************************************************************\n");
printf("********* 1.add 2.del ***********\n");
printf("********* 3.seek 4.mod ***********\n");
printf("********* 5.show 6.empty ***********\n");
printf("********* 7.sort 0.exit ***********\n");
printf("*****************************************************************\n");
}
二、main函数实现
第二步我们对主函数进行实现
int main()
{
int input = 0;
content ab; //定义通讯录变量ab
Initcontact(&ab); //初始化通讯录函数
do
{
mean();
printf("请选择->");
scanf("%d",&input);
switch (input)
{
case EXIT:
printf("退出通讯录\n");
break;
case ADD:
addcontact(&ab); //增加联系人信息函数
break;
case DEL:
delcontact(&ab); //删除联系人信息函数
break;
case SEEK:
seekcontact(&ab); //寻找联系人信息函数
break;
case MOD:
modcontact(&ab); //修改联系人信息函数
break;
case SHOW:
showcontact(&ab); //展示联系人信息函数
break;
case EMPTY:
emptycontact(&ab); //清空联系人信息函数
case SORT:
sortcontact(&ab); //排序联系人信息函数
break;
}
} while (input);
return 0;
}
将所有需要实现的情况都放在main,方便自己可以逻辑清晰的编写代码
三、枚举选项
一开始我们就用数字来编辑了菜单的选项,在这里需要用到枚举来实现菜单的选项,与主函数中的case进行对应
enum mean
{
EXIT,//0
ADD,//1
DEL,//2
SEEK,//3
MOD,//4
SHOW,//5
EMPTY,//6
SORT//7
};
运用枚举是为了让代码逻辑更加简洁易懂,提高代码的可维护性
四、定义通讯录内容以及联系人内容
这是个动态增长的版本,需要记录存放的数据,有效数据个数,默认数据个数
typedef struct message
{
char name[MIN_NAME];
char sex[MIN_SEX];
int age;
char number[MIN_NUMBER];
char address[MIN_ADDRESS];
}message;
typedef struct data
{
message* data; //用来保存通讯录存放的数据
int sz; //用来记录通讯录中有效数据的个数
int capcity; //用来记录通讯录默认数据个数
}content;
五、对全局变量进行声明
我们需要对通讯录内的数据做一定的限制,这里需要对全局变量做一些声明
#define MIN_NAME 15 //设置姓名数组中字符的个数
#define MIN_SEX 5 //设置性别数组中字符的个数
#define MIN_NUMBER 20 //设置号码数组中字符的个数
#define MIN_ADDRESS 18 //设置地址数组中字符的个数
#define FRINUM 3 //设置通讯录默认起始数据
六、通讯录功能的实现
我们已经拥有一个简易的通讯录了,现在需要对前文列举的功能进行一一实现
1.初始化通讯录
首先我们需要实现通讯录的保存功能,我们需要实现通讯录的初始化功能
//初始化通讯录函数
void Initcontact(content* ab)
{
assert(ab);
ab->sz = 0;
ab->capcity = FRINUM;
message* tmp = (message*)malloc(FRINUM*sizeof(message));
//判断tmp是否为空指针
if (tmp == NULL)
{
printf("Initcontact::%s\n",strerror(errno));
return;
}
ab->data = tmp; //动态的为指针ab开辟内存
return;
}
2.实现新增联系人(1.add)
//增加联系人函数
void addcontact(content* ab)
{
assert(ab);
capcityadd(ab); //增加通讯录的容量
printf("请输入联系人的姓名->");
scanf("%s",ab->data[ab->sz].name);
printf("请输入联系人的性别->");
scanf("%s",ab->data[ab->sz].sex);
printf("请输入联系人的年龄->");
scanf("%d",&(ab->data[ab->sz].age));
printf("请输入联系人的电话->");
scanf("%s",ab->data[ab->sz].number);
printf("请输入联系人的住址->");
scanf("%s",ab->data[ab->sz].address);
printf("增加联系人成功\n");
ab->sz++;
}
3.实现删除联系人(2.del)
//删除联系人函数
void delcontact(content* ab)
{
assert(ab);
char name[MIN_NAME] = {
0};
printf("请输入要删除联系人的姓名->");
scanf("%s", name);
int ret = seekname(name,ab); //查找姓名函数
if (ret == -1)
printf("没有该联系人\n");
else
{
for (i = ret; i < ab->sz; i++)
{
ab->data[i] = ab->data[i + 1];
}
printf("删除指定联系人成功\n");
ab->sz--; //注意这一一定要执行这一步,删除一个联系人以后通讯录中有效个数就应该减少1
}
return;
}
4.实现查找联系人(3.seek)
4.1.编写一个查找函数
为了使代码的可读性更高,功能更加齐全,我们需要编写一个通过姓名可以查找的功能
//查找姓名函数
int seekname(char* name, content* ab)
{
for (i = 0; i < ab->sz; i++)
{
if ((strcmp(name, ab->data[i].name)) == 0)
return i;
}
return -1;
}
4.2实现查找联系人
//寻找联系人函数
void seekcontact(content* ab)
{
assert(ab);
char name[MIN_NAME] = {
0 };
printf("请输入要查找联系人的姓名->");
scanf("%s", name);
int ret = seekname(name, ab); //查找姓名函数
if (ret == -1)
{
printf("没有该联系人\n");
return;
}
else
{
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[ret].name, ab->data[ret].sex, ab->data[ret].age, ab->data[ret].number, ab->data[ret].address);
}
return;
}
5.实现修改联系人(4.mod)
//修改联系人信息函数
void modcontact(content* ab)
{
assert(ab);
char name[MIN_NAME] = {
0 };
printf("请输入要查找联系人的姓名->");
scanf("%s", name);
int ret = seekname(name, ab); //查找姓名函数
if (ret == -1)
{
printf("没有该联系人\n");
return;
}
else
{
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[ret].name, ab->data[ret].sex, ab->data[ret].age, ab->data[ret].number, ab->data[ret].address);
}
printf("请输入修改信息\n");
printf("请输入联系人的姓名->");
scanf("%s", ab->data[ret].name);
printf("请输入联系人的性别->");
scanf("%s", ab->data[ret].sex);
printf("请输入联系人的年龄->");
scanf("%d", &(ab->data[ret].age));
printf("请输入联系人的电话->");
scanf("%s", ab->data[ret].number);
printf("请输入联系人的住址->");
scanf("%s", ab->data[ret].address);
printf("修改成功\n");
return;
}
6.实现展示联系人(5.show)
//展示联系人函数
void showcontact(content* ab)
{
//姓名、性别、年龄、电话、住址
assert(ab);
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n","姓名","性别", "年龄", "电话", "住址");
for (i = 0; i < ab->sz; i++)
{
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[i].name, ab->data[i].sex, ab->data[i].age, ab->data[i].number, ab->data[i].address);
}
return;
}
7.实现清空联系人(6.empty)
//清空联系人信息函数
void emptycontact(content* ab)
{
assert(ab);
printf("请确认是否要清空通讯录(Y/N):");
char str = 0;
while ((str = getchar()) != '\n')
{
;
}
scanf("%c", &str);
if (str == 'Y')
{
ab->data = 0;
ab->capcity = 0;
ab->sz = 0;
printf("全部清除成功\n");
}
return;
}
8.实现排序联系人信息(7.sort)
//排序联系人信息函数
void sortcontact(content* ab)
{
assert(ab);
qsort(ab->data,ab->sz,sizeof(ab->data[0]),compare);
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
for (i = 0; i < ab->sz; i++)
{
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[i].name, ab->data[i].sex, ab->data[i].age, ab->data[i].number, ab->data[i].address);
}
return;
}
9.代码总览
到这里进阶通讯录2.0已经全部完成了,下面就是程序的源代码
9.1 function.h
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define _CRT_SECURE_NO_WARNINGS
#define MIN_NAME 15 //设置姓名数组中字符的个数
#define MIN_SEX 5 //设置性别数组中字符的个数
#define MIN_NUMBER 20 //设置号码数组中字符的个数
#define MIN_ADDRESS 18 //设置地址数组中字符的个数
#define FRINUM 3 //设置通讯录默认起始数据
typedef struct message
{
char name[MIN_NAME];
char sex[MIN_SEX];
int age;
char number[MIN_NUMBER];
char address[MIN_ADDRESS];
}message;
typedef struct data
{
message* data; //用来保存通讯录存放的数据
int sz; //用来记录通讯录中有效数据的个数
int capcity; //用来记录通讯录默认数据个数
}content;
void Initcontact(content* ab); //初始化通讯录函数声明
void addcontact(content* ab); //增加联系人信息函数声明
void delcontact(content* ab); //删除联系人信息函数声明
void seekcontact(content* ab); //寻找联系人信息函数声明
void modcontact(content* ab); //修改联系人信息函数声明
void emptycontact(content* ab); //清空联系人信息函数声明
void showcontact(content* ab); //展示联系人信息函数声明
void sortcontact(content* ab); //排序联系人信息函数声明
9.2 main.c
#include "function.h"
//实现通讯录:通讯录可以用来存储1000个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址
//1.添加联系人信息
//2.删除指定联系人信息
//3.查找指定联系人信息
//4.修改指定联系人信息
//5.显示所有联系人信息
//6.清空所有联系人
//7.以名字排序所有联系人
enum number
{
EXIT,
ADD,
DEL,
SEEK,
MOD,
SHOW,
EMPTY,
SORT
};
void mean()
{
printf("*****************************************************************\n");
printf("********* 1.add 2.del ***********\n");
printf("********* 3.seek 4.mod ***********\n");
printf("********* 5.show 6.empty ***********\n");
printf("********* 7.sort 0.exit ***********\n");
printf("*****************************************************************\n");
}
int main()
{
int input = 0;
content ab; //定义通讯录变量ab
Initcontact(&ab); //初始化通讯录函数
do
{
mean();
printf("请选择->");
scanf("%d",&input);
switch (input)
{
case EXIT:
printf("退出通讯录\n");
break;
case ADD:
addcontact(&ab); //增加联系人信息函数
break;
case DEL:
delcontact(&ab); //删除联系人信息函数
break;
case SEEK:
seekcontact(&ab); //寻找联系人信息函数
break;
case MOD:
modcontact(&ab); //修改联系人信息函数
break;
case SHOW:
showcontact(&ab); //展示联系人信息函数
break;
case EMPTY:
emptycontact(&ab); //清空联系人信息函数
case SORT:
sortcontact(&ab); //排序联系人信息函数
break;
}
} while (input);
return 0;
}
9.3 function.c
#include "function.h"
int i = 0; //全局变量i
//排序里面的比较函数
int compare(const void* e1, const void* e2)
{
return strcmp(((message*)e1)->name, ((message*)e2)->name);
}
//增加通讯录容量函数
void capcityadd(content* ab)
{
if (ab->sz == ab->capcity)
{
message* tmp = (message*)realloc(ab->data, (ab->capcity + 2) * sizeof(message)); //注意这里的结构体,不要引错了
if (tmp != NULL)
{
ab->data = tmp;
ab->capcity += 2;
printf("增加容量成功\n");
}
else
{
printf("addcontact::%s\n", strerror(errno));
}
}
}
//查找姓名函数
int seekname(char* name, content* ab)
{
for (i = 0; i < ab->sz; i++)
{
if ((strcmp(name, ab->data[i].name)) == 0)
return i;
}
return -1;
}
//初始化通讯录函数
void Initcontact(content* ab)
{
assert(ab);
ab->sz = 0;
ab->capcity = FRINUM;
message* tmp = (message*)malloc(FRINUM*sizeof(message));
//判断tmp是否为空指针
if (tmp == NULL)
{
printf("Initcontact::%s\n",strerror(errno));
return;
}
ab->data = tmp; //动态的为指针ab开辟内存
return;
}
//增加联系人函数
void addcontact(content* ab)
{
assert(ab);
capcityadd(ab); //增加通讯录的容量
printf("请输入联系人的姓名->");
scanf("%s",ab->data[ab->sz].name);
printf("请输入联系人的性别->");
scanf("%s",ab->data[ab->sz].sex);
printf("请输入联系人的年龄->");
scanf("%d",&(ab->data[ab->sz].age));
printf("请输入联系人的电话->");
scanf("%s",ab->data[ab->sz].number);
printf("请输入联系人的住址->");
scanf("%s",ab->data[ab->sz].address);
printf("增加联系人成功\n");
ab->sz++;
}
//删除联系人函数
void delcontact(content* ab)
{
assert(ab);
char name[MIN_NAME] = {
0};
printf("请输入要删除联系人的姓名->");
scanf("%s", name);
int ret = seekname(name,ab); //查找姓名函数
if (ret == -1)
printf("没有该联系人\n");
else
{
for (i = ret; i < ab->sz; i++)
{
ab->data[i] = ab->data[i + 1];
}
printf("删除指定联系人成功\n");
ab->sz--; //注意这一一定要执行这一步,删除一个联系人以后通讯录中有效个数就应该减少1
}
return;
}
//寻找联系人函数
void seekcontact(content* ab)
{
assert(ab);
char name[MIN_NAME] = {
0 };
printf("请输入要查找联系人的姓名->");
scanf("%s", name);
int ret = seekname(name, ab); //查找姓名函数
if (ret == -1)
{
printf("没有该联系人\n");
return;
}
else
{
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[ret].name, ab->data[ret].sex, ab->data[ret].age, ab->data[ret].number, ab->data[ret].address);
}
return;
}
//修改联系人信息函数
void modcontact(content* ab)
{
assert(ab);
char name[MIN_NAME] = {
0 };
printf("请输入要查找联系人的姓名->");
scanf("%s", name);
int ret = seekname(name, ab); //查找姓名函数
if (ret == -1)
{
printf("没有该联系人\n");
return;
}
else
{
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[ret].name, ab->data[ret].sex, ab->data[ret].age, ab->data[ret].number, ab->data[ret].address);
}
printf("请输入修改信息\n");
printf("请输入联系人的姓名->");
scanf("%s", ab->data[ret].name);
printf("请输入联系人的性别->");
scanf("%s", ab->data[ret].sex);
printf("请输入联系人的年龄->");
scanf("%d", &(ab->data[ret].age));
printf("请输入联系人的电话->");
scanf("%s", ab->data[ret].number);
printf("请输入联系人的住址->");
scanf("%s", ab->data[ret].address);
printf("修改成功\n");
return;
}
//清空联系人信息函数
void emptycontact(content* ab)
{
assert(ab);
printf("请确认是否要清空通讯录(Y/N):");
char str = 0;
while ((str = getchar()) != '\n')
{
;
}
scanf("%c", &str);
if (str == 'Y')
{
ab->data = 0;
ab->capcity = 0;
ab->sz = 0;
printf("全部清除成功\n");
}
return;
}
//展示联系人函数
void showcontact(content* ab)
{
//姓名、性别、年龄、电话、住址
assert(ab);
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n","姓名","性别", "年龄", "电话", "住址");
for (i = 0; i < ab->sz; i++)
{
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[i].name, ab->data[i].sex, ab->data[i].age, ab->data[i].number, ab->data[i].address);
}
return;
}
//排序联系人信息函数
void sortcontact(content* ab)
{
assert(ab);
qsort(ab->data,ab->sz,sizeof(ab->data[0]),compare);
printf("%-7s\t%-5s\t%-5s\t%-15s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");
for (i = 0; i < ab->sz; i++)
{
printf("%-7s\t%-5s\t%-5d\t%-15s\t%-20s\n",
ab->data[i].name, ab->data[i].sex, ab->data[i].age, ab->data[i].number, ab->data[i].address);
}
return;
}