(通讯录动态类型)详细教程,C语言实现可进行扩容,查找,修改,删除,保存操作

# 前言:
通讯录演示:
(通讯录动态类型)详细教程,C语言实现可进行扩容,查找,修改,删除,保存操作_第1张图片
(通讯录动态类型)详细教程,C语言实现可进行扩容,查找,修改,删除,保存操作_第2张图片
(通讯录动态类型)详细教程,C语言实现可进行扩容,查找,修改,删除,保存操作_第3张图片

我们这个通讯录要分模块进行,分为三个部分:
***contact.h:***头文件部分,里面放入了定义的结构体类型和我们要用到的函数声明要在其他几个文件中引用

***test.c:***主函数所在的部分,用于测试项目

***contact.c:***里面是通讯里具体功能的实现

文章目录

    • 一、通讯录的大致框架
      • 1.0在contact.h中定义一些常量方便后续的使用与修改
      • 1.1创建一个包含联系人基本信息的结构体
      • 1.2创建一个包含1.1而且可以显示容量的结构体
      • 1.3搭建基本的框架
    • 二、通讯录的具体功能
      • 2.0初始化通讯录
      • 2.1增加联系人(addContact)
      • 2.15检验是否需要增容(check_capacity)
      • 2.2 查找输入的名字(FindByName)
      • 2.25删除联系人(delContact)
      • 2.3搜索指定联系人并打印信息(searchContact)
      • 2.4调整指定联系人信息(modifyContact)
      • 2.5展示所有联系人信息(showContact)
      • 2.6保存联系人信息到文件中(saveContact)
      • 2.7读取文件中所存的联系人信息(LoadContact)
      • 2.8关闭通讯录(destroyContack)
    • 三、完整代码:
      • 3.1 contact.h头文件部分
      • 3.2contact.c部分
      • 3.3test.c部分

一、通讯录的大致框架

1.0在contact.h中定义一些常量方便后续的使用与修改

#define NAME_MAX 20//名字的最大长度
#define SEX_MAX  5//性别所占最大字节数
#define ADDR_MAX 30//地址所占最大字节数
#define TELE_MAX 12//电话号码最大所占字节数

#define DEFAULT_SZ 3//默认的通讯录初始容量
#define INC_SZ  2//后续对通讯录进行扩容的时候一次扩容两个大小的联系人信息

1.1创建一个包含联系人基本信息的结构体

也是在contack.h的头文件里面定义,因为后期我们会反复用到

