C language - dynamic memory allocation - transformation of dynamic address book (12.3)

Table of contents

The dynamic address book needs to be modified:

1. Modify the structure for storing the address book

2. Transformation and initialization of address book implementation

3. Improve the implementation of adding contacts

4. Dynamic address book source code and links to static address book implementations

Write at the end:


The dynamic address book needs to be modified:

1. Modify the structure for storing the address book

In the contact.h file:

//通讯录中存放一个人的信息
typedef struct PeoInfo//typedef简化结构体名称
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

//动态增长版本的通讯录
typedef struct Contact
{
	PeoInfo* data;//指向存放人信息的空间
	int sz;//用来存放数组元素个数
	int capacity;//当前通讯录的最大容量
}Contact;

We don't hard case the address book, but use pointers.

2. Transformation and initialization of address book implementation

Referenced in the contact.h file:

//通讯录初始的大小和每次增容的大小
#define DEFAULT_SZ 3
#define INC_SZ 2

Implemented in the contact.c file:

//初始化通讯录//动态版
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;//通讯录中存放0个人的信息
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));//通过calloc开辟空间
	//判断
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	pc->data = ptr;//data指针得到开辟的空间的地址
	pc->capacity = DEFAULT_SZ;//初始容量赋值
}

3. Improve the implementation of adding contacts

Implemented in the contact.c file:

In fact, the operation of adding contact information is not different from the static address book.

However, if the dynamic address book is full, it needs to be expanded.

//增加联系人//动态版
void AddContact(Contact* pc)
{
	assert(pc);
	
	//增容
	CheckCapacity(pc);

	//增加一个人的信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	//通过pc指针访问data数组的结构体类型的元素,进而访问结构体成员

	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pc->sz].age));//age不是数组,需要取地址

	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);

	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);

	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);

	pc->sz++;//代表数组中的元素个数+1
}

We pack the capacity-enhancing function into a function implementation:

//增容函数
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)//如果容量满了,就进来
	{
		//通过realloc函数进行增容,原容量+INC_SZ(可以根据自己喜好设置)
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		//判断
		if (ptr == NULL)
		{
			perror("CheckCapacity::realloc");
			return;
		}
		pc->data = ptr;//data指针接收增容后的内存的地址
		pc->capacity += INC_SZ;//容量也按设定增加
		printf("增容成功\n");//提示增容成效
	}
}

In this way, if the address book is full, it will automatically increase the capacity.

4. Dynamic address book source code and links to static address book implementations

The link to realize the static address book: http://t.csdn.cn/kVy9X

source code:

test.c file

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"

void menu()
{
	printf("\n");
	printf("—————————— 通讯录 ———————————-\n");
	printf("—————————————————————————-\n");
	printf("————————   1.添加联系人    ————————\n");
	printf("—————————————————————————-\n");
	printf("————————   2.删除联系人    ————————\n");
	printf("—————————————————————————-\n");
	printf("————————   3.查找联系人    ————————\n");
	printf("—————————————————————————-\n");
	printf("————————   4.修改联系人信息  ———————\n");
	printf("—————————————————————————-\n");
	printf("————————   5.整理通讯录    ————————\n");
	printf("—————————————————————————-\n");
	printf("————————   6.查看整个通讯录  ———————\n");
	printf("—————————————————————————-\n");
	printf("————————   0.退出通讯录    ————————\n");
	printf("—————————————————————————-\n");
	printf("\n");
}

