在通讯录中, 可以做到基本的增删查改,也可以实现通讯录自动扩容,也可以将输入的联系人的信息保存到文件当中,不会因为程序的退出而内存销毁,而是保存到文件当中,因此在下次打开程序时,也可以将文件保存的联系人的信息读取出来,真正的做到了通讯录保存的功能
添加联系人:
排序+显示联系人:
查找联系人:
更改联系人的信息:
删除信息人:
当删除李华时,我们再将通讯录打印出来,就可以看到李华的信息已经被删除了
退出程序:
再次打开程序时,之前输入的联系人的信息也能够保存下来:
我会在文章的后面将原代码贴上:contact.h contact.c test.c
码字不易,如有用,望诸君点赞收藏一波!
一、通讯录的基本:
用到的头文件:
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
define的常量:
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_NUM 17
#define MAX_ADDR 30
#define MAX 3
#define Add_MAX 2
结构体定义联系人的基本信息:姓名、性别、年龄、电话号码、家庭住址
typedef struct PeoInfo
{
char name[MAX_NAME];
char sex[MAX_SEX];
int age;
char num[MAX_NUM];
char addr[MAX_ADDR];
}PeoInfo;
通讯录的基本要素:
typedef struct Contact
{
PeoInfo* data;//一个指向联系人类型空间的指针
int sz;//记录通讯录里的人数
int num;//记录通讯录空间的大小
}Contact;
二、初始化通讯录
在初始化通讯的时候,开始时用calloc在内存中定义一处空间,当要读取上一次写的通讯录的信息是,首先要判断通讯录是否满了,当程序发现通讯满了的时候,要用realloc将空间扩大,做到了通讯录的自动增容
void AddCapacity(Contact* pc);
//读取原来的文件
void ReadContact(Contact* pc)
{
//打开文件
FILE* ps = fopen("Contact.txt", "rb");
if (ps == NULL)
{
perror("ReadContact");
return;
}
//读文件
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, ps)) //fread的正常是返回值为读取的个数,异常时是比读取个数小,这里读取个数是是1,异常时会返回0,while结束
{
if (pc->sz == pc->num)
{
AddCapacity(pc);
}
pc->data[pc->sz] = tmp;
pc->sz++;
}
//关闭文件
fclose(ps);
ps = NULL;
}
//动态初始化通讯录
void IniContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->num = MAX;
pc->data = (PeoInfo*)calloc(pc->num, sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("IniContact->calloc");
return;
}
ReadContact(pc);
}
//增容通讯录
void AddCapacity(Contact* pc)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->num + Add_MAX) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("realloc");
return 1;
}
else
{
pc->data = ptr;
pc->num += Add_MAX;
//printf("增容成功\n");
}
}
三、 增加联系人
很容易实现,代码如下:
//增加联系人
void AddContact(Contact* pc)
{
assert(pc);
//判断通讯录是否满了
if (pc->sz == pc->num)
{
AddCapacity(pc);
}
printf("请输入姓名:\n");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:\n");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:\n");
scanf("%s", pc->data[pc->sz].num);
printf("请输入地址:\n");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功!\n");
}
四、显示联系人
就是将来联系人的信息打印出来
代码如下:
//显示联系人
void ShowContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("没有联系人,请添加联系人\n");
}
else
{
int i = 0;
printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n",
pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].num, pc->data[i].addr);
}
}
}
五、删除联系人
在删除联系人的时候,首先要查找到想要删除的联系人所在数组的坐标,因此我包装了一个函数FindPeople,专门查找联系人,返回所查找的联系人的坐标。
当拿到要删除的联系人的位置后,只需将后一个人的联系人的信息覆盖要删除的联系人的信息,然后将记录通讯录里联系人数量的 sz--,这样,如果想要删除最后一名联系人的时候,即使最后一个联系人的信息没办法覆盖,但是我们已经无法读取最后一个联系人的信息(因为sz已经减1了),因此也变相的完成的删除。
//查找人
int FindPeople(Contact* pc, char* name)
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name, pc->data[i].name) == 0)
return i;
}
return -1;
}
//删除联系人
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,请添加联系人\n");
return;
}
printf("请输入要删除的姓名:\n");
char name[MAX_NAME];
scanf("%s", name);
int ret = FindPeople(pc, name);
if (ret == -1)
{
printf("查无此人\n");
return;
}
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功!\n");
}
六、查找联系人
这个功能也是很简单,首先也要找到想要查找联系人的位置,因此也要用到FindPeople函数,找到联系人的坐标,将其打印在屏幕上就可以了
代码如下:
//查找联系人
void SearchContact(Contact* pc)
{
char name[MAX_NAME];
assert(pc);
printf("请输入要查找的姓名:\n");
scanf("%s", name);
int ret = FindPeople(pc, name);
printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n",
pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].num, pc->data[ret].addr);
}
七、更改联系人
在实现更改联系人这一功能时,也是首先将联系人的位置找到,重新输入联系人的信息即可
代码如下:
//更改联系人
void ModifyContact(Contact* pc)
{
char name[MAX_NAME];
assert(pc);
printf("请输入想要更改联系人的名字:\n");
scanf("%s", name);
int ret = FindPeople(pc, name);
if (ret == -1)
{
printf("查无此人!\n");
return;
}
printf("请输入重新更改的姓名:\n");
scanf("%s", pc->data[ret].name);
printf("请输入重新更改的性别:\n");
scanf("%s", pc->data[ret].sex);
printf("请输入重新更改的年龄:\n");
scanf("%d", &(pc->data[ret].age));
printf("请输入重新更改的电话:\n");
scanf("%s", pc->data[ret].num);
printf("请输入重新更改的地址:\n");
scanf("%s", pc->data[ret].addr);
printf("更改联系人成功!\n");
}
八、排序联系人
排序联系人时,需要用到qsort函数,我们可以设定排序的方式,比如:姓名、年龄、性别、电话,这些都是可以的,在这里我用的是以名字将通讯录排序的
代码如下:
//排序比较大小
int cmp(const void* e1, const void* e2)
{
return strcmp(( * (PeoInfo*)e1).name, ( * (PeoInfo*)e2).name);
}
//排序联系人
void SortContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空!\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
printf("排序成功!\n");
}
九、保存联系人
想要做到在程序退出前面,将所增加的联系人的信息写入文件 Contact.txt 当中去,
代码如下;
//保存通讯录
void ServeContact(Contact* pc)
{
//打开文件
FILE* ps = fopen("Contact.txt", "wb");
if (ps == NULL)
{
perror("ServeContact");
return;
}
//写文件
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, ps);
}
//关闭文件
fclose(ps);
ps = NULL;
}
十、销毁通讯录
因为通讯录是通过realloc、calloc动态开辟在堆区的,因此,在程序退出的时候,需要手动的将所申请的内存空间释放掉,不然可能会造成内存泄漏。
代码如下:
//销毁通讯录
void DestoryContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->sz = 0;
pc->num = 0;
}
———————————————————————————————————————————
源码:
contact.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_NUM 17
#define MAX_ADDR 30
#define MAX 3
#define Add_MAX 2
typedef struct PeoInfo
{
char name[MAX_NAME];
char sex[MAX_SEX];
int age;
char num[MAX_NUM];
char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact
{
PeoInfo* data;//一个指向联系人类型空间的指针
int sz;//记录通讯录里的人数
int num;//记录通讯录空间的大小
}Contact;
//初始化通讯录
void IniContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//显示联系人
void ShowContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
void SearchContact(Contact* pc);
//更改联系人
void ModifyContact(Contact* pc);
//排序联系人
void SortContact(Contact* pc);
//销毁通讯录
void DestoryContact(Contact* pc);
//保存通讯录
void ServeContact(Contact* pc);
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
//静态初始化通讯录
//void IniContact(Contact* pc)
//{
// assert(pc);
// pc->sz = 0;
// memset(pc->data, 0, sizeof(pc->data));
//}
void AddCapacity(Contact* pc);
//读取原来的文件
void ReadContact(Contact* pc)
{
//打开文件
FILE* ps = fopen("Contact.txt", "rb");
if (ps == NULL)
{
perror("ReadContact");
return;
}
//读文件
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, ps)) //fread的正常是返回值为读取的个数,异常时是比读取个数小,这里读取个数是是1,异常时会返回0,while结束
{
if (pc->sz == pc->num)
{
AddCapacity(pc);
}
pc->data[pc->sz] = tmp;
pc->sz++;
}
//关闭文件
fclose(ps);
ps = NULL;
}
//动态初始化通讯录
void IniContact(Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->num = MAX;
pc->data = (PeoInfo*)calloc(pc->num, sizeof(PeoInfo));
if (pc->data == NULL)
{
perror("IniContact->calloc");
return;
}
ReadContact(pc);
}
//增容通讯录
void AddCapacity(Contact* pc)
{
PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->num + Add_MAX) * sizeof(PeoInfo));
if (ptr == NULL)
{
perror("realloc");
return 1;
}
else
{
pc->data = ptr;
pc->num += Add_MAX;
//printf("增容成功\n");
}
}
//增加联系人
void AddContact(Contact* pc)
{
assert(pc);
//判断通讯录是否满了
if (pc->sz == pc->num)
{
AddCapacity(pc);
}
printf("请输入姓名:\n");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:\n");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入年龄:\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话:\n");
scanf("%s", pc->data[pc->sz].num);
printf("请输入地址:\n");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功!\n");
}
//显示联系人
void ShowContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("没有联系人,请添加联系人\n");
}
else
{
int i = 0;
printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
for (i = 0; i < pc->sz; i++)
{
printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n",
pc->data[i].name, pc->data[i].sex, pc->data[i].age, pc->data[i].num, pc->data[i].addr);
}
}
}
//查找人
int FindPeople(Contact* pc, char* name)
{
assert(pc);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(name, pc->data[i].name) == 0)
return i;
}
return -1;
}
//删除联系人
void DelContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空,请添加联系人\n");
return;
}
printf("请输入要删除的姓名:\n");
char name[MAX_NAME];
scanf("%s", name);
int ret = FindPeople(pc, name);
if (ret == -1)
{
printf("查无此人\n");
return;
}
int i = 0;
for (i = ret; i < pc->sz - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->sz--;
printf("删除成功!\n");
}
//查找联系人
void SearchContact(Contact* pc)
{
char name[MAX_NAME];
assert(pc);
printf("请输入要查找的姓名:\n");
scanf("%s", name);
int ret = FindPeople(pc, name);
printf("%-7s\t%-7s\t%-6s\t%-15s\t%-20s\t\n", "姓名", "性别", "年龄", "电话号码", "家庭地址");
printf("%-7s\t%-7s\t%-6d\t%-15s\t%-20s\t\n",
pc->data[ret].name, pc->data[ret].sex, pc->data[ret].age, pc->data[ret].num, pc->data[ret].addr);
}
//更改联系人
void ModifyContact(Contact* pc)
{
char name[MAX_NAME];
assert(pc);
printf("请输入想要更改联系人的名字:\n");
scanf("%s", name);
int ret = FindPeople(pc, name);
if (ret == -1)
{
printf("查无此人!\n");
return;
}
printf("请输入重新更改的姓名:\n");
scanf("%s", pc->data[ret].name);
printf("请输入重新更改的性别:\n");
scanf("%s", pc->data[ret].sex);
printf("请输入重新更改的年龄:\n");
scanf("%d", &(pc->data[ret].age));
printf("请输入重新更改的电话:\n");
scanf("%s", pc->data[ret].num);
printf("请输入重新更改的地址:\n");
scanf("%s", pc->data[ret].addr);
printf("更改联系人成功!\n");
}
//排序比较大小
int cmp(const void* e1, const void* e2)
{
return strcmp(( * (PeoInfo*)e1).name, ( * (PeoInfo*)e2).name);
}
//排序联系人
void SortContact(Contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空!\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
printf("排序成功!\n");
}
//销毁通讯录
void DestoryContact(Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->sz = 0;
pc->num = 0;
}
//保存通讯录
void ServeContact(Contact* pc)
{
//打开文件
FILE* ps = fopen("Contact.txt", "wb");
if (ps == NULL)
{
perror("ServeContact");
return;
}
//写文件
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, ps);
}
//关闭文件
fclose(ps);
ps = NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
printf("*******************************\n");
printf("**** 1.Add 2.Del ****\n");
printf("**** 3.Search 4.Modify ****\n");
printf("**** 5.Sort 6.Show ****\n");
printf("**** 0.Exit ****\n");
printf("*******************************\n");
}
enum Select
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
SHOW
};
int main()
{
int input = 0;
Contact pc;
//初始化通讯录
IniContact(&pc);
do
{
menu();
printf("请输入你的选择:\n");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&pc);
break;
case DEL:
DelContact(&pc);
break;
case SEARCH:
SearchContact(&pc);
break;
case MODIFY:
ModifyContact(&pc);
break;
case SORT:
SortContact(&pc);
break;
case SHOW:
ShowContact(&pc);
break;
case EXIT:
ServeContact(&pc);
printf("退出程序\n");
DestoryContact(&pc);
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
} while (input);
return 0;
}