用C语言实现一个通讯录(用VS2010实现)

实现一个通讯录;
通讯录可以用来存储联系人人的信息,每个人的信息包括:
序号、姓名、性别、年龄、电话、住址
通讯录为用户提供的操作:

0.退出
1.添加联系人信息
2.删除指定联系人信息
3.查找指定联系人信息
4.修改指定联系人信息
5.显示所有联系人信息
6.清空所有联系人
7.以名字排序所有联系人
8.保存联系人到文件 9. 加载联系人

通过对通讯录的实现,复习的知识点有:结构体、数组、指针、动态内存开辟(malloc、calloc、realloc、free)、文件相关操作。

通讯录简介:

运行程序后,可以进入选择界面,通过输入菜单中的序号来选择相应的操作,如下图所示:
在这里插入图片描述
添加联系人信息,如下图所示(只展示添加一个联系人,其他的省略):
在这里插入图片描述
添加完联系人信息后输入5,显示所有联系人信息,如下图:
在这里插入图片描述
输入3查找联系人,如下图:
在这里插入图片描述
输入2删除指定的联系人,如下图:
在这里插入图片描述
其他功能便不在此一一展示了。

编写过程:

1.建立3个文件,分别是contact.c、contact.h、test.c
contact.c用来放一些自定义的函数;contact.h用于放函数声明等内容;test.c用于放主函数,组织整个程序框架
2.在test.c中写一个main()函数,作为程序运行的入口,将测试函数test()放到里面

int main()
{
	test();
	return 0;
}

3.写一个菜单函数,用于打印通讯录的菜单

void menu()
{
	printf("**************************************************************\n");
	printf("**        1. 添加联系人                2. 删除联系人        **\n");
	printf("**        3. 查找联系人                4. 修改联系人信息    **\n");
	printf("**        5. 显示所有联系人            6. 清空所有联系人    **\n");
	printf("**        7. 联系人按姓名排序          0. 退出              **\n");
	printf("**************************************************************\n");
}

4.我们定义一个结构体,命名为person_info,用来存储联系人的信息;定义一个结构体,命名为addres_book,用来存放动态分配的内存的地址、动态分配的内存的容量大小以及联系人的数量。

typedef struct person_info
{
	int number;//为每个联系人分配一个编号
	char name[NAME_MAX];
	char sex[SEX_MAX];
	short age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}person_info;

typedef struct address_book
{
	person_info *data;
	int count;//记录联系人个数
	int capacity;//记录容量
}address_book;

5.在test.c中写一个测试函数test(),该函数用于将其他函数组织起来,成为完整的通讯录运行函数,同时也可以使main()函数看起来更简洁

void test()
{
	int input = 1;
	address_book book;
	address_book_init(&book);//初始化通讯录
	while (input)
	{
		menu();
		printf("请选择>> ");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			save_address_book(&book);
			printf("退出成功!\n");
			break;
		case ADD:
			address_book_add(&book);
			break;
		case DEL:
			address_book_del(&book);
			break;
		case SEARCH:
			address_book_find(&book);
			break;
		case MODIFY:
			address_book_update(&book);
			break;
		case SHOW:
			address_book_show(&book);
			break;
		case EMPTY:
			address_book_del_all(&book);
			break;
		case SORT:
			sort_by_name(&book);
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	}
}

6.子函数简介:
address_book_init( )函数
初始化通讯录。这个函数通过调用calloc( )函数动态分配三个起始空间,内容为空,并且通过调用address_book_load( )函数将文件中的数据加载进来。

address_book_add( )函数
添加联系人。当用户输入1后,test( )函数调用该函数,让用户添加一个联系人,这个函数会调用check_capacity( )函数自动扩容。

address_book_show( )函数
显示所有联系人信息 。当用户输入5后,test( )函数调用该函数,将通讯录中所有的联系人信息打印出来。

address_book_del_all( )函数
清空所有联系人。当用户输入6后,test( )函数调用该函数,该函数将释放之前动态分配的所有空间,并将联系人计数变量和内存计数变量都清空。