typedef struct PeoInfo {//一个联系人所含的信息
	char name[NAME_MAX];//名字
	char sex[SEX_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话
	int age;//年龄
}PeoInfo;

1.2创建一个包含1.1而且可以显示容量的结构体

typedef struct Contact {
	PeoInfo* date;//创建一个类型为联系人信息的指针,后续会让这个指针指向
	//一块申请的内存区域
	int sz;//通讯录当前联系人的个数
	int capacity;//通讯录最大所能容纳的联系人个数
}Contact;

1.3搭建基本的框架

这一步是在test.c函数里面进行的,把大致的框架搭出来,我们后续就只需要编写对应功能的函数就行了

void menu() {//通讯录菜单
	printf("************************************\n");
	printf("******  1. add    2. del      ******\n");
	printf("******  3. search 4. modify   ******\n");
	printf("******  5. show               ******\n");
	printf("******  0. exit               ******\n");
	printf("************************************\n");
}
enum Option {
    EXIT,//退出 0
	ADD,//增加联系人  1
	DEL,//删除联系人   2
	SEARCH,//搜索指定的联系人  3
	MODIFY,//调整联系人信息   4
	SHOW//展示整个通讯录信息   5
};
int main() {
	int input = 0;//输入的选项
	Contact con;//创建一个通讯录的结构体
	InitContact(&con);
	do {
		menu();//打印菜单
		printf("请输入你要输入的选项");
		scanf("%d" ,& input);
		switch (input) {
		case EXIT:
			saveContact(&con);//保存信息
			destroyContact(&con);//关闭整个通讯录
			printf("退出通讯录\n");
			break;
		case ADD:
			addContact(&con);//增加联系人
			break;
		case DEL:
			delContact(&con);//删除联系人
			break;
		case SEARCH:
			searchContact(&con);//搜索指定的联系人
			break;
		case MODIFY:
			modifyContact(&con);//调整联系人信息
			break;
		case SHOW:
			showContact(&con);//展示整个通讯录的信息
			break;
		default://输入了0——5的其他数字
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);//只要input不为0,也就是你不退出,循环就能一直下去
	return 0;
}

搭建框架的核心就是用do-while循环和switch语句与对应功能的函数建立起联系。

二、通讯录的具体功能

2.0初始化通讯录

void InitContact(Contact* pc) {
	assert(pc);//判断pc是否为空指针,若是则中断运行
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ,sizeof(PeoInfo));//先用ptr
	//指针申请一块通讯录初始大小的内存
	//用callo不用malloc原因:在申请一块空间后calloc还能对其进行初始化。
	//不直接对Contact*pc的date指针进行内存申请的原因是为了防止申请的内存为空,
	//所以先用ptr申请
	if (NULL == ptr) {
		perror("InitContact");//判断ptr申请的空间是否为空,若是打印错误信息
		return;
}
	else {
		pc->date = ptr;//ptr不是空,则让pc里的date指针获得这块空间地址
		ptr = NULL;//ptr用不到了所以置为空
		pc->capacity = DEFAULT_SZ;//申请空间成功,所以初始容量为我们申请的
		pc->sz = 0;//当前存入信息的人为0
	}
	LoadContact(pc);//加载文件里面人的信息,这个先别急,后面等下会说如何实现的
}

2.1增加联系人(addContact)

void addContact(Contact* pc) {
	assert(pc);//检验pc是否为空
	check_capacity(pc);//既然我们要增加人肯定要检验容量是否够容纳全部人,下面会说如何实现的
	printf("请输入名字:");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄:"); 
	scanf("%d", &(pc->date[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入地址:");
	scanf("%s", pc->date[pc->sz].addr);
	printf("请输入电话:");
	scanf("%s", pc->date[pc->sz].tele);//输入信息
	pc->sz++;//增加一个人信息,当前人数加一
}

2.15检验是否需要增容(check_capacity)

void check_capacity(Contact *pc){
	assert(pc);
	if (pc->capacity == pc->sz) {//当前人数达到了最大容量则进行增容
		PeoInfo* ptr = (PeoInfo*)realloc(pc->date, sizeof(PeoInfo) * (pc->capacity + INC_SZ));
		//先用ptr申请以防申请的空间为空,原先的最大容量(pc-》capacity)+每次增加的容积(INC_SZ)
		if (NULL == ptr) {//检验是否为空
			perror("check_capacity");
			return;
		}
		else {
			pc->date = ptr;//不为空,则让pc里的date指向那块空间
			pc->capacity = pc->capacity + INC_SZ;//最大容积发生改变
			ptr = NULL;//指针没用了要置为空
			printf("增容成功\n");
		}
	}
}

2.2 查找输入的名字(FindByName)

int FindByName(const Contact* pc,char name[]) {//接收用户要查找的name
	assert(pc);//判断pc是否为NULL,若是中断程序
	int i = 0;
	for (i = 0; i < pc->sz; i++) {
		if (strcmp(name, pc->date[i].name) == 0) {
		 //去遍历date中每一个数据的名字并与name比较,若相同返回0
			return i;//返回找到元素的下标
		}	
	}
	return -1;//没找到返回-1
}

2.25删除联系人(delContact)

void delContact(Contact* pc) {
	assert(pc);//pc若为NULL则中止程序
	printf("请输入你要查找人的名字");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);//pos接收要查找人名字的下标
	int i = 0;
	if (-1 == pos) {//pos为-1则失败
		printf("你要删除的人不存在\n");
		return;
	}
	else {
		for (i = pos; i < pc->sz; i++) {
			pc->date[i] = pc->date[i + 1];//从要删除的人位置开始,让后面的元素去覆盖前一个元素的信息
		}
	}
	pc->sz--;//当前人数信息减一
	printf("删除成功\n");
}

2.3搜索指定联系人并打印信息(searchContact)

void searchContact(Contact* pc) {
	assert(pc);//判断pc是否为空,若是程序终止
	printf("请输入你要查找人的名字");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);//pos接收要查找人名字的下标
	if (-1 == pos) {//pos为-1则失败
		printf("你要查找的人不存在");
	}
	else {
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->date[pos].name,
			pc->date[pos].age,//打印要查找人的信息
			pc->date[pos].sex,
			pc->date[pos].addr,
			pc->date[pos].tele);
	}
}

2.4调整指定联系人信息(modifyContact)

void modifyContact(Contact* pc) {
	assert(pc);
	printf("请输入你要修改人的名字:");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);//pos接收要查找人名字的下标
	if (-1 == pos) {//pos为-1则失败
		printf("你要修改的人不存在");
	}
	else {
		printf("请输入名字:");
		scanf("%s", pc->date[pos].name);//date的下标为pos,也就是要查找人的元素下标
		//对其进行修改
		printf("请输入年龄:");
		scanf("%d", &(pc->date[pos].age));
		printf("请输入性别:");
		scanf("%s", pc->date[pos].sex);
		printf("请输入地址:");
		scanf("%s", pc->date[pos].addr);
		printf("请输入电话:");
		scanf("%s", pc->date[pos].tele);
	}
	printf("修改完成\n");
}

