练手项目层中阶2—《详解动态版本——通讯录管理系统》

在这里插入图片描述

🏳‍🌈前言

第一个版本是静态的通讯录,就是用的结构体数组来存储的信息,这样会导致空间不够或者浪费的缺点;因此动态版本就解决这样的问题,减少此情况的发生。接下来讲解中阶版本的练手小项目——《动态通讯录管理系统》

🔊项目需求

动态版本的通讯录也是解决联系人的增、删、查、改、显示、排序的操作。如果看了我写的静态版本的通讯录文章的,其实结构和上一篇文章提到的差不多,只是改变了申请存储空间的方式。通过动态开辟内存来存储信息。

📝项目知识点包含

此动态版本的通讯录,主要是C语言中的动态内存管理知识、结构体、指针操作等,加上C语言的基础知识,接下来就详细描述该项目。👇👇👇👇

🧩项目框架

在这里插入图片描述

🔑框架拆解分析

接下来分别对Struct_Book1.h头文件、Struct_Book1.c源文件、test_book.c源文件作分析:👇

📚Struct_Book1.h头文件分析

在这里插入图片描述
代码展示

#define DEFAULT_SIZE 3

#define MAX_NAME 12
#define MAX_AGE 3
#define MAX_SEX 4
#define MAX_TELE 12
#define MAX_ADDRESS 40
//枚举功能
enum address_book
{
	Exit,
	Add,
	Delete,
	Find,
	Modify,
	Sort,
	Show
};


//信息结构体
typedef struct person_information
{
	char name[MAX_NAME];
	char age[MAX_AGE];
	char sex[MAX_SEX];
	char tel[MAX_TELE];
	char address[MAX_ADDRESS];
}PenInfo;


typedef struct Contact
{
	PenInfo* data;//和静态的对比,就是此处改变了,用结构体指针来表示
	int capacity_size;//动态空间容量
	int number_person;//实际的人的数量
}Con;


void init_contact(Con* ptr);//初始化函数
void addition_information(Con* ptr);//增加函数
void delete_information(Con* ptr);//删除函数
void find_information(Con* ptr);//查找函数
void modify_information(Con* ptr);//修改函数
void sort_information(Con* ptr);//排序函数
void show_information(const Con* ptr);//显示函数
void destroy_contact(Con* ptr);//释放函数

📚Struct_Book1.c源文件分析

直接代码展示出来:主要展示动态申请的代码块

//初始化函数[动态开辟]
void init_contact(Con* ptr)
{
	ptr->data = (PenInfo*)malloc(DEFAULT_SIZE*sizeof(PenInfo));
	//判断
	if (ptr->data == NULL)
	{
		perror("malloc");
		return;
	}
	ptr->capacity_size = DEFAULT_SIZE;//初始的空间大小
	ptr->number_person = 0;
}


//扩容检测
void check_capacity(Con* ps)
{
	assert(ps);
	if (ps->capacity_size == ps->number_person)
	{
		//扩容
		PenInfo* new_capacity = (PenInfo*)realloc(ps->data, 
		(ps->capacity_size+2) * sizeof(PenInfo));//可以修改为成倍数增长
		
		//判断,此处不能直接把开辟的空间,
		//如果开辟失败会返回NULL,那么直接赋值给原来的空间,会把原来的内容全部删除,所以先判断是否申请成功
		if (new_capacity == NULL)
		{
			printf("增容失败!\n");
			return;
		}
		//申请成功
		if (new_capacity != NULL)
		{
			ps->data = new_capacity;
			ps->capacity_size += 2;//此处可以修改成倍数增长,
			//pc->capacity*=2;//此处用倍数,那么在初始化的时候
			//也要改为倍数增长
			printf("增容成功!\n");
			printf("现在容量:%d\n", ps->capacity_size);
		}
	}
}

📚test_book.c源文件分析

代码如下:没有具体说的,比较好理解


void test()
{
	Con con;
	init_contact(&con);
	int input = 0;
	while (1)
	{
		menu();
		printf("请选择功能:\n");
		scanf("%d", &input);
		switch (input)
		{
		case Exit:
			destroy_contact(&con);//主要的是要记住释放申请的空间
			printf("欢迎下次使用!\n");
			return;
		case Add:
			addition_information(&con);
			break;
		case Delete:
			delete_information(&con);
			break;
		case Find:
			find_information(&con);
			break;
		case Modify:
			modify_information(&con);
			break;
		case Sort:
			sort_information(&con);
			break;
		case Show:
			show_information(&con);
			break;
		default:
			printf("选择错误,请重新选择:\n");
			break;
		}
		_getch();
		system("cls");
	}
}

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

注意:释放申请的动态空间,把它还给计算机内存,“有借有还、再借不难”

🎥效果演示

在这里插入图片描述
在这里插入图片描述

