【进阶C语言】通讯录(后期会升级)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

一.基本框架与功能

在这里插入图片描述

准备工作
一.分模块开发
 1.test.c,实现模块的测试环节
 2.contact.c实现函数的功能
 3.contact.h实现函数的命名与结构体的使用
下面重点讲解函数实现的函数在开始时会提供头文件以便于提高本文的可读性。

二.头文件的详细内容

#include<stdio.h>//printf,scanf,perror
#include<stdlib.h>//system,malloc,realloc
#include<string.h>//strcmp
//对开辟的大小方便之后的统一修改。
enum SIZE
{
	NAME_SIZE=10,
	SEX_SIZE=5,
	TELE_SIZE=15,
	ADDRE_SIZE=20,
	DEFAULT_SIZE=2,
	ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{
	ADD=1,
	DEL,
	FIND,
	MODIFY,
	PRINT,
	SORT,
	EXIT
};
//联系人信息
typedef struct people
{
	char name[NAME_SIZE];
	int age;
	char sex[SEX_SIZE];
	char tele[TELE_SIZE];
	char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{
	int count;//联系人个数
	int capacity;//当前最大容量
	peo CON[];//柔性数组利用内存池的概念使内存管理更加高效并且free只要一次更方便。
}contact;

//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);

三.函数的实现

1.打印菜单

void menu()
{
	printf("******************************************\n");
	printf("******** 1.增加联系人 2.删除联系人 *******\n");
	printf("******** 3.查找联系人 4.修改联系人 *******\n");
	printf("******** 5.打印联系人 6.排序联系人 *******\n");
	printf("******** 7.退出通讯录              *******\n");
	printf("******************************************\n");

}

参数无返回类型无可以写return;

2.初始化通讯录

void Init_contact(contact** p)
{
	*p = (contact*)malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
	if (*p != NULL)
	{
		(*p)->count = 0;
		(*p)->capacity = DEFAULT_SIZE;
	}
	else
	{
		perror("Init_contact");
		return;
	}
}

1.这里的开辟空间默认为两个整形+初始能存的联系人个数2
2.结构体指针访问成员只能是一级指针要改变一级指针就得给函数传二级指针
3.这里也可以用calloc不过比较麻烦并且效率比malloc略低。
4.注意对开辟空间返回的地址进行检查

3.添加联系人信息

void Add_Contact(contact** p)
{
	int judge = 0;
	//判断内存是否够
	if ((*p)->count== (*p)->capacity)
	{
		printf("通讯录已满请确定是否要增容1是0否");
		scanf("%d", &judge);
		if (judge)
		{
			contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) *   (DEFAULT_SIZE + ADD_SIZE));
			if (ptr != NULL)
			{
				(*p) = ptr;
				(*p)->capacity += ADD_SIZE;
				printf("增容成功\n");
			}
			else
			{
				perror("Add_Contact");
				printf("增容失败\n");
				return;
			}
		}
		else
		{
			return;
		}

	}
    //输入信息部分
	printf("请输入姓名");
	scanf("%s", (*p)->CON[(*p)->count].name);

	printf("请输入年龄");
	scanf("%d", &(*p)->CON[(*p)->count].age);

	printf("请输入性别");
	scanf("%s", (*p)->CON[(*p)->count].sex);

	printf("请输入电话");
	scanf("%s", (*p)->CON[(*p)->count].tele);

	printf("请输入住址");
	scanf("%s", (*p)->CON[(*p)->count].addre);
	printf("增加成功\n");
	(*p)->count++;
}

1.对realloc返回值进行检查如果为空要及时的报错
2.在输入信息之后要对联系人个数进行加1
3.输入信息时要确定访问的成员的类型以确定是否取地址
补充取地址数组名与数组名在进行输入的时候效果相同因为它们的数值是相同的但是意义不同。

4.打印联系人信息

void Print_Contact(contact* p)
{
	if (p->count == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", 
												"年龄", 
												"性别", 
												"电话", 
												"住址");
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name, 
													p->CON[i].age, 
													p->CON[i].sex, 
													p->CON[i].tele, 
													p->CON[i].addre);
	}
}

1.在通讯录无信息时应该及时的提醒。
2.注意下标与联系人信息的个数的关系
3.如果打印的内容太长建议要进行换行提高代码的易读性。
4.打印的时候需要对齐要设置好格式进行打印这样打印的内容较为简洁美观。

5.查找名字

const int Find_By_name(contact* p,char*arr)
{
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
		if (strcmp(p->CON[i].name, arr) == 0)
		{
			return i;
		}
	}
	return -1;
}