void test()
{
	int input = 0;

	//创建通讯录con
	Contact con;

	//初始化通讯录
	InitContact(&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 SHOW:
			ShowContact(&con);
			break;
		case EXIT:
			//DestroyContact(&con);
			printf("通讯录已退出\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
}

int main()//主函数里不要放太多东西
{
	test();
	return 0;
}

contact.h file:

#pragma once//防止头文件重复引用

//提前将需要使用的头文件引用,
//具体实现通讯录是,需要头文件可以直接添加
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>

//通过#define定义的常量,方便管理和使用
#define MAX 100
#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//typedef简化结构体名称
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char addr[ADDR_MAX];
	char tele[TELE_MAX];
}PeoInfo;

//动态增长版本的通讯录
typedef struct Contact
{
	PeoInfo* data;//指向存放人信息的空间
	int sz;//用来存放数组元素个数
	int capacity;//当前通讯录的最大容量
}Contact;

创建一个结构体将数组和数组中存放的元素数封装//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];//data这个数组元素的类型的是结构体PeoInfo
//	                  //用来存放联系人信息
//	int sz;//用来存放数组元素个数
//}Contact;

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

//初始化通讯录
void InitContact(Contact* pc);

销毁通讯录
//void DestroyContact(Contact* pc);

//增加联系人
void AddContact(Contact* pc);

//删除联系人
void DelContact(Contact* pc);

//查找联系人
void SearchContact(const Contact* pc);

//修改指定联系人
void ModifyContact(Contact* pc);

//整理通讯录
void SortContact(Contact* pc);

//显示通讯录的信息
void ShowContact(const Contact* pc);

contact.c file

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"

初始化通讯录//静态版
//void InitContact(Contact* pc)
//{
//  assert(pc);
//	pc->sz = 0;//代表数组中有0个元素
//	memset(pc->data, 0, sizeof(pc->data));//data是整个数组的大小,初始化成0
//}

//初始化通讯录//动态版
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;//通讯录中存放0个人的信息
	PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));//通过calloc开辟空间
	//判断
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	pc->data = ptr;//data指针得到开辟的空间的地址
	pc->capacity = DEFAULT_SZ;//初始容量赋值
}

销毁创建的内存
//void DestroyContact(Contact* pc)
//{
//	free(pc->data);
//	pc->data = NULL;
//}

//增容函数
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)//如果容量满了,就进来
	{
		//通过realloc函数进行增容,原容量+INC_SZ(可以根据自己喜好设置)
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		//判断
		if (ptr == NULL)
		{
			perror("CheckCapacity::realloc");
			return;
		}
		pc->data = ptr;//data指针接收增容后的内存的地址
		pc->capacity += INC_SZ;//容量也按设定增加
		printf("增容成功\n");//提示增容成效
	}
}


增加联系人//静态版
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)//如果通讯录满了
//	{
//		printf("通讯录已满,无法添加\n");
//		return;//就会直接返回
//	}
//
//	//增加一个人的信息
//	printf("请输入名字:>");
//	scanf("%s", pc->data[pc->sz].name);
//	//通过pc指针访问data数组的结构体类型的元素,进而访问结构体成员
//
//	printf("请输入年龄:>");
//	scanf("%d", &(pc->data[pc->sz].age));//age不是数组,需要取地址
//
//	printf("请输入性别:>");
//	scanf("%s", pc->data[pc->sz].sex);
//
//	printf("请输入地址:>");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	printf("请输入电话:>");
//	scanf("%s", pc->data[pc->sz].tele);
//
//	pc->sz++;//代表数组中的元素个数+1
//}

//增加联系人//动态版
void AddContact(Contact* pc)
{
	assert(pc);
	
	//增容
	CheckCapacity(pc);

	//增加一个人的信息
	printf("请输入名字:>");
	scanf("%s", pc->data[pc->sz].name);
	//通过pc指针访问data数组的结构体类型的元素,进而访问结构体成员

	printf("请输入年龄:>");
	scanf("%d", &(pc->data[pc->sz].age));//age不是数组,需要取地址

	printf("请输入性别:>");
	scanf("%s", pc->data[pc->sz].sex);

	printf("请输入地址:>");
	scanf("%s", pc->data[pc->sz].addr);

	printf("请输入电话:>");
	scanf("%s", pc->data[pc->sz].tele);

	pc->sz++;//代表数组中的元素个数+1
}