2.5展示所有联系人信息(showContact)

void showContact(const Contact* pc) {
	assert(pc);//pc若为NULL则中止程序
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");//表头
	for (i = 0; i < pc->sz; i++) {//依次打印sz个数据
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->date[i].name,//间距要与表头相同才会对齐一些
			pc->date[i].age,
			pc->date[i].sex,
			pc->date[i].addr,
			pc->date[i].tele);
	}
}

2.6保存联系人信息到文件中(saveContact)

void saveContact(Contact* pc) {
 
	FILE* p = fopen("C:\\Users\\Kaugo\\Desktop\\新建 文本文档.txt", "wb");
	//文件指针指向要打开的文件内存信息
	if (NULL == p) {//判断是否打开
		perror("saveContct");
		return;
	}
	else {
		int i = 0;
		for (i = 0; i < pc->sz; i++) {
			fwrite(pc->date + i, sizeof(PeoInfo), 1, p);
			//遍历将联系人信心一个一个写进去
		}

	}
	fclose(p);//关闭文件
	p = NULL;//指针置为NULL
	printf("保存成功\n");
}

2.7读取文件中所存的联系人信息(LoadContact)

void LoadContact(Contact* pc) {
	assert(pc);
	FILE* p = fopen("C:\\Users\\Kaugo\\Desktop\\新建 文本文档.txt", "rb");
	//文件指针指向要打开文件的信息
	if (NULL == p) {//判断是否打开
		perror("LoadContact");
		return;
	}
	else {
		int i = 0;
		PeoInfo tmp = { 0 };
		while (fread(&tmp, sizeof(PeoInfo), 1, p)) {
			//fread函数返回的是成功读取数据的个数,我们是一个一个读取的,所以当
			//他返回为0的时候也就是文件里面信息读取完了,此时while条件为0也退出循环
			//将读取到的数据放到tmp中。
			check_capacity(pc);//判断当前容积是否够,不够则进行扩容
			pc->date[i] = tmp;//将tmp中的数据放到date【i】中
			i++;
			pc->sz++;//当前人数增加
		}
	}
	fclose(p);//关闭文件
	p = NULL;
}

2.8关闭通讯录(destroyContack)

void destroyContact(Contact* pc) {
	 
	free(pc->date);//将date所指向空间释放
	pc->date = NULL;//指针置为NULL,防止野指针
	pc->sz = 0;//当前人数为0
	pc->capacity = 0;//当前容积为0
	pc = NULL;//指针置为NULL。
}

三、完整代码:

3.1 contact.h头文件部分

#pragma once
#include
#include
#include
#include
 
#define NAME_MAX 20//名字的最大长度
#define SEX_MAX  5//性别所占最大字节数
#define ADDR_MAX 30//地址所占最大字节数
#define TELE_MAX 12//电话号码最大所占字节数

#define DEFAULT_SZ 3//默认的通讯录初始容量
#define INC_SZ  2//后续对通讯录进行扩容的时候一次扩容两个大小的联系人信息

typedef struct PeoInfo {//一个联系人所含的信息
	char name[NAME_MAX];//名字
	char sex[SEX_MAX];//性别
	char addr[ADDR_MAX];//地址
	char tele[TELE_MAX];//电话
	int age;//年龄
}PeoInfo;

