[C/C++]c语言实现简单通讯录(动态内存)

7 篇文章 0 订阅
4 篇文章 0 订阅

设计目标:写一个通讯录,每个人的信息包括:1.名字,2.年龄,3.性别,4.电话,5.住址

                                            //功能:1. 增加一个人的信息
                                                         2. 删除一个指定的联系人
                                                        3. 查找一个指定的联系人
                                                        4. 修改一个指定的联系人
                                                        5. 显示通讯录中所有人的信息
                                                        6. 保存

                                                        7.销毁
                                                        0. 退出

静态版本 - 一次开辟1000个元素的连续空间

文件的版本 - 数据可以存储到文件中,不至于丢失,动态增长 - 按需开辟

成果图:增加: 

查找:  

删除:  

 保存:

销毁,展示:

1.通过结构保存个人信息和通讯录(静态动态两种建立方法)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>

#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELL_MAX 12
#define ADDRESS_MAX 30

#define CAPACITY_SZ 3

typedef struct Personal		//个人信息结构体
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tell[TELL_MAX];
	char address[ADDRESS_MAX];
}Persona;

//struct Contact		//通讯录静态
//{
//    Persona data[MAX];		//每创建一个就包含1000个 个人
//	int sz;
//};

struct Contact		//通讯录
{
	Persona *data;
	int sz;
	int capacity;		//最大容量
};

2.主函数:逻辑是创建通讯录--->初始化--->菜单--->功能,这里用枚举代替数字选择方便调试,更加直观。

enum Features
{
	Exit = 0,
	add,
	del,
	find,
	mod,
	show,
	save,
	Destroy,
};

void menu()
{
	printf("*****************************\n");
	printf("****1.add  ****2.  del ******\n");
	printf("****3.find ****4.  mod ******\n");
	printf("****5.show ****6. save ******\n");
	printf("****0.exit ****7. Dest******\n");
	printf("*****************************\n");
	printf("请选择--->");
}

int main()
{
	int input = 0;
	struct Contact Con;		//创建一个通讯录

	Initialize(&Con);			//初始化
	do
	{
		menu();
		scanf("%d", &input);

		switch (input)
		{
			case add:
				addContacts(&Con);
				break;
			case del:
				delContacts(&Con);
				break;
			case find:
				findContacts(&Con);
				break;
			case mod:
				modContacts(&Con);
				break;
			case show:
				showContacts(&Con);
				break;
			case save:
				saveContacts(&Con);
				break;
			case Destroy:
				DestroyContacts(&Con);
				break;
			case Exit:
				break;
			default:
				printf("输入错误,请重新输入\n");
				break;
		}
	} while (input);
	return 0;
}

3.初始化函数,给出两个版本(静态,动态)

//void Initialize(struct Contact * Con)  //静态
//{
//	Con->sz = 0;
//	memset(Con->data, 0, sizeof(Con->data));		//void *memset(void *s, int ch, size_t n);将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
//}


void Initialize(struct Contact* Con)		//动态版本初始化
{
	Con->sz = 0;
	Con->capacity = CAPACITY_SZ;
	Con->data = (struct PeoInfo*)malloc(CAPACITY_SZ * sizeof(struct Personal)); // void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的无类型指针。所以强制类型转换
	if (Con->data == NULL)
	{
		printf("初始化失败\n");
		exit(1);		//exit(1)表示异常退出
	}
	LoadContact(Con);		//读取文件中已有的
}

4.读取文件,动态初始化函数用到

void LoadContact(struct Contact* Con)		//读取文件中已经有的
{
	FILE* puin = fopen("contact.dat","rb");		//打开文件,二进制读
	if (puin == NULL)
	{
		printf("打开失败\n");
		return;
	}
	Persona tmp = { 0 };			//相当于中间变量
	while (fread(&tmp, sizeof(Persona), 1, puin))		//取出一个单位的内容到tmp的地址中
	{
		if (Expansion(Con) == 0)		//相当于增加,所以要判断容量
		{
			printf("容量不足且扩容失败\n");
			return;
		}
		Con->data[Con->sz] = tmp;			//当前位置的值
		Con->sz++;
	}
	fclose(puin);					//读完关闭文件,并将指针滞空
	puin = NULL;
}

5.增加函数,先判断是否需要扩容