1.由于这个函数只服务于实现函数的模块所以加上const
2.strcmp比较两个字符串如果相等返回0
3.如果没有字符串返回-1如果找到则返回其下标
4.这个函数是服务于查找联系人修改联系人删除联系人的

6.删除联系人信息

void Del_Contact(contact* p)
{
	char name[20] = { 0 };
	printf("请输入要删除的联系人");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret!=-1)
	{
		int i = 0;
		for (i = ret; i < p->count-1; i++)
		{
			p->CON[ret] = p->CON[ret + 1];
		}
		p->count--;
		printf("已删除\n");
	}
	else
	{
		printf("查无此人\n");
	}
}

1.这里删除的思路是进行覆盖至于最后一个元素的情况在联系人个数减过之后再添加会进行覆盖。
2.注意这里的i的范围结合下面的代码可知可能会发生数组越界的问题所以要减去1
3.结构体数组的成员可以直接覆盖前一个成员跟数组的特性一样

7.查找联系人

void Find_Contact(contact* p)
{
	char name[20] = { 0 };
	printf("请输入要查找的联系人");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
		printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", 
													"年龄", 
													"性别", 
													"电话", 
													"住址");
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name,
													p->CON[ret].age, 
			                                        p->CON[ret].sex,
			                                        p->CON[ret].tele, 
													p->CON[ret].addre);
	}
	else
	{
		printf("查无此人\n");
	}
}

8.修改联系人信息

void Modify_Contact(contact* p)
{
	char name[20] = { 0 };
	printf("请输入要修改的联系人");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
		printf("请输入姓名");
		scanf("%s", p->CON[ret].name);

		printf("请输入年龄");
		scanf("%d", &p->CON[ret].age);

		printf("请输入性别");
		scanf("%s", p->CON[ret].sex);

		printf("请输入电话");
		scanf("%s", p->CON[ret].tele);

		printf("请输入住址");
		scanf("%s", p->CON[ret].addre);
		printf("修改成功\n");
	}
	else
	{
		printf("查无此人\n");
	}
}

9.排序联系人按照名字

int my_cmp(const void* e1, const void* e2)
{
	return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{
	qsort(p->CON, p->count, sizeof(peo), my_cmp);
	printf("排序成功\n");
}

1.快排要写一个比较函数由于是字符串比较要用到字符串比较函数
2.要注意快排的参数——排序的数组排序的个数元素的大小比较函数

四.总结

1.test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
int main()
{
	contact *con =NULL;
	Init_contact(&con);
	int input = 0;
	do
	{
		menu();
		printf("请输入");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			system("cls");
			Add_Contact(&con);
			break;
		case DEL:
			system("cls");
			Del_Contact(con);
			break;
		case FIND:
			system("cls");
			Find_Contact(con);
			break;
		case MODIFY:
			system("cls");
			Modify_Contact(con);
			break;
		case PRINT:
			system("cls");
			Print_Contact(con);
			break;
		case SORT:
			system("cls");
			Sort_Contact(con);
			break;
		case EXIT:
			system("cls");
			Distory_Contact(&con);
			printf("退出成功\n");
			break;
		default:
			printf("输入错误\n");
			break;
		}

	} while (input!=EXIT);

	return 0;
}

2.contact.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.退出通讯录              *******\n");
	printf("******************************************\n");

}
void Init_contact(contact** p)
{
	*p = malloc(4*2 + sizeof(peo) * DEFAULT_SIZE);
	if (*p != NULL)
	{
		(*p)->count = 0;
		(*p)->capacity = DEFAULT_SIZE;
	}
	else
	{
		perror("Init_contact");
		return;
	}
}
void Add_Contact(contact** p)
{
	int judge = 0;
	if ((*p)->count== (*p)->capacity)
	{
		printf("通讯录已满请确定是否要增容1是0否");
		scanf("%d", &judge);
		if (judge)
		{
			contact* ptr = (contact*)realloc(*p, 4 * 2 + sizeof(peo) * (DEFAULT_SIZE + ADD_SIZE));
			if (ptr != NULL)
			{
				(*p) = ptr;
				(*p)->capacity += ADD_SIZE;
				printf("增容成功\n");
			}
			else
			{
				perror("Add_Contact");
				printf("增容失败\n");
				return;
			}
		}
		else
		{
			return;
		}

	}

	printf("请输入姓名");
	scanf("%s", (*p)->CON[(*p)->count].name);

	printf("请输入年龄");
	scanf("%d", &(*p)->CON[(*p)->count].age);

	printf("请输入性别");
	scanf("%s", (*p)->CON[(*p)->count].sex);

	printf("请输入电话");
	scanf("%s", (*p)->CON[(*p)->count].tele);

	printf("请输入住址");
	scanf("%s", (*p)->CON[(*p)->count].addre);
	printf("增加成功\n");
	(*p)->count++;
}

