通讯录(巨细版)

目录

一、整体思路

二、搭建框架

1. 菜单打印

2. 定义一些枚举常量

3. 创建结构体用于存储用户信息

4. 根据七个功能来构建出整体的框架

三、通讯录的核心代码

1. 初始化函数

版本2

检查容量的函数

2. 增加

3. 显示完整信息

4. 查找函数

5. 删除

6. 查找

7. 修改

8. 排序

9. 保存到文件当中(可选)

10. 释放开辟的动态空间(静态版本可忽略)

四、代码汇总

contact.h

test.c

contact.c (key)


一、整体思路

分两个源文件完成,一个是测试文件test.c,其中包括菜单打印、初始化通讯录、用户功能选择;(这部分类似于前面文章写过的三子棋和扫雷)

另一个是函数实现文件contact.c,包括初始化函数具体实现、增删查改通讯录、排序、保存通讯录到文件、退出销毁内存空间等;(这部分是关键)

当然,还需要将这些函数包含到头文件contact.h中以便测试文件使用。

二、搭建框架

1. 菜单打印

printf就行:

void menu()
{
	printf("********************************\n");
	printf("**** 1. add        2. del   ****\n");
	printf("**** 3. search     4.modify ****\n");
	printf("**** 5. show       6. sort  ****\n");
	printf("**** 0. exit                ****\n");
	printf("********************************\n");
}

2. 定义一些枚举常量

为了后面功能选择的switch语句使用,提高代码的可读性

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};

3. 创建结构体用于存储用户信息

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

同时还需要将结构体的大小记录下来

因为此版本为动态内存的版本,所以个人信息用指针来表示,为了方便动态内存管理,可随时扩容

void InitContact(Contact* pc)
{
	assert(pc);

	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//加载文件中的信息到通讯录
	LoadContact(pc);//此函数后面会实现,若没有保存到文件的操作即可忽略
}

4. 根据七个功能来构建出整体的框架

input表示用户的输入选择。其中包含的函数在contact.c中会具体实现。

int main()
{
	int input = 0;
	Contact con;
	InitCon(&con);
	do {
		menu();
		printf("请输入你的选择:>  ");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			Search(&con);
			break;
		case MODIFY:
			Modify(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("程序已退出\n");
			SaveContact(&con);
			Destory(&con);
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

	return 0;
}

三、通讯录的核心代码

接下来我们来完成contact.c中的内容

1. 初始化函数

每一个函数都是把Contact的地址接收过来的,所以用指针作为参数

在初始化函数的时候要把之前存在文件中的数据先读取出来,所以要先把这部分的功能用一个函数来实现:

此部分要用到文件操作相关的知识,在此不进行过多拓展,建议不了解的朋友可以先跳过这部分


void CheckCapacity(Contact* pc);//声明定义在后面的函数,一定要!!不然没法使用!!

void LoadContact(Contact* pc)
{
	FILE* pf = fopen("Contact.txt", "rb");//打开文件
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}//打开失败判断
	Peoinfo tmp = { 0 };
	while (fread(&tmp, sizeof(Peoinfo), 1, pf))
	{
		CheckCapacity(pc);//此函数用于确认数组的容量是否足够,后面会实现
        //注意如果函数的定义在此函数后,要在此函数前声明

        //读取文件信息
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
    //关闭文件
	fclose(pf);
	pf = NULL;
}

然后初始化函数

void InitContact(Contact* pc)
{
	assert(pc);
    
    //此部分要用到动态内存管理的知识,不是必须,可以略过
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact->calloc");
		return;
	}
	//加载文件中的信息到通讯录
	LoadContact(pc);
}

版本2

若未学到动态内存管理的知识,可参考下面版本的初始化:

void InitContact(Contact* pc)
{
	assert(pc);

	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

检查容量的函数
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += DEFAULT_INC;
			printf("增容成功\n");
		}
		else
		{
			perror("AddContact->realloc");
			return;
		}
	}
}

2. 增加

增加里边我设计了两个分支。分别是添加单个用户和多个用户,用conswitch来判断是否继续循环