void addContacts(struct Contact * Con)				//增加
{
	if (Expansion(Con) == 0)
	{
		printf("容量不足且扩容失败\n");
		return;
	}

	printf("请输入姓名:");
	scanf("%s", &(Con->data[Con->sz].name));
	printf("请输入年龄:");
	scanf("%d", &(Con->data[Con->sz].age));
	printf("请输入性别:");
	scanf("%s", &(Con->data[Con->sz].sex));
	printf("请输入电话:");
	scanf("%s", &(Con->data[Con->sz].tell));
	printf("请输入地址:");
	scanf("%s", &(Con->data[Con->sz].address));
	printf("保存成功\n");
	(Con->sz)++;
}

6.扩容函数,增加函数中用到

int Expansion(struct Contact* Con)		//扩容函数
{
	if (Con->sz == Con->capacity)			//满了才扩
	{
		//(起始地址,包含以前的大小的总大小所以是3+2)
		struct PeoInfo* ptr = (struct PeoInfo*)realloc(Con->data, (Con->capacity + 2) * sizeof(struct Personal));
		if (ptr == NULL)
		{
			printf("扩容失败\n");
			return 0;
		}
		else
		{
			Con->data = ptr;
			Con->capacity += 2;
			printf("扩容成功\n");
			return 1;
		}
	}
	return 1;
}

7.展示函数,先判断是否为空。

void showContacts(struct Contact* pc)
{
	int i = 0;
	if ((pc->sz) == 0)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		//%-20s -靠左,占20位  \t属于转义字符。是水平制表符
		while (i < (pc->sz))			//从0向上加
		{
			printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", 
				pc->data[i].name, 
				pc->data[i].age,
				pc->data[i].sex,
				pc->data[i].tell,
				pc->data[i].address);
			i++;
		}
	}
}

8.修改函数

void modContacts(struct Contact* Con)			//修改
{
	char name[NAME_MAX];
	if (Con->sz == 0)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("请输入需要修改人的姓名:>");
		scanf("%s", &name);
		int ret = FindName(name, Con);		//这里Con本身就是指针变量,不能再取地址
		if (ret == -1)
		{
			printf("不存在\n");
		}
		else
		{
			printf("请输入姓名:");
			scanf("%s", &(Con->data[ret].name));
			printf("请输入年龄:");
			scanf("%d", &(Con->data[ret].age));
			printf("请输入性别:");
			scanf("%s", &(Con->data[ret].sex));
			printf("请输入电话:");
			scanf("%s", &(Con->data[ret].tell));
			printf("请输入地址:");
			scanf("%s", &(Con->data[ret].address));
			printf("修改成功\n");
		}
	}
}

9.寻找名字对应的行数,修改中使用

static int FindName(char name[NAME_MAX],const struct Contact* Con)			//寻找名字对应的行数,全局变量
{
	int i = 0;
	for (i = 0; i < Con->sz; i++)
	{
		//只能用strcmp判断完全相同,STRSTR不可
		if (strcmp((Con->data[i].name), name) == 0)
		{
			return i;
		}
	}
	return -1;

}

10.查找函数

void findContacts(struct Contact* Con)			//查找
{
	char name[NAME_MAX];
	if (Con->sz == 0)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("请输入需要查找人的姓名:>");
		scanf("%s", &name);
		int ret = FindName(name, Con);		//这里Con本身就是指针变量,不能再取地址
		if (ret == -1)
		{
			printf("查无此人\n");
		}
		else
		{
			printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
			printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",
				Con->data[ret].name,
				Con->data[ret].age,
				Con->data[ret].sex,
				Con->data[ret].tell,
				Con->data[ret].address);
		}
	}
}

11.删除函数

void delContacts(struct Contact* Con)
{
	char name[NAME_MAX];

	if (Con->sz == 0)
	{
		printf("通讯录为空,没法删除\n");
	}
	else
	{
		printf("请输入需要删除人的姓名:>");
		scanf("%s", &name);
		int ret = FindName(name, Con);
		if (ret == -1)
		{
			printf("查无此人\n");
		}
		else
		{
			int j = 0;
			for (j = ret; j < (Con->sz - 1); j++)		//向前挪一个
			{
				Con->data[j] = Con->data[j + 1];
			}
			Con->sz--;			//总数减一
			printf("删除成功\n");
		}
	}
}

12.保存文件,也可使用其他保存类型

void saveContacts(struct Contact* Con)
{
	FILE* pout = fopen("contact.dat", "wb");		//打开文件,二进制写
	if (pout == NULL)
	{
		printf("打开失败\n");
		return;
	}

	for (int i = 0; i < Con->sz; i++)
	{
		fwrite(Con->data + i, sizeof(Persona), 1, pout);
	}
	printf("保存成功\n");
	fclose(pout);
	pout = 0;
}