✨完整代码

Struct_Book1.h

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<conio.h>
#include<Windows.h>

#define DEFAULT_SIZE 3

#define MAX_NAME 12
#define MAX_AGE 3
#define MAX_SEX 4
#define MAX_TELE 12
#define MAX_ADDRESS 40
//枚举功能
enum address_book
{
	Exit,
	Add,
	Delete,
	Find,
	Modify,
	Sort,
	Show
};


//信息结构体
typedef struct person_information
{
	char name[MAX_NAME];
	char age[MAX_AGE];
	char sex[MAX_SEX];
	char tel[MAX_TELE];
	char address[MAX_ADDRESS];
}PenInfo;


typedef struct Contact
{
	PenInfo* data;
	int capacity_size;
	int number_person;
}Con;


void init_contact(Con* ptr);//初始化函数
void addition_information(Con* ptr);//增加函数
void delete_information(Con* ptr);//删除函数
void find_information(Con* ptr);//查找函数
void modify_information(Con* ptr);//修改函数
void sort_information(Con* ptr);//排序函数
void show_information(const Con* ptr);//显示函数
void destroy_contact(Con* ptr);//释放函数

Struct_Book1.c

#include "Struct_Book1.h"

//初始化函数[动态开辟]
void init_contact(Con* ptr)
{
	ptr->data = (PenInfo*)malloc(DEFAULT_SIZE*sizeof(PenInfo));
	//判断
	if (ptr->data == NULL)
	{
		perror("malloc");
		return;
	}
	ptr->capacity_size = DEFAULT_SIZE;
	ptr->number_person = 0;
}


//扩容检测
void check_capacity(Con* ps)
{
	assert(ps);
	if (ps->capacity_size == ps->number_person)
	{
		//扩容
		PenInfo* new_capacity = (PenInfo*)realloc(ps->data, (ps->capacity_size+2) * sizeof(PenInfo));//可以修改为成倍数增长
		//判断
		if (new_capacity == NULL)
		{
			printf("增容失败!\n");
			return;
		}
		if (new_capacity != NULL)
		{
			ps->data = new_capacity;
			ps->capacity_size += 2;//此处可以修改成倍数增长
			printf("增容成功!\n");
			printf("现在容量:%d\n", ps->capacity_size);
		}
	}
}

//增加函数
void addition_information(Con* ptr)
{
	//增加之前必须判断是否指针为空和空间是否满
	assert(ptr);//断言一下
	//检查是否扩容
	check_capacity(ptr);
	//满足条件,添加数据
	printf("------------------------\n");
	printf("|请输入联系人对应的信息|\n");
	printf("|信息录入中……        |\n");
	printf("------------------------\n");
	printf("姓名—>:");
	scanf("%s", ptr->data[ptr->number_person].name);
	printf("年龄—>:");
	scanf("%s", ptr->data[ptr->number_person].age);
	printf("性别—>:");
	scanf("%s", ptr->data[ptr->number_person].sex);
	printf("电话—>:");
	scanf("%s", ptr->data[ptr->number_person].tel);
	printf("地址—>:");
	scanf("%s", ptr->data[ptr->number_person].address);
	ptr->number_person++;
	printf("添加成功\n");
}


//显示函数
void show_information(const Con* ptr)
{
	assert(ptr);
	if (ptr->number_person == 0)
	{
		printf("通讯录为空,无法显示!\n");
		return;
	}
	printf("*************************************************************************************************\n");
	printf("*****************************          通讯录信息         ***************************************\n");
	printf("*************************************************************************************************\n");
	printf("-------------------------------------------------------------------------------------------------\n");
	printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n","姓名","年龄","性别","电话","地址");
	for (int i = 0; i < ptr->number_person; i++)
	{
		printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", ptr->data[i].name
			, ptr->data[i].age
			, ptr->data[i].sex
			, ptr->data[i].tel
			,ptr->data[i].address);
	}
	printf("-------------------------------------------------------------------------------------------------\n");



}


//只能在当前.c文件中使用
static int find(Con* ps,char* name1)
{
	assert(ps);
	for (int i = 0; i < ps->number_person; i++)
	{
		//此处不能这样比较
		//if (ps->data[i].name == name1)
		//{
		//	return i;//返回找到的位置
		//}
		if ((strcmp(ps->data[i].name, name1)) == 0)
		{
			return i;
		}
	}
	return -1;
}

//删除函数
void delete_information(Con* ptr)
{
	//断言
	assert(ptr);
	if (ptr->number_person == 0)
	{
		printf("通讯录为空,无法删除!\n");
		return;
	}
	//找到对应要删除的联系人
	char name[MAX_NAME];
	printf("请输入要删除联系人的姓名:");
	scanf("%s", name);
	int ret=find(ptr,name);
	if (ret == -1)
	{
		printf("没找到,无法删除!\n");
		return;
	}
	//删除
	for (int i = ret; i < ptr->number_person - 1; i++)
	{
		ptr->data[i] = ptr->data[i + 1];
	}
	//人数-1
	ptr->number_person--;
	printf("删除成功!\n");
	show_information(ptr);
}


