【进阶C语言】通讯录--动态内存加强版

本次代码分成3个模块实现通讯录

通讯录的功能有:

1、增加信息:增加“姓名”、“性别”、“年龄”、“电话”、“地址”。

2、删除信息:选择需要删除的信息的“姓名”,打印与“姓名”相同的相关信息,再选择对应的“序号”删除信息。 -- 可把我调试麻了,小白一枚

3、查找信息:输入需要查找的信息的“姓名”,打印出所有与“姓名”相符合的信息。

4、修改信息:输入需要修改的信息的“序号”,选择对应的元素进行修改。

5、排序:按照“姓名”的ASCLL值进行排序。

6、清空信息:清空所有的信息。

7、打印信息:打印所有的信息。

8、清空页面:system("cls")清理页面--非删除。

不说了,上代码!

contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Contact.h"

void menu(void)
{
	printf("************************************\n");
	printf("****  1.增加信息   2.删除信息   ****\n");
	printf("****  3.查找信息   4.修改信息   ****\n");
	printf("****  5.排序       6.清空信息   ****\n");
	printf("****  7.打印       8.清空页面   ****\n");
	printf("****         0.EXIT              ***\n");
	printf("************************************\n");

}

enum Choise
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	REVISE,
	SORT,
	EMPTY,
	PRINT,
	CLEAN
};//枚举方便查看

int main()
{
	int input = 0;
	//创建通讯录
	contact con;
	//初始化通讯录
	Init_con(&con);

	do
	{
		menu(); //创建目录
		printf("选择功能:>");
		scanf("%d", &input);
		
		switch (input)
		{
		case ADD:
			ADD_con(&con);    //增加信息
			break;
		case DEL:
			Delete_con(&con); //删除信息
			break;
		case SEARCH:
			Search_con(&con); //查找信息
			break;
		case REVISE:
			Recise_con(&con); //修改信息
			break;
		case SORT:
			Sort_con(&con);   //排序信息--按姓名排序
			break;
		case EMPTY:
			Empty_con(&con);   //清空所有的个人信息
			printf("清空完毕!\n");
			break;
		case PRINT:
			Print_con(&con);  //打印通讯录
			break;
		case CLEAN:
			perror("CLEAN");
			system("cls");    //清空页面
			printf("清理成功!\n");
			break;
		case EXIT:
			Destroyed(&con);
			printf("再见!\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}

	} while (input);

	return 0;
}

contact.h


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

#define MAX_NAME 10
#define MAX_TELE 13
#define MAX_ADDR 30
#define MAX_SEX 7
#define MAX_STRUCT 3
#define MAX_SZ 2


//创建通讯录
typedef struct PeoInformation
{
	int Sort;
	char Name[MAX_NAME];
	char Sex[MAX_SEX];
	int Age;
	char Tele[MAX_TELE];
	char Addr[MAX_ADDR];
}Infor;


//动态内存
typedef struct contact
{
	Infor* data;   //指向动态内存
	int sz;        //信息个数
	int capacity;  //当前内存最大容量
}contact;


//初始化通讯录
void Init_con(contact* pc);

//增加信息
void ADD_con(contact*pc);

//打印信息
void Print_con(contact* pc);

//查找信息
void Search_con(contact* pc);

//删除信息
void Delete_con(contact* pc);

//修改信息
void Recise_con(contact* pc);

//排序信息
void Sort_con(contact* pc);

//清空所有的个人信息
void Empty_con(contact* pc);

//释放内存free
void Destroyed(contact* pc);

execule.c

#include "Contact.h"

//动态内存初始化
void Init_con(contact* pc)
{
	pc->data = (Infor*)malloc(MAX_STRUCT * sizeof(Infor));

	//内存设置
	pc->sz = 0;
	pc->capacity = MAX_STRUCT;

	if (pc->data == NULL)
	{
		perror("calloc");
		return;
	}

}

//打印全部信息的函数(与单个打印 Little_print 不同)
void Print_con(contact* pc)
{
	int i = 0;
	//添加列表
	printf("|%-3s\t|%-4s\t|%-7s\t|%-3s\t|%-13s\t|%-30s\n", "序号", "姓名", "性别", "年龄", "电话", "地址");

	for (i = 0; i < pc->sz; i++)
	{
		printf("|%-3d\t|%-4s\t|%-7s\t|%-3d\t|%-13s\t|%-30s\n", 
									pc->data[i].Sort,
									pc->data[i].Name,
									pc->data[i].Sex,
									pc->data[i].Age,
									pc->data[i].Tele,
									pc->data[i].Addr  );

	}
}

//增加信息
void ADD_con(contact* pc)
{

	if (pc->sz == pc->capacity)
	{
		Infor* ptr = (Infor*)realloc(pc->data, (pc->capacity + MAX_SZ) * sizeof(Infor));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += MAX_SZ;
			printf("扩容成功\n");
		}
		else
		{
			perror("ADD_con");
			printf("扩容失败\n");
			return;
		}

	}

	//添加信息
	printf("姓名:>");
	scanf("%s", pc->data[pc->sz].Name); //因为name是数组首元素地址,所以不用&
	printf("性别:>");
	scanf("%s", pc->data[pc->sz].Sex); 
	printf("年龄:>");
	scanf("%d", &pc->data[pc->sz].Age); //Age是int类型,要&
	printf("电话:>");
	scanf("%s", pc->data[pc->sz].Tele);
	printf("地址:>");
	scanf("%s", pc->data[pc->sz].Addr);
	pc->data[pc->sz].Sort = pc->sz+1;

	pc->sz++;  //容量+1
	printf("添加成功!\n");	
	
}

//方便打印单个 i 的函数
static void Little_print(contact* pc, int i)
{
	printf("|%-3s\t|%-4s\t|%-7s\t|%-3s\t|%-13s\t|%-30s\n", "序号", "姓名", "性别", "年龄", "电话", "地址");

	printf("|%-3d\t|%-4s\t|%-7s\t|%-3d\t|%-13s\t|%-30s\n",
		pc->data[i].Sort,
		pc->data[i].Name,
		pc->data[i].Sex,
		pc->data[i].Age,
		pc->data[i].Tele,
		pc->data[i].Addr);

}

//查找名字
static int Find_name(contact* pc, char name[])
{
	int i = 0;
	int count = 0;  //根据count是否发生变化来查找信息
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->data[i].Name) == 0)
		{
			Little_print(pc, i); //打印单个的函数
			count= 1;
		}
	}
	if (0 == count)
	{
		printf("没有此人信息\n");
		return 0;
	}
	return 1;
}