13.销毁函数,释放空间后,指针要滞空

void DestroyContacts(struct Contact* Con)
{
	free(Con->data);
	Con->data = NULL;		//释放空间后要滞空
	Con->capacity = 0;
	Con->sz = 0;
	printf("销毁成功\n");		//已经销毁
}

 

 

下面给出完整代码:

1.Contacts.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>

#define MAX 1000
#define NAME_MAX 20
#define SEX_MAX 5
#define TELL_MAX 12
#define ADDRESS_MAX 30

#define CAPACITY_SZ 3

typedef struct Personal		//个人信息结构体
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tell[TELL_MAX];
	char address[ADDRESS_MAX];
}Persona;

//struct Contact		//通讯录
//{
//    Persona data[MAX];		//每创建一个就包含1000个 个人
//	int sz;
//};

struct Contact		//通讯录
{
	Persona *data;
	int sz;
	int capacity;		//最大容量
};

void addContacts(struct Contact* Con);			//增加

void Initialize(struct Contact* Con);			//初始化函数

void delContacts(struct Contact* Con);			//删除

void modContacts(struct Contact* Con);			//修改

void showContacts(struct Contact* Con);			//展示

void findContacts(struct Contact* Con);			//查找

void DestroyContacts(struct Contact* Con);	//销毁

2.fun.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contacts.h"

//void Initialize(struct Contact * Con)
//{
//	Con->sz = 0;
//	memset(Con->data, 0, sizeof(Con->data));		//void *memset(void *s, int ch, size_t n);将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
//}

int Expansion(struct Contact* Con)		//扩容函数
{
	if (Con->sz == Con->capacity)			//满了才扩
	{
		//(起始地址,包含以前的大小的总大小所以是3+2)
		struct PeoInfo* ptr = (struct PeoInfo*)realloc(Con->data, (Con->capacity + 2) * sizeof(struct Personal));
		if (ptr == NULL)
		{
			printf("扩容失败\n");
			return 0;
		}
		else
		{
			Con->data = ptr;
			Con->capacity += 2;
			printf("扩容成功\n");
			return 1;
		}
	}
	return 1;
}

void LoadContact(struct Contact* Con)		//读取文件中已经有的
{
	FILE* puin = fopen("contact.dat","rb");		//打开文件,二进制读
	if (puin == NULL)
	{
		printf("打开失败\n");
		return;
	}
	Persona tmp = { 0 };			//相当于中间变量
	while (fread(&tmp, sizeof(Persona), 1, puin))		//取出一个单位的内容到tmp的地址中
	{
		if (Expansion(Con) == 0)		//相当于增加,所以要判断容量
		{
			printf("容量不足且扩容失败\n");
			return;
		}
		Con->data[Con->sz] = tmp;			//当前位置的值
		Con->sz++;
	}
	fclose(puin);					//读完关闭文件,并将指针滞空
	puin = NULL;
}

void Initialize(struct Contact* Con)		//动态版本初始化
{
	Con->sz = 0;
	Con->capacity = CAPACITY_SZ;
	Con->data = (struct PeoInfo*)malloc(CAPACITY_SZ * sizeof(struct Personal)); // void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的无类型指针。所以强制类型转换
	if (Con->data == NULL)
	{
		printf("初始化失败\n");
		exit(1);		//exit(1)表示异常退出
	}
	LoadContact(Con);		//读取文件中已有的
}
void addContacts(struct Contact * Con)				//增加
{
	if (Expansion(Con) == 0)
	{
		printf("容量不足且扩容失败\n");
		return;
	}

	printf("请输入姓名:");
	scanf("%s", &(Con->data[Con->sz].name));
	printf("请输入年龄:");
	scanf("%d", &(Con->data[Con->sz].age));
	printf("请输入性别:");
	scanf("%s", &(Con->data[Con->sz].sex));
	printf("请输入电话:");
	scanf("%s", &(Con->data[Con->sz].tell));
	printf("请输入地址:");
	scanf("%s", &(Con->data[Con->sz].address));
	printf("保存成功\n");
	(Con->sz)++;
}

void showContacts(struct Contact* pc)
{
	int i = 0;
	if ((pc->sz) == 0)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		//%-20s -靠左,占20位  \t属于转义字符。是水平制表符
		while (i < (pc->sz))			//从0向上加
		{
			printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", 
				pc->data[i].name, 
				pc->data[i].age,
				pc->data[i].sex,
				pc->data[i].tell,
				pc->data[i].address);
			i++;
		}
	}
}