typedef struct Contact {
	PeoInfo* date;//创建一个类型为联系人信息的指针,后续会让这个指针指向一块申请的内存区域
	int sz;//通讯录当前联系人的个数
	int capacity;//通讯录最大所能容纳的联系人个数
}Contact;
void check_capacity(Contact* pc);
int FindByName(const Contact* pc, char name[]);
void LoadContact(Contact* pc);
void InitContact(Contact* pc);
void addContact(Contact* pc);
void delContact(Contact* pc);
void showContact(const Contact* pc);
void modifyContact(Contact* pc);
void searchContact(Contact* pc);
void saveContact(Contact* pc);
void destroyContact(Contact* pc);

3.2contact.c部分

#define _CRT_SECURE_NO_WARNINGS 1 
#include"contact.h"

void check_capacity(Contact *pc){
	assert(pc);
	if (pc->capacity == pc->sz) {//当前人数达到了最大容量则进行增容
		PeoInfo* ptr = (PeoInfo*)realloc(pc->date, sizeof(PeoInfo) * (pc->capacity + INC_SZ));
		//先用ptr申请以防申请的空间为空,原先的最大容量(pc-》capacity)+每次增加的容积(INC_SZ)
		if (NULL == ptr) {//检验是否为空
			perror("check_capacity");
			return;
		}
		else {
			pc->date = ptr;//不为空,则让pc里的date指向那块空间
			pc->capacity = pc->capacity + INC_SZ;//最大容积发生改变
			ptr = NULL;//指针没用了要置为空
			printf("增容成功\n");
		}
	}
}
int FindByName(const Contact* pc,char name[]) {//接收用户要查找的name
	assert(pc);//判断pc是否为NULL,若是中断程序
	int i = 0;
	for (i = 0; i < pc->sz; i++) {
		if (strcmp(name, pc->date[i].name) == 0) {
		 //去遍历date中每一个数据的名字并与name比较,若相同返回0
			return i;//返回找到元素的下标
		}	
	}
	return -1;//没找到返回-1
}


void LoadContact(Contact* pc) {
	assert(pc);
	FILE* p = fopen("C:\\Users\\Kaugo\\Desktop\\新建 文本文档.txt", "rb");
	//文件指针指向要打开文件的信息
	if (NULL == p) {//判断是否打开
		perror("LoadContact");
		return;
	}
	else {
		int i = 0;
		PeoInfo tmp = { 0 };
		while (fread(&tmp, sizeof(PeoInfo), 1, p)) {
			//fread函数返回的是成功读取数据的个数,我们是一个一个读取的,所以当
			//他返回为0的时候也就是文件里面信息读取完了,此时while条件为0也退出循环
			//将读取到的数据放到tmp中。
			check_capacity(pc);//判断当前容积是否够,不够则进行扩容
			pc->date[i] = tmp;//将tmp中的数据放到date【i】中
			i++;
			pc->sz++;//当前人数增加
		}
	}
	fclose(p);//关闭文件
	p = NULL;
}

void InitContact(Contact* pc) {
	assert(pc);//判断pc是否为空指针,若是则中断运行
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ,sizeof(PeoInfo));//先用ptr指针申请一块
	//通讯录初始大小的内存
	//用callo不用malloc原因:在申请一块空间后calloc还能对其进行初始化。
	//不直接对Contact*pc的date指针进行内存申请的原因是为了防止申请的内存为空,所以先用ptr申请
	if (NULL == ptr) {
		perror("InitContact");//判断ptr申请的空间是否为空,若是打印错误信息
		return;
}
	else {
		pc->date = ptr;//ptr不是空,则让pc里的date指针获得这块空间地址
		ptr = NULL;//ptr用不到了所以置为空
		pc->capacity = DEFAULT_SZ;//申请空间成功,所以初始容量为我们申请的
		pc->sz = 0;//当前存入信息的人为0
	}
	LoadContact(pc);//加载文件里面人的信息,这个先别急,后面等下会说如何实现的
}