//查找信息
void Search_con(contact* pc)
{

	char name[MAX_NAME] = { 0 };
	printf("输入要查找的名字:>\n");
	scanf("%s", name);
	//查找名字
	Find_name(pc, name);

}

//动态p内存 -- 删除模块
static int* P_MAX(int* p, int sz)
{
	int count = 1;  //基数

	if (*(p+sz-1) != '\0')
	{
		int*ptr = (int*)realloc(p, (MAX_STRUCT + count * MAX_SZ) * sizeof(int));
		if (ptr != NULL)
		{
			p = ptr;
			printf("扩容成功\n");
			count++;
		}
		else
		{
			perror("int* P_MAX()");
			printf("扩容失败\n");
			return;
		}
	}

}

//删除模块专用函数 -- 判断后储存
static int* Judge_num(contact*pc, char *name) 
{
	int p[MAX_STRUCT] = { 0 };
	int i = 0;
	int num = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->data[i].Name) == 0)
		{
			//相同就储存在数组中
			p[num] = pc->data[i].Sort;
			//判断有无满载
			int sz = sizeof(p) / sizeof(p[0]);
			P_MAX(p, sz, pc);
		}
	}
	return p;
}

//删除模块专用函数 -- 判断judge储存后的数值与选择的序号是否相等
static int compare_num(int* p, int num)
{
	while (*p)
	{
		if (num == *p)
			return 1;
		p++;
	}
	return 0;

}