void AddContact(Contact* pc)
{
	assert(pc);
	int count = 1;//第一次循环和后续循环内容的区分
	int conswitch = 1;//两个分支的判断
	while (1)
	{
		CheckCapacity(pc);//确认是否需要增容
		if (count == 1)
		{
			printf("1. 添加单个用户信息\n");
			printf("2. 添加多个用户信息\n");
			scanf("%d", &conswitch);
			printf("请输入姓名:");
			scanf("%s", pc->data[pc->sz].name);
		}

		if (count > 1)
		{
			printf("请输入姓名:(若不再添加则输入exit)");
            //此处我不用0表示退出是因为用户可能会命名为0
			scanf("%s", pc->data[pc->sz].name);
			if (strcmp(pc->data[pc->sz].name, "exit") == 0)
				break;
		}
		
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%d", pc->data[pc->sz].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pc->sz].address);

		pc->sz++;
		count++;
		printf("增加成功\n");
		if (conswitch == 1)//判断是否继续循环
			break;
	}
}

3. 显示完整信息

void ShowContact(const Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需打印\n");
		return;
	}
	int i = 0;
	//名字  年龄  性别  电话    地址
	//xxx   xxx  xxx  xxx     xxx
	printf("%-20s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    //为了更加清晰地展示,最好对齐
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s%-5d%-5s%-12s%-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}

4. 查找函数

此函数在删除、查找、修改函数均有使用到

因为此函数只在contact.c中使用,所以用static修饰

static int FindByName(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;//找不到
}

5. 删除

删除的逻辑类似于添加,不过要注意通讯录无内容的情况;

要用到查找函数找到对应的用户

void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	if (pc->sz == 0)
	{
		printf("通讯录未添加内容,无法删除");
		return;
	}
	
	int count = 1;
	int conswitch = 1;

	while (1)
	{
		if (count == 1)
		{
			printf("1. 删除单个用户信息\n");
			printf("2. 删除多个用户信息\n");
			scanf("%d", &conswitch);
			printf("请输入要删除成员的姓名:");
			scanf("%s", name);
		}
		if (count > 1)
		{
			printf("请输入要删除成员的姓名:(若不再删除则输入exit)");
			scanf("%s", name);
			if (strcmp(name, "exit") == 0)
				break;
		}
		int ret = Find_by_name(pc, name);
		if (ret == -1)
		{
			printf("无此成员,请重新输入\n");
			count++;
			continue;
		}
		else
		{
			for (int i = ret; i < pc->sz - 1; i++)
				pc->data[i] = pc->data[i + 1];

			pc->sz--;
			printf("删除成功!\n");
			if (conswitch == 1)
				break;
			count++;
		}
		
	}

}

6. 查找

查找的时候用到前面展示信息类似的操作方式,同样用到查找函数

void Search(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	printf("请输入要查找用户的姓名:");
	while (1)
	{
		scanf("%s", name);
		int ret = Find_by_name(pc, name);
		if (ret == -1)
		{
			printf("找不到此成员,请重新输入\n");
			continue;
		}
		printf("%-20s%-5s%-5s%-12s%-30s", "姓名", "年龄", "性别", "电话", "地址");
		printf("\n");
		printf("%-20s%-5d%-5s%-12d%-30s",
			pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, *(pc->data[ret].tele), pc->data[ret].address);
		printf("\n");
		break;
	}
}

7. 修改

 修改用到了查找函数,以及修改单个多个的逻辑,算是前面思路都用上了

void Modify(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
		{
			printf("无可修改成员\n");
			return;
		}
	char name[NAME_MAX];
	
	while (1)
	{
		
		int count = 1;
		int conswitch = 1;
		if (count == 1)
		{
			printf("1. 修改单个用户信息\n");
			printf("2. 修改多个用户信息\n");
			scanf("%d", &conswitch);
			printf("请输入要修改的成员姓名:");
			scanf("%s", name);
		}

		if (count > 1)
		{
			printf("请输入要修改的成员姓名:(若不再添加则输入exit)");
			scanf("%s", name);
			if (strcmp(name, "exit") == 0)
				break;
		}
		
		int ret = Find_by_name(pc, name);
		if (ret == -1)
		{
			printf("找不到此成员,请重新输入\n");
			continue;
		}

		printf("请开始修改:\n");
		printf("请输入姓名:");
		scanf("%s", &(pc->data[ret].name));
		printf("请输入年龄:");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入性别:");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话:");
		scanf("%d", pc->data[ret].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[ret].address);
		printf("\n");
		if (conswitch == 1)
			break;
	}
}

 

