[C语言]充分理解通讯录项目(动态版本+可存储记录数据)

目录

总体架构

在写动态存储数据的通讯录前请最好自己熟悉静态通讯录的原理思路,这里放一篇静态通讯录。
我们使用contact.h,contact.c,test,c三个文件
由于我们有时候只是用动态版本不进行存储数据,所以这里把所有跟存储功能有关的函数代码都用箭头标志上,定为版本三

contact.h

#pragma once

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

#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 30
#define MAX_ADDR 30

#define MAX 1000

//动态版本
#define DEFAULT_NUM 3//一次申请3peoinfo的空间
#define AD_NUM 2//一次的增量

//结构体类型的定义,通讯录一个联系人的信息
typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
	int age;
}PeoInfo;//将struct PeoInfo定义为PeoInfo

//动态版本
typedef struct Contact
{
	PeoInfo *data;//指向动态申请的空间,存放人的信息
	int num;//记录已经存在的有效信息的个数
	int capcity;//记录当前通讯录有效信息的最大个数
}Contact;

//初始化通讯录
void InitContact(Contact* pc);
//增添联系人
void AddContact(Contact* pc);
//打印所有联系人
void PrintContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查询联系人
void SearchContact(Contact* pc);
//修改联系人
void ModifyContact(Contact* pc);
//排列联系人
void SortContact(Contact* pc);
//释放通讯录
void DestoryContact(Contact* pc);
//存储联系人信息
void SaveContact(Contact* pc);		<-(版本三)
//读取联系人信息
void LoadContact(Contact* pc);		<-(版本三)

动态版本主要在于部分函数的改变以及增添

test.c

#define _CRT_SECURE_NO_DEPRECATE 1

#pragma warning(disable:4996)

#include "contact.h"

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

void menu()
{
	printf("*****************************\n");
	printf("****** 1.Add    2.Del *******\n");
	printf("****** 3.Search 4.Modify ****\n");
	printf("****** 5.Sort   6.Print  ****\n");
	printf("*********** 0.Exit **********\n");
	printf("*****************************\n");
}

//动态版本
//每次退出程序后保留之前的数据
int main()
{
	int input = 0;
	Contact con;//创建通讯录
	InitContact(&con);	//初始化通讯录
	LoadContact(&con);		<-版本三//加载数据
	do {
		menu();
		printf("请输入:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case PRINT:
			PrintContact(&con);
			break;
		case EXIT:
			SaveContact(&con);	<-(版本三)//储存联系人信息
			DestoryContact(&con);//释放通讯录
			printf("退出成功\n");
			break;
		default:
			printf("输入错误,重新输入");
			break;
		}
	} while (input);
	return 0;
}

具体函数实现

初始化通讯录

  • malloc申请空间若申请失败则会返回NULL
void InitContact(Contact* pc)
{
	pc->data = (PeoInfo*)malloc(DEFAULT_NUM * sizeof(PeoInfo));//用malloc申请3个PeoInfo大小的值
	if (pc->data == NULL)//判断是否申请失败
	{
		perror("InitContact");//若失败perror报错
		return;
	}
	pc->num = 0;//将数据个数置空
	pc->capcity = DEFAULT_NUM;//容量设为3	
}

销毁/释放通讯录

  • 在退出时执行销毁功能
void DestoryContact(Contact* pc)
{
	free(pc->data);//释放data内存
	//整个过程只有pc->data开辟了动态内存
	pc->data = NULL;//置空
	pc->num = 0;//数据个数置零
	pc->capcity = 0;//容量置零
}

检查通讯录是否需要扩容

  • 增加联系人时会检查是否需要增容,我们更偏向于单独写出来这个功能
  • realloc是重新调整ptr指向的内存块大小,所以我们(pc->capcity + AD_NUM)需要加上本身capacity
void CheckCapcity(Contact* pc)
{
	if (pc->num == pc->capcity)//判断是否容量已经满了
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capcity + AD_NUM) * sizeof(PeoInfo));//将realloc申请的空间放到一个临时的结构体指针中
		if (ptr != NULL)//判断是否realloc成功
		{
			pc->data = ptr;//将ptr的内存容量赋给data
			pc->capcity += AD_NUM;//扩容
			printf("增容成功\n");
		}
		else//realloc失败
		{
			perror(AddContact);
			printf("增加联系人失败\n");
			return;
		}
	}
}

增加联系人

  • 检查后正常输入