//删除信息
void Delete_con(contact* pc)
{
	//判断有没有信息
	if (pc->sz == 0)
	{
		printf("没有可删除的信息了~\n");
		return;
	}

	//输入删除者的名字
	char name[MAX_NAME] = { 0 };
	printf("输入删除的名字:>");
	scanf("%s", name);

	//找出名字
	int ret = Find_name(pc, name);
	if (0 == ret)
		return;

	//选择删除编号
	int num = 0;
	printf("选择要删除的编号:>");
	scanf("%d", &num);
	int* p = Judge_num(pc, name); //用Judge_num储存判断好的数以数组指针的形式返回
	int tmp = compare_num(p, num); 
	if (0 == tmp)
	{
		printf("输入错误\n");
		return;
	}

	if (num<0 || num>pc->sz)
	{
		printf("输入错误\n");
		return;
	}

	//判断选择编号
	if (pc->data[num - 1].Sort != num)
	{
		printf("输入编号不符~\n");
		return;
	}

	//调整序列
	int i = 0;
	for (i = num - 1; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
		pc->data[i].Sort = pc->data[i].Sort - 1;  //为了让序列衔接上,要减去1
	}

	pc->sz--;
	printf("删除成功!\n");


}

//修改信息
void Recise_con(contact* pc)
{
	if (pc->sz == 0)
	{
		printf("没有可修改的信息了~\n");
		return;
	}

	//选择要修改的序号
	int num = 0;
	printf("输入修改的序号:>");
	scanf("%d", &num);

	//显示一下
	Little_print(pc, num-1);
	
	//修改元素
	char element[5] = { 0 };
	printf("输入修改的元素:>");
	scanf("%s", element);

	char value[MAX_ADDR] = { 0 };  //用最大的住址信息来存放,就不用每一个变量都创建了
	int age = 0;

	if (strcmp(element, "姓名") == 0)
	{
		printf("输入修改的值:>\n");
		scanf("%s", pc->data[num - 1].Name);
	}
	else if (strcmp(element, "性别") == 0)
	{
		printf("输入修改的值:>\n");
		scanf("%s", pc->data[num - 1].Sex);
	}
	else if (strcmp(element, "年龄") == 0)
	{
		printf("输入修改的值:>\n");
		scanf("%d", &pc->data[num - 1].Age);
	}
	else if (strcmp(element, "电话") == 0)
	{
		printf("输入修改的值:>\n");
		scanf("%s", pc->data[num - 1].Tele);
	}
	else if (strcmp(element, "地址") == 0)
	{
		printf("输入修改的值:>\n");
		scanf("%s", pc->data[num - 1].Addr);
	}
	else
		printf("错误\n");
	printf("修改成功\n");
	//打印一下
	Little_print(pc, num - 1);
}

//排序信息
void Sort_con(contact* pc)
{
	int i = 0;
	int j = 0;

	//冒泡排序法
	for (i = 0; i < pc->sz; i++)
	{
		int count = 0;

		for (j = 0; j < pc->sz - i - 1; j++)
		{
			if (strcmp(pc->data[j].Name,pc->data[j+1].Name) > 0)
			{
				Infor tmp = pc->data[j];    //这里的tmp用Infor类型,因为我们要存储的值的Infor结构体
				pc->data[j] = pc->data[j + 1];
				pc->data[j + 1] = tmp;
				pc->data[j + 1].Sort = pc->data[j + 1].Sort + 1;  //序号改一下
				pc->data[j].Sort = pc->data[j].Sort - 1;

				count = 1;  //如果有交换动作,就改变count
			}

		}
		if (0 == count)  //如果count为0,说明没有可交换的值,跳出
			break;
		
	}
	printf("顺序已排好!\n");
	Print_con(pc);
}

//清空所有的个人信息
void Empty_con(contact* pc)
{
	int i = 0;
	for (i = 0; i < pc->sz+1; i++)
	{
		pc->sz--;   //减少下标相当于删除,只是隐藏起来了
		if (0 == pc->sz--)
		{
			break;
		}
	}
}

//释放内存
void Destroyed(contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz;
	pc->capacity;
	printf("释放成功\n");
}

效果如图:

 

如果出现自己的 Infor 结构体打印出来是奇怪的信息,调一调动态内存相关参数,如果发生改变,说明是动态内存扩容哪个地方出错了。

 别写成了常量,要随着空间变化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值