address_book_del( )函数
删除指定联系人信息 。当用户输入2后,test( )函数调用该函数,该函数将会提示用户输入要删除的联系人的姓名,当用户输入姓名后,该函数会调用Find( )函数进行查找,(考虑到用户有可能会将两个同名的联系人存到通讯录中)然后将找到的所有同名的联系人的相关信息打印出来。此时该函数会提示用户输入要删除的联系人的序号,这样就可以避免同名的联系人的信息误删的情况了。

address_book_find( )函数
查找指定联系人信息,并将其打印。当用户输入3后,test( )函数将调用该函数,该函数会提示用户输入要查找的联系人的姓名,当用户输入姓名后,该函数将调用Find( )函数进行查找,并将找到的所有同名联系人信息打印出来。

address_book_update( )函数
修改指定联系人信息。当用户输入4后,test( )函数将调用该函数,该函数会提示用户输入要修改的用户的姓名,然后通过用户输入信息对原变量重新赋值,达到修改信息的目的。

sort_by_name( )函数
将所有的联系人按名字排序。当用户输入7后,test( )函数将调用该函数,该函数会通过使用qsort( )函数对联系人信息(person_info类型的结构体变量)按姓名进行排序。

save_address_book( )函数
将通讯录的内容存入文件中。当用户输入0打算退出的时候,test( )函数将调用该函数,该函数通过文件二进制写操作将person_info类型的数组中的数据(联系人信息)保存到address book.data文件中。

check_capacity( )函数
通过联系人的数量(count)和动态分配的内存的容量(capacity)的关系判断是否需要进行扩容,扩容的方法是使用realloc( )函数重新分配一块更大的内存空间。

address_book_load( )函数
将address book.data文件中的数据加载到动态分配的数组中,如果内存大小不够,该函数会通过调用check_capacity( )函数对内存进行扩充。该函数被address_book_init( )函数调用 ,用于用户打开通讯录程序的时候的数据加载。

Find( )函数
查找联系人并返回该联系人的位置,找不到返回-1.该函数被address_book_del( )、sort_by_name()和address_book_update( )调用,用来通过姓名查找联系人。

通讯录代码总览:

contact.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#define NAME_MAX 11
#define SEX_MAX 5
#define TEL_MAX 12
#define ADDR_MAX 21
#define DEFAULT_SIZE 3

enum//将菜单定义为一个枚举类
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	EMPTY,
	SORT
};

typedef struct person_info
{
	int number;//为每个联系人分配一个编号
	char name[NAME_MAX];
	char sex[SEX_MAX];
	short age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}person_info;

typedef struct address_book
{
	person_info *data;
	int count;//记录联系人个数
	int capacity;//记录容量
}address_book;

void address_book_init(address_book *);//初始化通讯录
void address_book_add(address_book *);//添加联系人
void address_book_show(const address_book *);//显示所有联系人信息 
void address_book_del_all(address_book *);//清空所有联系人
void address_book_del(address_book *);//	删除指定联系人信息 
void address_book_find(address_book *);//查找指定联系人信息,并将其打印
void address_book_update(address_book *);//修改指定联系人信息 
void sort_by_name(address_book *);//将所有的联系人按名字排序
void save_address_book(address_book *);//将通讯录的内容存入文件中

contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"

void check_capacity(address_book *pbook)
{
	assert(pbook);
	if (pbook->capacity == pbook->count)//如果满了则扩容
	{
		person_info *ptmp = (person_info *)realloc(pbook->data, (pbook->capacity+2)*sizeof(person_info));
		if (ptmp != NULL)
		{
			pbook->capacity += 2;
			pbook->data = ptmp;
			//printf("扩容成功!\n");
		}
	}
}

void address_book_load(address_book *pbook)
{
	person_info tmp = {0};
	FILE *pfread = fopen("address book.data", "rb");
	if (pfread == NULL)
	{
		printf("加载失败:打开文件失败!\n");
		return;
	}
	//加载消息
	while (fread(&tmp, sizeof(person_info), 1, pfread))
	{
		check_capacity(pbook);
		pbook->data[pbook->count] = tmp;
		pbook->count++;
	}
	fclose(pfread);
	pfread = NULL;
}