void AddContact(Contact* pc)
{
	CheckCapcity(pc);//检查/扩容
	printf("请输入姓名:>\n");
	scanf("%s", pc->data[pc->num].name);
	printf("请输入年龄:>\n");
	scanf("%d", &(pc->data[pc->num].age));
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->num].sex);
	printf("请输入电话\n");
	scanf("%s", pc->data[pc->num].tele);
	printf("请输入地址\n");
	scanf("%s", pc->data[pc->num].addr);
	pc->num++;
}

打印联系人

  • "%-20s\t%-8s\t%-8s\t%-20s\t%-30s\n"是为了对应各个信息的大小(姓名最大20个字节)
  • '\t'使标题对齐,for循环中i < pc->num打印当前存储的所有联系人
void PrintContact(const Contact* pc)
{
	//打印最上方标题
	printf("%-20s\t%-8s\t%-8s\t%-20s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	//打印人物数据
	for (int i = 0; i < pc->num; i++)
	{
		printf("%-20s\t%-8d\t%-8s\t%-20s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

查找姓名

  • 搜索联系人修改联系人删除联系人功能都有一个步骤——即查询姓名
  • 所以我们把查找姓名也单独写一个函数
int FindName(Contact* pc, char name[])
{
	for (int i = 0; i < pc->num; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
			return i;
	}
	return -1;
}

当我们输入要查询的联系人姓名后,FindName()会遍历目前储存的所有联系人,用strcmp判断是否有相等,如果相等返回其下标

查询联系人

void SearchContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->num == 0)	//判断一下通讯录是否有联系人,如果为空直接退出,可去掉此if语句
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入要查找的人的名字");
	scanf("%s", &name);
	int ret = FindName(pc, name);	//将查找出的联系人下标赋给ret
	if (ret == -1)	//判断是否找到该联系人
	{
		printf("您要查找的人物不存在\n");
		return;
	}
	else	//打印ret下标的联系人所有信息
	{
		printf("%-20s\t%-8s\t%-8s\t%-20s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-8d\t%-8s\t%-20s\t%-30s\n",
				pc->data[ret].name,
				pc->data[ret].age,
				pc->data[ret].sex,
				pc->data[ret].tele,
				pc->data[ret].addr);
	}
}

删除联系人

  • 我们删除联系人的本质是把该联系人后面的所有联系人下标向前移一位,后面的联系人直接覆盖该联系人,最后num--(存储的联系人个数)
void DelContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->num == 0)	//判断一下通讯录是否有联系人,如果为空直接退出,可去掉此if语句
	{
		printf("通讯录为空\n");
		return;
	}
	printf("输入要删除人物的名字\n");
	scanf("%s", name);
	//查找人物
	int ret = FindName(pc,name);
	if (ret == -1)
	{
		printf("您要删除的人物不存在\n");
		return;
	}
	for (int i = ret; i < pc->num-1; i++)//注意num-1为了最后成员的名字无需将他后面的空白替换过来
	{
		pc->data[i] = pc->data[i + 1];//把从pc->data[ret]后的成员向前移
	}
	pc->num--;
	printf("删除成功\n");
}

修改联系人

  • 修改联系人与删除、查询联系人很类似,先判断在输入最后执行操作
void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->num == 0)	//判断一下通讯录是否有联系人,可去掉此if语句
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入要修改的人的名字:>");
	scanf("%s", name);
	int ret = FindName(pc, name);
	if (ret == -1)
	{
		printf("您要修改的人物不存在\n");
		return;
	}
	else
	{
		/*printf("请输入姓名:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入性别");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话");
		scanf("%s", pc->data[ret].tele);
		printf("请输入地址");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");*/
		int op = 0;
		do {
			printf("请输入需要修改的部分\n");
			printf("1.姓名 2.年龄 3.性别 4.电话 5.地址 0.退出修改\n");
			scanf("%d", &op);
			switch (op)
			{
			case 1:
				printf("请输入姓名:>");
				scanf("%s", pc->data[ret].name);
				break;
			case 2:
				printf("请输入年龄:>");
				scanf("%d", &(pc->data[ret].age));
				break;
			case 3:
				printf("请输入性别:>");
				scanf("%s", pc->data[ret].sex);
				break;
			case 4:
				printf("请输入电话:>");
				scanf("%s", pc->data[ret].tele);
				break;
			case 5:
				printf("请输入地址:>");
				scanf("%s", pc->data[ret].addr);
				break;
			case 0:
				printf("退出修改\n");
				break;
			default:
				printf("输入错误,重新输入");
				break;
			}
		} while (op);
	}
}