//查找函数
void find_information(Con* ptr)
{
	assert(ptr);
	if (ptr->number_person == 0)
	{
		printf("通讯录为空,无法查找!\n");
		return;
	}
	char name1[MAX_NAME];
	printf("请输入要查找联系人的姓名:");
	scanf("%s", name1);
	int ret = find(ptr,name1);
	if (ret == -1)
	{
		printf("没找到!\n");
		return;
	}
	printf("-------------------------------------------------------------------------------------------------\n");
	printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", ptr->data[ret].name
			, ptr->data[ret].age
			, ptr->data[ret].sex
			, ptr->data[ret].tel
			, ptr->data[ret].address);
	printf("-------------------------------------------------------------------------------------------------\n");
}


//修改函数
void modify_information(Con* ptr)
{
	assert(ptr);
	if (ptr->number_person == 0)
	{
		printf("通讯录为空,无法修改!\n");
		return;
	}
	char name2[MAX_NAME];
	printf("请输入要修改联系人的姓名:");
	scanf("%s", name2);
	int ret = 0;
	ret = find(ptr,name2);
	if (ret == -1)
	{
		printf("没找到!\n");
		return;
	}
	printf("修改进行中…………\n");
	printf("请输入新的姓名:");
	scanf("%s", ptr->data[ret].name);
	printf("请输入新的年龄:");
	scanf("%s", ptr->data[ret].age);
	printf("请输入新的性别:");
	scanf("%s", ptr->data[ret].sex);
	printf("请输入新的电话:");
	scanf("%s", ptr->data[ret].tel);
	printf("请输入新的地址:");
	scanf("%s", ptr->data[ret].address);

	printf("修改成功!\n");
	show_information(ptr);
}



 int compar_by_name(const void* e1, const void* e2)
 {
	 return strcmp(((PenInfo*)e1)->name,((PenInfo*)e2)->name);
 }

 int compar_by_age(const void* e1, const void* e2)
 {
	 return strcmp(((PenInfo*)e1)->age, ((PenInfo*)e2)->age);
 }


//排序函数
void sort_information(Con* ptr)
{
	assert(ptr);
	if (ptr->number_person == 0)
	{
		printf("通讯录为空,无法排序!\n");
		return;
	}

	printf("请选择排序方式:1、按照姓名排序,2、按照年龄排序。\n");
	int select1= 0;
	scanf("%d", &select1);
	if (select1 == 1)
	{
		//qsort()用法
		//void qsort (void* base, size_t num, size_t size,int (*compar)(const void*, const void*));
		/*
		base ——>Pointer to the first object of the array to be sorted, converted to a void*.
		num  ——>Number of elements in the array pointed to by base.size_t is an unsigned integral type.
		size  ——> Size in bytes of each element in the array.size_t is an unsigned integral type.
		compar  ——> Pointer to a function that compares two elements.This function is called repeatedly 
		by qsort to compare two elements. 
		It shall follow the following prototype:int compar (const void* p1, const void* p2);*/

		qsort(ptr->data, ptr->number_person, sizeof(PenInfo), compar_by_name);
		printf("排序成功!\n");
	}
	if (select1 == 2)
	{
		qsort(ptr->data, ptr->number_person, sizeof(PenInfo), compar_by_age);
		printf("排序成功!\n");
	}

	
}


//释放函数
void destroy_contact(Con* ptr)
{
	free(ptr->data);
	ptr->data = NULL;
}

test_book.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Struct_Book1.h"


void menu()
{
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t*********        通讯录       *********\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  1、添加联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  2、删除联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  3、查找联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  4、修改联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  5、通讯录排序  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  6、显示联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  0、退出通讯录  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");

}


void test()
{
	Con con;
	init_contact(&con);
	int input = 0;
	while (1)
	{
		menu();
		printf("请选择功能:\n");
		scanf("%d", &input);
		switch (input)
		{
		case Exit:
			destroy_contact(&con);
			printf("欢迎下次使用!\n");
			return;
		case Add:
			addition_information(&con);
			break;
		case Delete:
			delete_information(&con);
			break;
		case Find:
			find_information(&con);
			break;
		case Modify:
			modify_information(&con);
			break;
		case Sort:
			sort_information(&con);
			break;
		case Show:
			show_information(&con);
			break;
		default:
			printf("选择错误,请重新选择:\n");
			break;
		}
		_getch();
		system("cls");
	}
}

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

动态版本的就这样了,后面会更新文件版本和数据库版本的通讯录👌
在这里插入图片描述

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值