static int FindName(char name[NAME_MAX],const struct Contact* Con)			//寻找名字对应的行数,全局变量
{
	int i = 0;
	for (i = 0; i < Con->sz; i++)
	{
		//只能用strcmp判断完全相同,STRSTR不可
		if (strcmp((Con->data[i].name), name) == 0)
		{
			return i;
		}
	}
	return -1;

}

void modContacts(struct Contact* Con)			//修改
{
	char name[NAME_MAX];
	if (Con->sz == 0)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("请输入需要修改人的姓名:>");
		scanf("%s", &name);
		int ret = FindName(name, Con);		//这里Con本身就是指针变量,不能再取地址
		if (ret == -1)
		{
			printf("不存在\n");
		}
		else
		{
			printf("请输入姓名:");
			scanf("%s", &(Con->data[ret].name));
			printf("请输入年龄:");
			scanf("%d", &(Con->data[ret].age));
			printf("请输入性别:");
			scanf("%s", &(Con->data[ret].sex));
			printf("请输入电话:");
			scanf("%s", &(Con->data[ret].tell));
			printf("请输入地址:");
			scanf("%s", &(Con->data[ret].address));
			printf("修改成功\n");
		}
	}
}

void findContacts(struct Contact* Con)			//查找
{
	char name[NAME_MAX];
	if (Con->sz == 0)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("请输入需要查找人的姓名:>");
		scanf("%s", &name);
		int ret = FindName(name, Con);		//这里Con本身就是指针变量,不能再取地址
		if (ret == -1)
		{
			printf("查无此人\n");
		}
		else
		{
			printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
			printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n",
				Con->data[ret].name,
				Con->data[ret].age,
				Con->data[ret].sex,
				Con->data[ret].tell,
				Con->data[ret].address);
		}
	}
}

void delContacts(struct Contact* Con)
{
	char name[NAME_MAX];

	if (Con->sz == 0)
	{
		printf("通讯录为空,没法删除\n");
	}
	else
	{
		printf("请输入需要删除人的姓名:>");
		scanf("%s", &name);
		int ret = FindName(name, Con);
		if (ret == -1)
		{
			printf("查无此人\n");
		}
		else
		{
			int j = 0;
			for (j = ret; j < (Con->sz - 1); j++)		//向前挪一个
			{
				Con->data[j] = Con->data[j + 1];
			}
			Con->sz--;			//总数减一
			printf("删除成功\n");
		}
	}
}

void saveContacts(struct Contact* Con)
{
	FILE* pout = fopen("contact.dat", "wb");		//打开文件,二进制写
	if (pout == NULL)
	{
		printf("打开失败\n");
		return;
	}

	for (int i = 0; i < Con->sz; i++)
	{
		fwrite(Con->data + i, sizeof(Persona), 1, pout);
	}
	printf("保存成功\n");
	fclose(pout);
	pout = 0;
}

void DestroyContacts(struct Contact* Con)
{
	free(Con->data);
	Con->data = NULL;		//释放空间后要滞空
	Con->capacity = 0;
	Con->sz = 0;
	printf("销毁成功\n");		//已经销毁
}

3.test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contacts.h"

enum Features
{
	Exit = 0,
	add,
	del,
	find,
	mod,
	show,
	save,
	Destroy,
};

void menu()
{
	printf("*****************************\n");
	printf("****1.add  ****2.  del ******\n");
	printf("****3.find ****4.  mod ******\n");
	printf("****5.show ****6. save ******\n");
	printf("****0.exit ****7. Dest******\n");
	printf("*****************************\n");
	printf("请选择--->");
}

int main()
{
	int input = 0;
	struct Contact Con;		//创建一个通讯录

	Initialize(&Con);			//初始化
	do
	{
		menu();
		scanf("%d", &input);

		switch (input)
		{
			case add:
				addContacts(&Con);
				break;
			case del:
				delContacts(&Con);
				break;
			case find:
				findContacts(&Con);
				break;
			case mod:
				modContacts(&Con);
				break;
			case show:
				showContacts(&Con);
				break;
			case save:
				saveContacts(&Con);
				break;
			case Destroy:
				DestroyContacts(&Con);
				break;
			case Exit:
				break;
			default:
				printf("输入错误,请重新输入\n");
				break;
		}
	} while (input);
	return 0;
}

以上就是所有内容,希望大家多多指正!晚安!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值