这里提供了两种,因为修改联系人很多时候只需要修改某条信息,所以我们使用do_while&&switch_case来进行某些项的修改。
而注释掉的代码是逐步修改所有项

排序联系人

void SortContact(Contact* pc)
{
	if (pc->num == 0)	//先进行判断通讯录是否为空
	{
		printf("通讯录为空\n");
		return;
	}
	for (int i = 0; i < pc->num - 1; i++)
	{
		for (int j = 0; j < pc->num - i - 1; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			//比较data下标为j和下标为j+1的名字的大小
			{
				PeoInfo tmp = { 0 };	//创建一个临时变量用于交换
				tmp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = tmp;
			}
		}
	}
	printf("排序成功\n");
}

排序联系人使用冒泡排序的方法。

保存数据

  • 为了使通讯录具有储存联系人的功能,每次退出前进行保存数据
  • 注意contact.dat要在代码文件的同路径下
void SaveContact(Contact* pc)//3
{
	FILE *pf = fopen("Contact.dat", "w");//打开只写文件,若文件不存在会自动创建
	if (pf == NULL)//判断是否fopen打开成功
	{
		perror(SaveContact);
		return;
	}
	for (int i = 0; i < pc->num; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);//data+i即为下标为i的地址
	}
	fclose(pf);//关闭流
	pf = NULL;//置空
}

读取数据

void LoadContact(Contact* pc)
{
	FILE* pf = fopen("Contact.dat", "r");//以只读模式打开
	if (pf == NULL)//判断是否打开成功
	{
		perror(LoadContact);
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))//将pf读取到*tmp指向的内存中
	{
		//判断增容
		CheckCapcity(pc);
		pc->data[pc->num] = tmp;
		pc->num++;
	}
}

完整代码

这里贴一个笔者的gitee链接 卜及中-share-contact

contact.c

#define _CRT_SECURE_NO_DEPRECATE 1

#pragma warning(disable:4996)

#include "contact.h"


void InitContact(Contact* pc)
{
	pc->data = (PeoInfo*)malloc(DEFAULT_NUM * sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact");
		return;
	}
	pc->num = 0;
	pc->capcity = DEFAULT_NUM;
}

void CheckCapcity(Contact* pc)
{
	if (pc->num == pc->capcity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capcity + AD_NUM) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capcity += AD_NUM;
			printf("增容成功\n");
		}
		else
		{
			perror(AddContact);
			printf("增加联系人失败\n");
			return;
		}
	}
}

void AddContact(Contact* pc)
{
	CheckCapcity(pc);
	printf("请输入姓名:>\n");
	scanf("%s", pc->data[pc->num].name);
	printf("请输入年龄:>\n");
	scanf("%d", &(pc->data[pc->num].age));
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->num].sex);
	printf("请输入电话\n");
	scanf("%s", pc->data[pc->num].tele);
	printf("请输入地址\n");
	scanf("%s", pc->data[pc->num].addr);

	pc->num++;
}

void PrintContact(const Contact* pc)
{
	//打印最上方标题
	printf("%-20s\t%-8s\t%-8s\t%-20s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	//打印人物数据
	for (int i = 0; i < pc->num; i++)
	{
		printf("%-20s\t%-8d\t%-8s\t%-20s\t%-30s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].tele,
			pc->data[i].addr);
	}
}

//查找名字
int FindName(Contact* pc, char name[])
{
	for (int i = 0; i < pc->num; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
			return i;
	}
	return -1;
}


void DelContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->num == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("输入要删除人物的名字\n");
	scanf("%s", name);
	//查找人物
	int ret = FindName(pc,name);
	if (ret == -1)
	{
		printf("您要删除的人物不存在\n");
		return;
	}
	for (int i = ret; i < pc->num-1; i++)//注意num-1为了最后成员的名字无需将他后面的空白替换过来
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->num--;
	printf("删除成功\n");
}

void SearchContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->num == 0)	//判断一下通讯录是否有联系人,可去掉此if语句
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入要查找的人的名字");
	scanf("%s", &name);
	int ret = FindName(pc, name);
	if (ret == -1)
	{
		printf("您要查找的人物不存在\n");
		return;
	}
	else
	{
		printf("%-20s\t%-8s\t%-8s\t%-20s\t%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-8d\t%-8s\t%-20s\t%-30s\n",
				pc->data[ret].name,
				pc->data[ret].age,
				pc->data[ret].sex,
				pc->data[ret].tele,
				pc->data[ret].addr);
	}
}

