使用结构体实现通讯录(静态版本+动态版本)

一、通讯录的基本功能

实现一个通讯录,用来保存其名字,年龄,性别,电话,住址
1、增加联系人
2、删除指定联系人
3、修改指定联系人
4、查找指定联系人
5、显示当先所存所有联系人的信息
6、对当前联系人按照某个标准进行排序

二、通讯录的实现逻辑及代码(静态版本)

实现方式:

考虑到通讯录要存储联系人的姓名,年龄,性别,电话,所以考虑使用结构体来存储通讯录的数据信息。对于这个实现我们采用多文件的形式来完成,test.c用来实现整个通讯录的测试逻辑,contact.h实现对函数,标识符,结构体等声明,contact.c用来实现整个通讯录的增删查改显示以及排序函数的实现。

静态版本代码如下:

test.c文件实现对整个通讯录的测试,根据不同的菜单进行相应的操作,如选择1进行增加通讯录中的联系人,选择2删除指定的联系人,选择3按照名字查找通讯录中的联系人,选择4可以对联系人的姓名,年龄,性别,电话进行修改,选择5可以将当前通讯录中所存储的信息进行展示,选择6将按照名字的进行排序。代码有相应的注释可供参考

#include"contact.h"
int main()
{
	int input = 0;
	struct contact con;
	//一定要记得对这个con结构体进行初始化,否则可能会出现内存非法访问的问题
	init_contact(&con);
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			add_contact(&con);//要对结构体内容进行改变,必须要传址
			break;
		case 2:
			del_contact(&con);//要对结构体内容进行改变,必须要传址
			break;
		case 3:
			search(&con);
			break;
		case 4:
			modify(&con);//要对结构体内容进行改变,必须要传址
			break;
		case 5:
			show_contact(&con);
			break;
		case 6:
			sort(&con);
			break;
		case 0:
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

contact,h主要对函数进行声明,定义相应的结构体类型,声明相应的头文件等,其代码如下:

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

#define max_num 100
#define max_name 20
#define max_sex 5
#define max_tel 12

//考虑到通讯录要存储联系人的姓名,年龄,性别,电话,所以考虑使用结构体来存储数据
struct People_info
{
	char name[max_name];
	int age;
	char sex[max_sex];
	char tel[max_tel];
};

//该contact结构体包含联系人信息结构体(由于要存储多人所以定义一个结构体数组),sz是用来记录通讯录中有多少人
struct contact
{
	struct People_info people[max_num];//最大用来存储联系人的结构体数组
	int sz;//用来记录当前存了多少联系人了
};
//菜单打印函数
void menu();

//初始化通讯录
void init_contact(struct contact *p);

//增加通讯录联系人
void add_contact(struct contact *p);


//显示通讯录
void show_contact(struct contact*p);


//删除通讯录中的联系人
void del_contact(struct contact* p);

//查找通讯录中的联系人
void search(struct contact* p);

//修改通讯录中的联系人
void modify(struct contact* p);

//根据名字进行升序排序
void sort(struct contact* p);

 contact.c主要用来实现增,删,查,改,显示,按照名字进行升序排列,其代码实现方式如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"

void menu()
{
	printf("******   1.add       2.del    *****\n");
	printf("******   3.search    4.modify *****\n");
	printf("******   5.show      6.sort   *****\n");
	printf("******        0.exit          *****\n");
}
void modify_menu()
{
	printf("******   1.name       2.age   *****\n");
	printf("******   3.sex        4.tel   *****\n");
	printf("******        0.no modify     *****\n");
}
//搜寻查找
int find(char*str,struct contact*p)
{
	for (int i = 0; i < p->sz; i++)
	{
		if (!strcmp(str, p->people[i].name))
		{
			return i;
		}
	}
	return -1;
}

//对通讯录进行初始化
void init_contact(struct contact* p)
{
	p->sz = 0;
	char arr[] = "\0";
	for (int i = 0; i < max_num; i++)//对联系人进行初始化
	{
		strcpy(p->people[i].name, arr);
		strcpy(p->people[i].sex, arr);
		strcpy(p->people[i].tel, arr);
		p->people[i].age=0;
	}
}


//增加通讯录联系人
void add_contact(struct contact* p)
{
	if (p->sz > max_num)
	{
		printf("容量已满,无法无法增加\n");
		return;//容量已经满了直接返回
	}
	else
	{
		printf("请输入要添加联系人的姓名:>");
		scanf("%s", p->people[p->sz].name);
		printf("\n");
		printf("请输入要添加联系人的年龄:>");
		scanf("%d", &(p->people[p->sz].age));
		printf("\n");
		printf("请输入要添加联系人的性别:>");
		scanf("%s", p->people[p->sz].sex);
		printf("\n");
		printf("请输入要添加联系人的电话:>");
		scanf("%s", p->people[p->sz].tel);
		p->sz++;
		printf("添加成功\n");
	}
}

//通讯录中的显示
void show_contact(struct contact* p)
{
	printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");
	for (int i = 0; i < p->sz; i++)
	{
		printf("%-10s\t%-5d\t%-5s\t%-20s\n", 
			p->people[i].name,
			p->people[i].age, 
			p->people[i].sex,
			p->people[i].tel);
	}
	printf("\n");
}

//删除通讯录中的联系人
void del_contact(struct contact* p)
{
	if (!p->sz)
	{
		printf("通讯录为空,无法进行删除操作\n");
		return;
	}
	printf("请输入要删除的联系人:>");
	char str[max_name]="\0";
	scanf("%s", str);
	int del=find(str,p);
	if (del == -1)//通讯录找不到该联系人就返回,提前结束
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除联系人
	for (int i = del; i < p->sz - 1; i++)
	{
		p->people[i].age = p->people[i + 1].age;
		strcpy(p->people[i].name, p->people[i + 1].name);
		strcpy(p->people[i].sex, p->people[i + 1].sex);
		strcpy(p->people[i].tel, p->people[i + 1].tel);
	}
	p->sz--;
	printf("删除成功\n");
}

//查找通讯录中的联系人
void search(struct contact* p)
{
	printf("强输入想要查找的联系人姓名:>");
	char str[max_name] = "\0";
	scanf("%s", str);
	int ret=find(str, p);
	if (ret == -1)
	{
		printf("在该通讯录中找不到\n");
		return;
	}
	printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");;
	printf("%-10s\t%-5d\t%-5s\t%-20s\n",
		p->people[ret].name,
		p->people[ret].age,
		p->people[ret].sex,
		p->people[ret].tel);
}

//修改通讯录中的联系人
void modify(struct contact* p)
{
	printf("请输入要修改人的名字:>");
	char str[max_name] = "\0";
	scanf("%s", str);
	int ret = find(str, p);
	if (ret == -1)
	{
		printf("要修改的人在通讯录中不存在\n");
	}
	else
	{
		int input = 0;
		do//该逻辑与test.c文件的逻辑基本一致,选择想要修改的或者不修改退出
		{
			modify_menu();
			printf("请选择想要修改的:>");
			scanf("%d", &input);
			char tmp[max_name] = "\0";//用max_name比其他的大,所以足够容下其他的修改输入
			int tt = 0;
			switch (input)
			{
			case 1:
				printf("请输入想要修改联系人的名字:>");
				scanf("%s", tmp);
				strcpy(p->people[ret].name, tmp);
				break;
			case 2:
				printf("请输入想要修改联系人的年龄:>");
				scanf("%d", &tt);
				p->people[ret].age = tt;
				break;
			case 3:
				printf("请输入想要修改联系人的性别:>");
				scanf("%s", tmp);
				strcpy(p->people[ret].sex, tmp);
				break;
			case 4:
				printf("请输入想要修改联系人的电话:>");
				scanf("%s", tmp);
				strcpy(p->people[ret].tel, tmp);
				break;
			case 0:
				printf("不修改\n");
				break;
			default :
				printf("选择错误请重新选择\n");
				break;
			}
		} while (input);
	}
}

//排序,按照名字进行升序排序
int cmp(const void* str1, const void* str2)
{
	return strcmp(((struct People_info*)str1)->name, ((struct People_info*)str2)->name);
}
void sort(struct contact* p)
{
	int num = p -> sz;
	struct contact* ptr = p;
	qsort(ptr->people, p->sz, sizeof(p->people[0]), cmp);//调用qsort库函数进行排序
	show_contact(p);
}

modify修改函数的实现加入了和test.c基本一致的逻辑结构,通过对应的选择来选择修改相应的部分或不修改。

三、测试结果

增加测试:

通过增加了4个人信息显示如下:

删除之后显示如下:

查找通讯录中不存在的联系人:

查找通讯录中存在的联系人

 修改也是类似的

排序之前:

排序之后:

 动态版本代码(逻辑与静态版本一致):

实现的方式和静态版本的逻辑是一致的(只是在选择0退出释放开辟的空间以及初始化函数部分,增加联系人函数的进行了一些修改),动态版本使用的是

test.c代码如下:

#include"contact.h"
int main()
{
	int input = 0;
	struct contact con;
	//一定要记得对这个con结构体进行初始化,否则可能会出现内存非法访问的问题
	init_contact(&con);
	
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			add_contact(&con);//要对结构体内容进行改变,必须要传址
			break;
		case 2:
			del_contact(&con);//要对结构体内容进行改变,必须要传址
			break;
		case 3:
			search(&con);
			break;
		case 4:
			modify(&con);
			break;
		case 5:
			show_contact(&con);
			break;
		case 6:
			sort(&con);
			break;
		case 0:
			free(con.people);//退出释放开辟的空间
            con.people = NULL;//将指针置为空指针
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

 contact.h文件代码如下:

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

#define init_cmp 1//默认最初的容量为1
#define max_name 20
#define max_sex 5
#define max_tel 12

//考虑到通讯录要存储联系人的姓名,年龄,性别,电话,所以考虑使用结构体来存储数据
struct People_info
{
	char name[max_name];
	int age;
	char sex[max_sex];
	char tel[max_tel];
};
struct contact
{
	struct People_info *people;
	int sz;//用来记录当前存了多少联系人了
	int cap;//记录当前通讯录最大的空间存储
};
//菜单打印函数
void menu();

//初始化通讯录
void init_contact(struct contact *p);

//增加通讯录联系人
void add_contact(struct contact *p);


//显示通讯录
void show_contact(struct contact*p);


//删除通讯录中的联系人
void del_contact(struct contact* p);

//查找通讯录中的联系人
void search(struct contact* p);

//修改通讯录中的联系人
void modify(struct contact* p);

//根据名字进行升序排序
void sort(struct contact* p);

 contact.c文件(主要对增加通讯录联系人的这个函数和初始化通讯录进行修改)代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"

void menu()
{
	printf("******   1.add       2.del    *****\n");
	printf("******   3.search    4.modify *****\n");
	printf("******   5.show      6.sort   *****\n");
	printf("******        0.exit          *****\n");
}
void modify_menu()
{
	printf("******   1.name       2.age   *****\n");
	printf("******   3.sex        4.tel   *****\n");
	printf("******        0.no modify     *****\n");
}
//搜寻查找
int find(char*str,struct contact*p)
{
	for (int i = 0; i < p->sz; i++)
	{
		if (!strcmp(str, p->people[i].name))
		{
			return i;
		}
	}
	return -1;//通讯录中没查到此人就返回-1
}

//对通讯录进行初始化
void init_contact(struct contact* p)
{
	p->people = (struct People_info*)malloc(sizeof(struct People_info) * init_cmp);
	if (p->people==NULL)
	{
		perror("malloc:");//申请失败,提醒是malloc开辟空间失败
		return;
	}
	p->sz = 0;
	char arr[] = "\0";
	for (int i = 0; i < init_cmp; i++)//对联系人进行初始化
	{
		strcpy(p->people[i].name, arr);
		strcpy(p->people[i].sex, arr);
		strcpy(p->people[i].tel, arr);
		p->people[i].age=0;
	}
	p->cap = init_cmp;//防止空间浪费,所以初始容量大小为2
}


//增加通讯录联系人
void add_contact(struct contact* p)
{
	if ((p->sz) >= (p->cap))
	{
		p->cap += 2;//每次容量增加2
		struct People_info* ptr = (struct People_info*)realloc(p->people, sizeof(struct People_info) * (p->cap));//申请失败,提醒是realloc开辟空间失败
		if (ptr == NULL)
		{
            p->cap -= 2;//没增容成功,就减到原来的容量      
			printf("增容失败\n");
			return;//失败直接返回
		}
		p->people = ptr;
		printf("增容成功\n");
	}
	printf("请输入要添加联系人的姓名:>");
	scanf("%s", p->people[p->sz].name);
	printf("\n");
	printf("请输入要添加联系人的年龄:>");
	scanf("%d", &(p->people[p->sz].age));
	printf("\n");
	printf("请输入要添加联系人的性别:>");
	scanf("%s", p->people[p->sz].sex);
	printf("\n");
	printf("请输入要添加联系人的电话:>");
	scanf("%s", p->people[p->sz].tel);
	p->sz++;
	printf("添加成功\n");
}

//通讯录中的显示
void show_contact(struct contact* p)
{
	printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");
	for (int i = 0; i < p->sz; i++)
	{
		printf("%-10s\t%-5d\t%-5s\t%-20s\n", 
			p->people[i].name,
			p->people[i].age, 
			p->people[i].sex,
			p->people[i].tel);
	}
	printf("\n");
}

//删除通讯录中的联系人
void del_contact(struct contact* p)
{
	if (!p->sz)
	{
		printf("通讯录为空,无法进行删除操作\n");
		return;
	}
	printf("请输入要删除的联系人:>");
	char str[max_name]="\0";
	scanf("%s", str);
	int del=find(str,p);
	if (del == -1)//通讯录找不到该联系人就返回,提前结束
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除联系人
	for (int i = del; i < p->sz - 1; i++)
	{
		p->people[i].age = p->people[i + 1].age;
		strcpy(p->people[i].name, p->people[i + 1].name);
		strcpy(p->people[i].sex, p->people[i + 1].sex);
		strcpy(p->people[i].tel, p->people[i + 1].tel);
	}
	p->sz--;
	printf("删除成功\n");
}

//查找通讯录中的联系人
void search(struct contact* p)
{
	printf("请输入想要查找的联系人姓名:>");
	char str[max_name] = "\0";
	scanf("%s", str);
	int ret=find(str, p);
	if (ret == -1)
	{
		printf("在该通讯录中找不到\n");
		return;
	}
	printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");;
	printf("%-10s\t%-5d\t%-5s\t%-20s\n",
		p->people[ret].name,
		p->people[ret].age,
		p->people[ret].sex,
		p->people[ret].tel);
}

//修改通讯录中的联系人
void modify(struct contact* p)
{
	printf("请输入要修改人的名字:>");
	char str[max_name] = "\0";
	scanf("%s", str);
	int ret = find(str, p);
	if (ret == -1)
	{
		printf("要修改的人在通讯录中不存在\n");
	}
	else
	{
		int input = 0;
		do
		{
			modify_menu();
			printf("请选择想要修改的:>");
			scanf("%d", &input);
			char tmp[max_name] = "\0";//用max_name比其他的大,所以足够容下其他的修改输入
			int tt = 0;
			switch (input)
			{
			case 1:
				printf("请输入想要修改联系人的名字:>");
				scanf("%s", tmp);
				strcpy(p->people[ret].name, tmp);
				break;
			case 2:
				printf("请输入想要修改联系人的年龄:>");
				scanf("%d", &tt);
				p->people[ret].age = tt;
				break;
			case 3:
				printf("请输入想要修改联系人的性别:>");
				scanf("%s", tmp);
				strcpy(p->people[ret].sex, tmp);
				break;
			case 4:
				printf("请输入想要修改联系人的电话:>");
				scanf("%s", tmp);
				strcpy(p->people[ret].tel, tmp);
				break;
			case 0:
				printf("不修改\n");
				break;
			default :
				printf("选择错误请重新选择\n");
				break;
			}
		} while (input);
	}
}

//排序,按照名字字符进行排序
int cmp(const void* str1, const void* str2)
{
	return strcmp(((struct People_info*)str1)->name, ((struct People_info*)str2)->name);
}
void sort(struct contact* p)
{
	int num = p -> sz;
	struct contact* ptr = p;
	qsort(ptr->people, p->sz, sizeof(p->people[0]), cmp);
	show_contact(p);
}

 最小的容量设置的为1,当存第二个联系人将会重新申请空间增加容量,每次增加2个存放联系人信息的空间。

总结:该通讯录主要使用了结构体,结构体数组,结构体嵌套结构体在使用结构体首选传址而不是传值,需要注意的,要对结构体中的信息进行修改要传相应的结构体地址。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值