void Print_Contact(contact* p)
{
	if (p->count == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[i].name, 
													p->CON[i].age, 
													p->CON[i].sex, 
													p->CON[i].tele, 
													p->CON[i].addre);
	}
}
const int Find_By_name(contact* p,char*arr)
{
	int i = 0;
	for (i = 0; i < p->count; i++)
	{
		if (strcmp(p->CON[i].name, arr) == 0)
		{
			return i;
		}
	}
	return -1;
}
void Del_Contact(contact* p)
{
	char name[20] = { 0 };
	printf("请输入要删除的联系人");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret!=-1)
	{
		int i = 0;
		for (i = ret; i < p->count-1; i++)
		{
			p->CON[ret] = p->CON[ret + 1];
		}
		p->count--;
		printf("已删除\n");
	}
	else
	{
		printf("查无此人\n");
	}
}
void Find_Contact(contact* p)
{
	char name[20] = { 0 };
	printf("请输入要查找的联系人");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
		printf("%-5s\t%3s\t%-3s\t%-12s\t%-20s\t\n", "姓名", "年龄", "性别", "电话", "住址");
		printf("%-5s\t%3d\t%-3s\t%-12s\t%-20s\t\n", p->CON[ret].name, p->CON[ret].age, 
			                                        p->CON[ret].sex, p->CON[ret].tele, 
													p->CON[ret].addre);
	}
	else
	{
		printf("查无此人\n");
	}
}
void Modify_Contact(contact* p)
{
	char name[20] = { 0 };
	printf("请输入要修改的联系人");
	scanf("%s", name);
	int ret = Find_By_name(p, name);
	if (ret != -1)
	{
		printf("请输入姓名");
		scanf("%s", p->CON[ret].name);

		printf("请输入年龄");
		scanf("%d", &p->CON[ret].age);

		printf("请输入性别");
		scanf("%s", p->CON[ret].sex);

		printf("请输入电话");
		scanf("%s", p->CON[ret].tele);

		printf("请输入住址");
		scanf("%s", p->CON[ret].addre);
		printf("修改成功\n");
	}
	else
	{
		printf("查无此人\n");
	}


}


void Distory_Contact(contact** p)
{
	free(*p);
	*p = NULL;
}



int my_cmp(const void* e1, const void* e2)
{
	return strcmp(((peo*)e1)->name, ((peo*)e2)->name);
}
void Sort_Contact(contact* p)
{
	qsort(p->CON, p->count, sizeof(peo), my_cmp);
	printf("排序成功\n");
}

3.contact.h

#include<stdio.h>//printf,scanf,perror
#include<stdlib.h>//system,malloc,realloc
#include<string.h>//strcmp
//对开辟的大小方便之后的统一修改。
enum SIZE
{
	NAME_SIZE=10,
	SEX_SIZE=5,
	TELE_SIZE=15,
	ADDRE_SIZE=20,
	DEFAULT_SIZE=2,
	ADD_SIZE=2
};
//功能的选项数字赋予一定的意义
enum function
{
	ADD=1,
	DEL,
	FIND,
	MODIFY,
	PRINT,
	SORT,
	EXIT
};
//联系人信息
typedef struct people
{
	char name[NAME_SIZE];
	int age;
	char sex[SEX_SIZE];
	char tele[TELE_SIZE];
	char addre[ADD_SIZE];
}peo;
//通讯录信息
typedef struct Contact
{
	int count;//联系人个数
	int capacity;//当前最大容量
	peo CON[];//柔性数组利用内存池的概念使内存管理更加高效并且free只要一次更方便。
}contact;

//菜单
void menu();
//初始化通讯录
void Init_contact(contact** p);//要修改一级指针所以要传一级指针的地址用二级指针来接收
//添加联系人信息
void Add_Contact(contact** p);//同理
//打印通讯录
void Print_Contact(contact* p);
//删除联系人信息
void Del_Contact(contact* p);
//查找联系人信息
void Find_Contact(contact* p);
//修改联系人信息
void Modify_Contact(contact* p);
//释放已开辟的内存空间
void Distory_Contact(contact** p);//同理
//按照名字进行排序通讯录
void Sort_Contact(contact* p);
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6