8. 排序

排序按照的是名字的顺序排的,方法是冒泡排序(可翻看往期文章)

void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
		printf("通讯录中无联系人信息");
	for (int i = 0; i < pc->sz - 1; i++)
	{
		for (int j = 0; j < pc->sz - 1 - i; j++)
		{
			if ((strcmp(pc->data[j].name, pc->data[j + 1].name)) > 0)
			{
				Peoinfo temp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = temp;
			}
		}
	}

	printf("排序成功!\n");
}

 

 

9. 保存到文件当中(可选)

void SaveContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写信息到文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);
		fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);
	}

	fclose(pf);
	pf = NULL;
}

10. 释放开辟的动态空间(静态版本可忽略)

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}

四、代码汇总

contact.h

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

#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

#define MAX 100
#define DEFAULT_SZ 3


typedef struct Peoinfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	int tele[TELE_MAX];
	char address[ADDR_MAX];
}Peoinfo;

typedef struct Contact
{
	Peoinfo* data;
	int sz;
	int capacity;
}Contact;

void InitCon(Contact* pc);

void AddContact(Contact* pc);

void DelContact(Contact* pc);

void Search(Contact* pc);

void Modify(Contact* pc);

void ShowContact(Contact* pc);

void SortContact(Contact* pc);

void Destory(Contact* pc);

void SaveContact(Contact* pc);

test.c

#include "contact.h"

void menu()
{
	printf("********************************\n");
	printf("**** 1. add        2. del   ****\n");
	printf("**** 3. search     4.modify ****\n");
	printf("**** 5. show       6. sort  ****\n");
	printf("**** 0. exit                ****\n");
	printf("********************************\n");
}

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT
};


int main()
{
	int input = 0;
	Contact con;
	InitCon(&con);
	do {
		menu();
		printf("请输入你的选择:>  ");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			Search(&con);
			break;
		case MODIFY:
			Modify(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("程序已退出\n");
			SaveContact(&con);
			Destory(&con);
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

	return 0;
}

contact.c (key)

#include "contact.h"

void CheckCapacity(Contact* pc);

void LoadContact(Contact* pc)
{
	FILE* pf = fopen("Contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	Peoinfo tmp = { 0 };
	while (fread(&tmp, sizeof(Peoinfo), 1, pf))
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}
	fclose(pf);
	pf = NULL;
}


void InitCon(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
	pc->data = calloc(pc->capacity, sizeof(Peoinfo));

	if (pc->data == NULL)
	{
		perror("InitCon->calloc");
		return;
	}
	LoadContact(pc);
}

void CheckCapacity(Contact* pc)
{
	assert(pc);
	if (pc->sz == pc->capacity)
	{
		Peoinfo* str = (Peoinfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peoinfo));
		if (str != NULL)
		{
			pc->data = str;
			pc->capacity += 2;
			printf("增容成功\n");
		}
		else
		{
			perror("AddContact->realloc");
			return;
		}
		
	}
}

void AddContact(Contact* pc)
{
	assert(pc);
	int count = 1;
	int conswitch = 1;
	while (1)
	{
		CheckCapacity(pc);
		if (count == 1)
		{
			printf("1. 添加单个用户信息\n");
			printf("2. 添加多个用户信息\n");
			scanf("%d", &conswitch);
			printf("请输入姓名:");
			scanf("%s", pc->data[pc->sz].name);
		}

		if (count > 1)
		{
			printf("请输入姓名:(若不再添加则输入exit)");
			scanf("%s", pc->data[pc->sz].name);
			if (strcmp(pc->data[pc->sz].name, "exit") == 0)
				break;
		}
		
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%d", pc->data[pc->sz].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pc->sz].address);

		pc->sz++;
		count++;
		printf("增加成功\n");
		if (conswitch == 1)
			break;
	}
}

int Find_by_name(Contact* pc, char* name)
{
	assert(pc&&name);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
			return i;
	}
	return -1;
}