void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	if (pc->num == 0)	//判断一下通讯录是否有联系人,可去掉此if语句
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入要修改的人的名字:>");
	scanf("%s", name);
	int ret = FindName(pc, name);
	if (ret == -1)
	{
		printf("您要修改的人物不存在\n");
		return;
	}
	else
	{
		/*printf("请输入姓名:>");
		scanf("%s", pc->data[ret].name);
		printf("请输入年龄:>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入性别");
		scanf("%s", pc->data[ret].sex);
		printf("请输入电话");
		scanf("%s", pc->data[ret].tele);
		printf("请输入地址");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");*/
		int op = 0;
		do {
			printf("请输入需要修改的部分\n");
			printf("1.姓名 2.年龄 3.性别 4.电话 5.地址 0.退出修改\n");
			scanf("%d", &op);
			switch (op)
			{
			case 1:
				printf("请输入姓名:>");
				scanf("%s", pc->data[ret].name);
				break;
			case 2:
				printf("请输入年龄:>");
				scanf("%d", &(pc->data[ret].age));
				break;
			case 3:
				printf("请输入性别:>");
				scanf("%s", pc->data[ret].sex);
				break;
			case 4:
				printf("请输入电话:>");
				scanf("%s", pc->data[ret].tele);
				break;
			case 5:
				printf("请输入地址:>");
				scanf("%s", pc->data[ret].addr);
				break;
			case 0:
				printf("退出修改\n");
				break;
			default:
				printf("输入错误,重新输入");
				break;
			}
		} while (op);
	}
}
	
void SortContact(Contact* pc)
{
	if (pc->num == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	for (int i = 0; i < pc->num - 1; i++)
	{
		for (int j = 0; j < pc->num - 1-i; j++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				PeoInfo tmp = { 0 };
				tmp = pc->data[j];
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = tmp;
			}
		}
	}
	printf("排序成功\n");
}
//动态版本
void DestoryContact(Contact* pc)//3
{
	free(pc->data);
	//整个过程只有pc->data开辟了动态内存
	pc->data = NULL;
	pc->num = 0;
	pc->capcity = 0;
}

//版本三-存储数据
void SaveContact(Contact* pc)//3
{
	FILE *pf = fopen("Contact.dat", "w");
	if (pf == NULL)
	{
		perror(SaveContact);
		return;
	}
	for (int i = 0; i < pc->num; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);//data+i即为下标为i的地址
	}
	fclose(pf);
	pf = NULL;
}
//版本三 - 加载数据
void LoadContact(Contact* pc)
{
	FILE* pf = fopen("Contact.dat", "r");
	if (pf == NULL)
	{
		perror(LoadContact);
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		//判断增容
		CheckCapcity(pc);
		pc->data[pc->num] = tmp;
		pc->num++;
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
你想了解关于使用C语言实现通讯录数据结构吗?在使用C语言实现通讯录时,可以使用结构体来表示联系人的信息,例如姓名、电话号码、地址等。可以使用数组或链表来存储多个联系人的信息。以下是一个简单的示例代码: ```c #include <stdio.h> #include <string.h> #define MAX_CONTACTS 100 struct Contact { char name[50]; char phone[20]; char address[100]; }; struct Contact contacts[MAX_CONTACTS]; int numContacts = 0; void addContact(const char* name, const char* phone, const char* address) { if (numContacts < MAX_CONTACTS) { strcpy(contacts[numContacts].name, name); strcpy(contacts[numContacts].phone, phone); strcpy(contacts[numContacts].address, address); numContacts++; printf("Contact added successfully!\n"); } else { printf("Contact list is full!\n"); } } void displayContacts() { if (numContacts == 0) { printf("Contact list is empty.\n"); } else { printf("Contact list:\n"); for (int i = 0; i < numContacts; i++) { printf("Name: %s\n", contacts[i].name); printf("Phone: %s\n", contacts[i].phone); printf("Address: %s\n", contacts[i].address); printf("\n"); } } } int main() { // 添加示例联系人 addContact("John Doe", "1234567890", "123 Main St"); addContact("Jane Smith", "9876543210", "456 Elm St"); // 显示联系人列表 displayContacts(); return 0; } ``` 在上述示例中,我们定义了一个结构体`Contact`来表示联系人的信息。通过`addContact`函数可以添加联系人到通讯录中,通过`displayContacts`函数可以显示通讯录中的所有联系人。你可以根据需要进行扩展和修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值