//显示通讯录的信息
void ShowContact(const Contact* pc)
{
	assert(pc);
	printf("%-10s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
	int i = 0;
	for (i = 0; i < pc->sz; i++)//遍历通讯录并打印
	{
		printf("%-10s\t%-4d\t%-5s\t%-20s\t%-12s\n",
				pc->data[i].name,
 				pc->data[i].age,
				pc->data[i].sex,
				pc->data[i].addr,
				pc->data[i].tele);
	}
}

//查找函数
int FindByName(const Contact* pc, char name[])
{
	int i = 0;
	int del = 0;
	for (i = 0; i < pc->sz; i++)//遍历通讯录
	{
		if (strcmp(pc->data[i].name, name) == 0)
		{   //通过strcmp函数判断要查找的联系人是否存在
			del = i;
			return del;//返回数组下标(要查找的元素的位置)
		}
	}
	return -1;//找不到
}

//删除联系人
void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };//初始化name数组(字符串)

	if (pc->sz == 0)//判断通讯录中是否存在联系人
	{
		printf("通讯录为空,无法删除\n");
		return;
	}

	//找到要删除的人
	printf("请输入要删除的人的名字:>");
	scanf("%s", name);//输入字符串
	int ret = FindByName(pc, name);//分装字符串查找函数
	if (-1 == ret)
	{
		printf("要删除的人不存在\n");
		return;
	}

	//删除
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];//将存放在被删除的联系人后面的联系人信息,
   	}                                 //通过循环一个个往前覆盖
	pc->sz--;//数组元素-1
	printf("删除成功\n");
}

//查找联系人
void SearchContact(const Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };//初始化name数组(字符串)
	printf("请输入要查找人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);//函数复用
	if (-1 == pos)
	{
		printf("要查找的人不存在\n");
		return;
	}

	//打印信息//我实现的是左对齐,并用水平制表符使打印出来的观感更好
	printf("%-10s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
		printf("%-10s\t%-4d\t%-5s\t%-20s\t%-12s\n",
			pc->data[pos].name,
			pc->data[pos].age,
			pc->data[pos].sex,
			pc->data[pos].addr,
			pc->data[pos].tele);
}

//修改指定联系人
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };//初始化name数组(字符串)
	printf("请输入要修改人的名字:>");
	scanf("%s", name);
	int pos = FindByName(pc, name);//函数复用
	if (-1 == pos)
	{
		printf("要修改的人不存在\n");
		return;
	}

	//重新录入
	printf("请输入修改后的名字:>");
	scanf("%s", pc->data[pos].name);

	printf("请输入修改后的年龄:>");
	scanf("%d", &(pc->data[pos].age));//age不是数组,需要取地址

	printf("请输入修改后的性别:>");
	scanf("%s", pc->data[pos].sex);

	printf("请输入修改后的地址:>");
	scanf("%s", pc->data[pos].addr);

	printf("请输入修改后的电话:>");
	scanf("%s", pc->data[pos].tele);

	printf("修改完成\n");
}

//整形排序的实现
int CmpContactByAge(const void* e1, const void* e2)
{
	//这个排出来的是升序,如果想排降序,只需将e1和e2的位置调换即可
	return ((Contact*)e1)->data->age - ((Contact*)e2)->data->age;
}

//整理通讯录
void SortContact(Contact* pc)
{
	assert(pc);
	int sz = pc->sz;
	//通过qsort函数辅助排序
	qsort(pc->data, sz, sizeof(pc->data[0]), CmpContactByAge);
	printf("排序成功\n");
}

Write at the end:

The above is the content of this article, thank you for reading.

If you like this article, please like and comment, and write down your opinions.

If you want to learn programming with me, you might as well follow me, we will learn and grow together.

I will output more high-quality content in the future, welcome to watch.

Guess you like

Origin blog.csdn.net/Locky136/article/details/128687055