void addContact(Contact* pc) {
	assert(pc);//检验pc是否为空
	check_capacity(pc);//既然我们要增加人肯定要检验容量是否够容纳全部人,下面会说如何实现的
	printf("请输入名字:");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄:"); 
	scanf("%d", &(pc->date[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入地址:");
	scanf("%s", pc->date[pc->sz].addr);
	printf("请输入电话:");
	scanf("%s", pc->date[pc->sz].tele);//输入信息
	pc->sz++;//增加一个人信息,当前人数加一
}

void delContact(Contact* pc) {
	assert(pc);//pc若为NULL则中止程序
	printf("请输入你要查找人的名字");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);//pos接收要查找人名字的下标
	int i = 0;
	if (-1 == pos) {//pos为-1则失败
		printf("你要删除的人不存在\n");
		return;
	}
	else {
		for (i = pos; i < pc->sz; i++) {
			pc->date[i] = pc->date[i + 1];//从要删除的人位置开始,让后面的元素去覆盖前一个元素的信息
		}
	}
	pc->sz--;//当前人数信息减一
	printf("删除成功\n");
}
void showContact(const Contact* pc) {
	assert(pc);//pc若为NULL则中止程序
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");//表头
	for (i = 0; i < pc->sz; i++) {//依次打印sz个数据
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->date[i].name,//间距要与表头相同才会对齐一些
			pc->date[i].age,
			pc->date[i].sex,
			pc->date[i].addr,
			pc->date[i].tele);
	}
}

void modifyContact(Contact* pc) {
	assert(pc);
	printf("请输入你要修改人的名字:");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);//pos接收要查找人名字的下标
	if (-1 == pos) {//pos为-1则失败
		printf("你要修改的人不存在");
	}
	else {
		printf("请输入名字:");
		scanf("%s", pc->date[pos].name);//date的下标为pos,也就是要查找人的元素下标
		//对其进行修改
		printf("请输入年龄:");
		scanf("%d", &(pc->date[pos].age));
		printf("请输入性别:");
		scanf("%s", pc->date[pos].sex);
		printf("请输入地址:");
		scanf("%s", pc->date[pos].addr);
		printf("请输入电话:");
		scanf("%s", pc->date[pos].tele);
	}
	printf("修改完成\n");
}

void searchContact(Contact* pc) {
	assert(pc);//判断pc是否为空,若是程序终止
	printf("请输入你要查找人的名字");
	char name[NAME_MAX] = { 0 };
	scanf("%s", name);
	int pos = FindByName(pc, name);//pos接收要查找人名字的下标
	if (-1 == pos) {//pos为-1则失败
		printf("你要查找的人不存在");
	}
	else {
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->date[pos].name,
			pc->date[pos].age,//打印要查找人的信息
			pc->date[pos].sex,
			pc->date[pos].addr,
			pc->date[pos].tele);
	}
}
void saveContact(Contact* pc) {
 
	FILE* p = fopen("C:\\Users\\Kaugo\\Desktop\\新建 文本文档.txt", "wb");
	//文件指针指向要打开的文件内存信息
	if (NULL == p) {//判断是否打开
		perror("saveContct");
		return;
	}
	else {
		int i = 0;
		for (i = 0; i < pc->sz; i++) {
			fwrite(pc->date + i, sizeof(PeoInfo), 1, p);
			//遍历将联系人信心一个一个写进去
		}

	}
	fclose(p);//关闭文件
	p = NULL;//指针置为NULL
	printf("保存成功\n");
}
void destroyContact(Contact* pc) {
	 
	free(pc->date);//将date所指向空间释放
	pc->date = NULL;//指针置为NULL,防止野指针
	pc->sz = 0;//当前人数为0
	pc->capacity = 0;//当前容积为0
	pc = NULL;//指针置为NULL。
}

3.3test.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. show               ******\n");
	printf("******  0. exit               ******\n");
	printf("************************************\n");
}
enum Option {
    EXIT,//0
	ADD,//增加联系人  1
	DEL,//删除联系人   2
	SEARCH,//搜索指定的联系人  3
	MODIFY,//调整联系人信息   4
	SHOW//展示整个通讯录信息   5
};


int main() {
	int input = 0;//输入的选项
	Contact con;//创建一个通讯录的结构体
	InitContact(&con);
	do {
		menu();//打印菜单
		printf("请输入你要输入的选项");
		scanf("%d" ,& input);
		switch (input) {
		case EXIT:
			saveContact(&con);//保存信息
			destroyContact(&con);//关闭整个通讯录
			printf("退出通讯录\n");
			break;
		case ADD:
			addContact(&con);//增加联系人
			break;
		case DEL:
			delContact(&con);//删除联系人
			break;
		case SEARCH:
			searchContact(&con);//搜索指定的联系人
			break;
		case MODIFY:
			modifyContact(&con);//调整联系人信息
			break;
		case SHOW:
			showContact(&con);//展示整个通讯录的信息
			break;
		default://输入了0——5的其他数字
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);//只要input不为0,也就是你不退出,循环就能一直下去
	return 0;
}

你可能感兴趣的:(c语言,c++,开发语言)