void address_book_init(address_book *pbook)
{
	pbook->count = 0;
	//memset(pbook->data, '0', sizeof(pbook->data));
	pbook->data = (person_info *)calloc(DEFAULT_SIZE, sizeof(person_info));
	if (pbook->data == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	pbook->capacity = DEFAULT_SIZE;
	address_book_load(pbook);//加载通讯录
}

void address_book_show(const address_book *pbook)
{
	int i = 0;
	if (pbook->count == 0)
	{
		printf("通讯录内容为空,无联系人可显示!\n");
		return;
	}
	printf("%-8s%-14s%-8s%-7s%-15s%-24s\n", "序号","姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < (pbook->count); i++)
	{
		printf("%-8d%-14s%-8s%-7d%-15s%-24s\n",
			pbook->data[i].number,
			pbook->data[i].name,
			pbook->data[i].sex,
			pbook->data[i].age,
			pbook->data[i].tel,
			pbook->data[i].addr);
	}

}

void address_book_add(address_book *pbook)
{
	assert(pbook);
	check_capacity(pbook);
	printf("请输入要添加的联系人的信息!\n");
	printf("姓名>> ");
	scanf("%s", pbook->data[pbook->count].name);
	printf("性别>> ");
	scanf("%s", pbook->data[pbook->count].sex);
	printf("年龄>> ");
	scanf("%d", &(pbook->data[pbook->count].age));
	printf("电话>> ");
	scanf("%s", pbook->data[pbook->count].tel);
	printf("地址>> ");
	scanf("%s", pbook->data[pbook->count].addr);
	pbook->data[pbook->count].number = pbook->count + 1;
	(pbook->count)++;
	printf("添加成功!\n");
}

void address_book_del_all(address_book *pbook)
{
	free(pbook->data);
	pbook->data = NULL;
	pbook->capacity = 0;
	pbook->count = 0;
	printf("通讯录内容已经被清空!\n");
}

static int Find(const address_book *pbook, char *name, int i)//查找联系人并返回该联系人的位置,找不到返回-1
{
	for (; i < (pbook->count); i++)//i表示要查找的位置
	{
		if (strcmp((pbook->data[i]).name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void address_book_del(address_book *pbook)
{	
	int i = 0;
	int tmp = 0;
	int tag1 = 0;
	int tag2 = 0;
	char name[11] = {0};
	person_info empty = {0};
	if (0 == (pbook->count))
	{
		printf("通讯录为空,没有内容可删除!\n");
		return;
	}
	printf("请输入要删除的联系人的姓名>> ");
	scanf("%s", name);
	while (tmp < (pbook->count))
	{
		tmp = Find(pbook, name, tag2);
		if (-1 != tmp)
		{
			tag2 = tmp + 1;
			if (0 == tag1)
			{
				printf("%-8s%-14s%-8s%-7s%-15s%-24s\n",
					"序号","姓名", "性别", "年龄", "电话", "地址");
			}
			printf("%-8d%-14s%-8s%-7d%-15s%-24s\n",
				pbook->data[tmp].number,
				pbook->data[tmp].name,
				pbook->data[tmp].sex,
				pbook->data[tmp].age,
				pbook->data[tmp].tel,
				pbook->data[tmp].addr);
			tag1 = 1;
		}
		else
		{
			break;
		}
	}
	if (0 == tag1)
	{
		printf("找不到联系人:%s!\n", name);
	}
	else
	{
		while (1)
		{
			printf("请输入要删除的联系人的序号>> ");
			scanf("%d", &i);
			if (strcmp(pbook->data[i-1].name, name) != 0)
			{
				printf("输入的序号有误,请重新输入!\n");
				continue;
			}
			else//输入的序号与输入的姓名对应才会删除
			{
				for (;i < pbook->count; i++)
				{
					pbook->data[i-1] = pbook->data[i];
					pbook->data[i-1].number = i;//修正序号
				}
				//memset(&(pbook->data[(pbook->count) - 1]), '0', sizeof(person_info));//最后一个单元清空
				pbook->data[(pbook->count) - 1] = empty;
				printf("删除成功!\n");
				(pbook->count)--;
				break;
			}
		}
	}
}

void address_book_find(address_book *pbook)
{
	int tmp = 0;
	int tag1 = 0;//标记是否找到
	int tag2 = 0;//标记查找的位置
	char name[11] = {0};
	if (0 == (pbook->count))
	{
		printf("通讯录为空,无内容可查找!\n");
		return;
	}
	printf("请输入要查找的联系人的姓名>> ");
	scanf("%s", name);
	while (tag2 < (pbook->count))
	{
		tmp = Find(pbook, name, tag2);
		if (-1 != tmp)
		{
			tag2 = tmp + 1;//如果找到了就更新tag2
			if (0 == tag1)
			{
				printf("%-8s%-14s%-8s%-7s%-15s%-24s\n",
					"序号","姓名", "性别", "年龄", "电话", "地址");
			}
			printf("%-8d%-14s%-8s%-7d%-15s%-24s\n",
				pbook->data[tmp].number,
				pbook->data[tmp].name,
				pbook->data[tmp].sex,
				pbook->data[tmp].age,
				pbook->data[tmp].tel,
				pbook->data[tmp].addr);
			tag1 = 1;
		}
		else
		{
			break;
		}
	}
	if (0 == tag1)
	{
		printf("找不到联系人:%s!\n", name);
	}
}

void address_book_update(address_book *pbook)
{
	int i = 0;
	int tmp = 0;
	char name[11] = {0};
	if (0 == pbook->count)
	{
		printf("通讯录内容为空,无法修改联系人!\n");
		return;
	}
	printf("请输入要修改的联系人的姓名>> ");
	scanf("%s", name);
	tmp = Find(pbook, name, i);
	if (-1 != tmp)
	{
		printf("姓名修改为>> ");
		scanf("%s", pbook->data[tmp].name);
		printf("性别修改为>> ");
		scanf("%s", pbook->data[tmp].sex);
		printf("年龄修改为>> ");
		scanf("%d", &(pbook->data[tmp].age));//这里需要注意一下:记得取地址
		printf("电话修改为>> ");
		scanf("%s", pbook->data[tmp].tel);
		printf("地址修改为>> ");
		scanf("%s", pbook->data[tmp].addr);
		printf("修改成功!\n");
	}
	else
	{
		printf("找不到联系人:%s!\n", name);
	}
}

static int cmp_by_name(const void *p1, const void *p2)
{
	return strcmp(((person_info *)p1)->name, ((person_info *)p2)->name);
}

void sort_by_name(address_book *pbook)//使用qsort函数进行排序
{
	if (pbook->count == 0)
	{
		printf("通讯录的内容为空,不需要排序!\n");
		return;
	}
	qsort(pbook->data, (pbook->count), sizeof(pbook->data[0]), cmp_by_name);//需要排序的联系人个数是count个
	printf("排序成功\n");
}

void save_address_book(address_book *pbook)
{
	int i = 0;
	FILE *pfwrite = fopen("address book.data", "wb");
	if (pfwrite == NULL)
	{
		printf("保存失败:打开文件失败!\n");
		return;
	}
	for (i = 0; i < pbook->count; i++)
	{
		fwrite(pbook->data+i, sizeof(person_info), 1, pfwrite);
	}
	fclose(pfwrite);
	pfwrite = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"

void menu()
{
	printf("**************************************************************\n");
	printf("**        1. 添加联系人                2. 删除联系人        **\n");
	printf("**        3. 查找联系人                4. 修改联系人信息    **\n");
	printf("**        5. 显示所有联系人            6. 清空所有联系人    **\n");
	printf("**        7. 联系人按姓名排序          0. 退出              **\n");
	printf("**************************************************************\n");
}

void test()
{
	int input = 1;
	address_book book;
	address_book_init(&book);//初始化通讯录
	while (input)
	{
		menu();
		printf("请选择>> ");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			save_address_book(&book);
			printf("退出成功!\n");
			break;
		case ADD:
			address_book_add(&book);
			break;
		case DEL:
			address_book_del(&book);
			break;
		case SEARCH:
			address_book_find(&book);
			break;
		case MODIFY:
			address_book_update(&book);
			break;
		case SHOW:
			address_book_show(&book);
			break;
		case EMPTY:
			address_book_del_all(&book);
			break;
		case SORT:
			sort_by_name(&book);
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	}
}

int main()
{
	test();
	return 0;
}

源代码连接:https://github.com/xiao-hao-hao/Contacts

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值