void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	if (pc->sz == 0)
	{
		printf("通讯录未添加内容,无法删除");
		return;
	}
	
	int count = 1;
	int conswitch = 1;

	while (1)
	{
		if (count == 1)
		{
			printf("1. 删除单个用户信息\n");
			printf("2. 删除多个用户信息\n");
			scanf("%d", &conswitch);
			printf("请输入要删除成员的姓名:");
			scanf("%s", name);
		}
		if (count > 1)
		{
			printf("请输入要删除成员的姓名:(若不再删除则输入exit)");
			scanf("%s", name);
			if (strcmp(name, "exit") == 0)
				break;
		}
		int ret = Find_by_name(pc, name);
		if (ret == -1)
		{
			printf("无此成员,请重新输入\n");
			count++;
			continue;
		}
		else
		{
			for (int i = ret; i < pc->sz - 1; i++)
				pc->data[i] = pc->data[i + 1];

			pc->sz--;
			printf("删除成功!\n");
			if (conswitch == 1)
				break;
			count++;
		}
		
	}

}




void Modify(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
		{
			printf("无可修改成员\n");
			return;
		}
	char name[NAME_MAX];
	
	while (1)
	{
		
		int count = 1;
		int conswitch = 1;
		if (count == 1)
		{
			printf("1. 修改单个用户信息\n");
			printf("2. 修改多个用户信息\n");
			scanf("%d", &conswitch);
			printf("请输入要修改的成员姓名:");
			scanf("%s", name);
		}

		if (count > 1)
		{
			printf("请输入要修改的成员姓名:(若不再添加则输入exit)");
			scanf("%s", name);
			if (strcmp(name, "exit") == 0)
				break;
		}
		
		int ret = Find_by_name(pc, name);
		if (ret == -1)
		{
			printf("找不到此成员,请重新输入\n");
			continue;
		}

		printf("请开始修改:\n");
		printf("请输入姓名:");
		scanf("%s", &(pc->data[ret].name));
		printf("请输入年龄:");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入性别:");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话:");
		scanf("%d", pc->data[ret].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[ret].address);
		printf("\n");
		if (conswitch == 1)
			break;
	}
}




void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("无成员\n");
		return;
	}
	int i = 0;
	printf("%-20s%-5s%-5s%-12s%-30s", "姓名", "年龄", "性别", "电话", "地址");
	printf("\n");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-12d%-30s",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex, *(pc->data[i].tele), pc->data[i].address);
		printf("\n");
	}
	printf("\n");
	
}

void Search(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX];
	printf("请输入要查找用户的姓名:");
	while (1)
	{
		scanf("%s", name);
		int ret = Find_by_name(pc, name);
		if (ret == -1)
		{
			printf("找不到此成员,请重新输入\n");
			continue;
		}
		printf("%-20s%-5s%-5s%-12s%-30s", "姓名", "年龄", "性别", "电话", "地址");
		printf("\n");
		printf("%-20s%-5d%-5s%-12d%-30s",
			pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, *(pc->data[ret].tele), pc->data[ret].address);
		printf("\n");
		break;
	}
}


void SortContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
		printf("通讯录中无联系人信息");
	for (int i = 0; i < pc->sz - 1; i++)
	{
		for (int j = 0; j < pc->sz - 1 - i; j++)
		{
			if ((strcmp(pc->data[j].name, pc->data[j + 1].name)) > 0)
			{
				Peoinfo temp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = temp;
			}
		}
	}

	printf("排序成功!\n");
}


void Destory(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
}


void SaveContact(Contact* pc)
{
	FILE* pf = fopen("Contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fwrite(pc->data+i, sizeof(Peoinfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值