C语言实现通讯录--动态版

这篇具有很好参考价值的文章主要介绍了C语言实现通讯录--动态版。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、题目要求

实现一个通讯录,联系人的数量可多可少

二、解题思路

1.在静态版本的基础上改用动态的方法:
(1)默认能够存放三个人的信息
(2)不够的话,每次增加两个人的信息
2.其他功能不变

三、模块划分

建立三个文件:
test.c 用于测试通讯录的相关功能
contsct.c 通讯录的实现模块(用函数实现功能)
contact.h 声明(函数的声明)

四、代码实现

test.c

#define _CRT_SECURE_NO_WARNINGS 1
//C语言实现通讯录--动态版
/*
解题思路
1.在静态版本的基础上改用动态的方法:
(1)默认能够存放三个人的信息
(2)不够的话,每次增加两个人的信息
2.其他功能不变
*/
//菜单
#include "contact.h"
void menu() {
	printf("****************************************************\n");
	printf("**********1.add*********2.del***********************\n");
	printf("**********3.search******4.modify********************\n");
	printf("**********5.show********6.sort**********************\n");
	printf("**********0.exit************************************\n");
}
//通讯录功能用枚举方法列举出来,提高代码的可读性
/*
在主函数中的switch...case...语句中选择功能时,case 1,2,3...这样的选项不能让代码阅读者清晰地联想到各个数字代表实现什么功能
但是使用枚举,在case语句中用case 1代表增加联系人的时候就可写成case add
当枚举中的选项和菜单上的数字匹配上之后,在case语句中想实现哪个功能,写哪个选项就可以了
这样的话,case里面的选项和我们想实现的功能的意思就关联起来了
*/
enum Option {
	Exit,
	add,
	del,
	search,
	modify,
	show,
	sort
};
int main() {
	int input = 0;
	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 show:
		{
			ShowContact(&con);
			break;
		}
		case sort:
		{
			SortContact(&con);
			break;
		}
		case Exit:
		{
			DestroyContact(&con);//销毁通讯录:整个通讯录都是动态开辟来的,退出时要释放掉
			printf("退出通讯录\n");
			break;
		}
		default:
		{
			printf("选择错误\n");
			break;
		}
		}
	} while (input);

	return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"

//初始化通讯录
void InitContact(Contact* pc) {
	pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (pc->data == NULL) {
		printf("通讯录初始化失败:%s\n", strerror(errno));
		return;
	}
	pc->sz = 0;
	pc->capacity = DEFAULT_SZ;
}
//检测容量的函数
//扩容成功,返回1
//扩容失败,返回0
void CheckCapacity(Contact* pc) {
	if (pc->sz == pc->capacity) { //有效信息个数等于容量的时候,需要扩容
		PeoInfo* ptr=(PeoInfo*)realloc(pc->data, (pc->capacity + INC_sz) * sizeof(PeoInfo));//将扩容后的地址交给新指针
		//判断扩容是否成功
		//扩容失败,打印错误信息,返回
		//扩容成功,将新指针交给pc->data维护,通讯录容量变动
		if (ptr == NULL) {
			printf("CheckCapacity:%s\n", strerror(errno));
			return 0;
		}
		else {
			pc->data = ptr;
			pc->capacity += INC_sz;
			printf("增容成功,当前容量:%d\n", pc->capacity);
			return 1;
		}
	}
	//如果通讯录未满,不进入上面的if语句,直接返回1
	return 1;
}

//增容
void AddContact(Contact* pc) {
	//对检测通讯录容量的函数的返回值进行判断
	if (0 == CheckCapacity) {
		printf("空间不够,扩容失败\n");
		return 0;
	}
	else {
		printf("请输入名字:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &pc->data[pc->sz].age);
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pc->sz].addr);

		pc->sz++;
		printf("添加成功\n");
	}
}

//销毁通讯录
void DestroyContact(Contact* pc) {
	free(pc->data);  
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	printf("释放内存\n");
}

//显示联系人信息
void ShowContact(Contact* pc) {
	int i = 0;
	//打印标题
	//在%后面加上负号表示左对齐的方式,在%s的s前面加上数字可以限制打印出来最多几个字节
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++) {
		printf("%-10s %-4d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
	}
}
//实际上,删查改联系人都需要先在通讯录中查找
//为了减少代码的冗余度,可以封装一个查找的函数FindByName
//封装的这个函数前面加static,这个函数只能在自己所在的.c文件中使用,其他的源文件看不见该函数,对它加以保护
//根据名字在通讯录中查找下标的函数
static int FindByName(const Contact* pc, char name[]) {
	int i = 0;
	for (i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			return i;
		}
	}
	return -1;
	//找不到直接返回-1
	/*
	不要写成
	if(i==pc->sz){
		return -1;
	}
	因为写成这样,if进去,条件成立才有返回,不成立无返回
	编译器在编译时发现这样的代码考虑不周全,有些情况是存在返回值的,就会发出警告
	所以,严谨的情况下,直接返回既清晰又严谨
	*/
}


//删除联系人函数
void DelContact(Contact* pc) {
	if (pc->sz == 0) {
		printf("通讯录为空,无法删除\n");
		return;
	}
	//1.根据要删除的人的名字找到在通讯录中的下标
	char name[MAX_NAME] = { 0 };
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1) {
		printf("要删除的人不存在\n");
		return;
	}
	//2.删除pos位置上的数据
	int i = 0;
	for (i = pos; i < pc->sz; i++) {
		pc->data[i] = pc->data[i + 1];//从pos下标处开始覆盖
	}
	pc->sz--;
	printf("删除成功\n");
}
//查找联系人 
void SearchContact(const Contact* pc) {//查找不需要修改通讯录,使用const加以保护,防止被修改
	char name[MAX_NAME] = { 0 };
	printf("请输入要查找的人的名字:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1) {
		printf("要查找的人不存在\n");
		return;
	}
	//找到的话直接打印这个联系人的信息
	printf("%-10s %-4s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-10s %-4d %-5s %-12s %-30s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr);
}
//修改联系人
void ModifyContact(Contact* pc) {
	char name[MAX_NAME] = { 0 };
	printf("请输入要修改的人的名字:");
	scanf("%s", name);
	int pos = FindByName(pc, name);
	if (pos == -1) {
		printf("要修改的人不存在\n");
		return;
	}
	//修改:把要修改人下标为pos的信息全都再录入一遍
	printf("请输入名字:");
	scanf("%s", pc->data[pos].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pos].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pos].sex);
	printf("请输入电话:");
	scanf("%s", pc->data[pos].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pos].addr);

	printf("修改成功\n");
}
//排序联系人
//使用qsort进行排序,要自定义一个排序方法
int cmp_by_name(const void* e1, const void* e2) {//e1,e2指针各自指向一个人的信息
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc) {
	//按照名字来排序
	qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_name);
	printf("排序成功\n");
	//调用显示联系人函数ShowContact,自动打印一下排序后的结果
	ShowContact(pc);
}

contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

#define DEFAULT_SZ 3 //默认是3个
#define INC_sz 2  //扩容每次增加2个

//结构体存放每个联系人的信息
typedef struct PeoInfo { //typedef:给已定义的变量类型起个别名,这里的作用是给struct Peoinfo起个别名PeoInfo
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;
//结构体存放通讯录
typedef struct Contact {
	PeoInfo *data; //data指向存放数据的空间
	int sz;        //sz记录通讯录中的有效信息个数
	int capacity; //通讯录当前的容量
}Contact, * pContact;//*pContact意思是将结构体指针struct Contact*重命名为pContact

//初始化通讯录--传址
void InitContact(Contact* pc);
//销毁通讯录
void DestroyContact(Contact* pc);
//增加指定联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
/*
传址可以写成void ...Contact(pContact pc);
这里通过pContact定义出来的指针也是结构体指针
*/
//显示联系人信息
void ShowContact(Contact* pc);
//查找联系人 
void SearchContact(const Contact* pc);
//修改联系人
void ModifyContact(Contact* pc);
//排序联系人
void SortContact(Contact* pc);

五、运行结果

C语言实现通讯录--动态版,C语言,c语言,算法,开发语言文章来源地址https://www.toymoban.com/news/detail-617547.html

到了这里,关于C语言实现通讯录--动态版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C语言】实现通讯录(动态+文件)

    在之前三子棋和扫雷的基础上,本篇文章博主将给大家逐步分析实现通讯录,介绍通讯录的每个功能( 动态增长和文件保存 )。 —————————————————————— test.c - 测试通讯录 Contact.c - 函数的实现 Contact.h - 函数和类型的声明 以多文件的形式分模块写的

    2024年02月13日
    浏览(37)
  • C语言动态内存练习:【通讯录(动态内存版本)实现】

    前面我们写了一个静态数组版本的通讯录,再结合刚学习的动态内存管理的知识,我们现在来实现一个动态内存版本的通讯录。 动态内存版本的通讯录,主要还是为了解决静态数组版本的通讯录空间太大导致的内存浪费和空间太小不够存放的问题。 扩容策略: 为通讯录设置

    2023年04月13日
    浏览(55)
  • C语言之通讯录的实现(静态版,动态版,文件版)

    个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客 目录 静态通讯录的实现逻辑  test.c:通讯录的逻辑实现 Contact.h:函数的声明与头文件的包含 Contact.c:函数的实现  通讯录源码:  test.c: Contact.c: Contect.h: 动态版通讯录  test.c: Co

    2024年04月13日
    浏览(27)
  • 【进阶C语言】动态版通讯录的实现(详细讲解+全部码源)

    前言 📕作者简介: 热爱跑步的恒川 ,致力于 C/C++、Java、Python 等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于 C语言进阶 系列,本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等,持续更

    2024年02月01日
    浏览(33)
  • 动态内存管理函数介绍及C语言实现通讯录管理系统2.0版(动态增长版本)

    之前向大家介绍了C语言实现通讯录管理系统1.0版本,但该版本有明显的不足之处,比如:一开始就开辟了1000个date数组,如果联系人很少,那么就会造成严重的内存浪费,或者联系人超过了1000人,那么原数组就放不下了,所以今天我们考虑使用动态内存管理的办法来实现一个

    2023年04月08日
    浏览(37)
  • 【C语言】动态通讯录 -- 详解

    前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客,但是静态版通讯录的空间是无法被改变的,而且空间利用率也不高。为了解决静态通讯录这一缺点,这时就要有一个能够随着存入联系人数量的增加而增大空间的通讯录。接下来我们将

    2024年02月12日
    浏览(31)
  • 【C语言】动态通讯录(超详细)

    通讯录是一个可以很好锻炼我们对结构体的使用,加深对结构体的理解,在为以后学习数据结构打下结实的基础 这里我们想设计一个有 添加联系人,删除联系人,查找联系人,修改联系人,展示联系人,排序 这几种功能的通讯录 注意:我们按照三个区域划分 上图所示进行

    2024年02月08日
    浏览(25)
  • C语言实践——通讯录(2)(动态版)

    首先感谢上一篇博客的大佬们的点赞,非常感谢!!! 目录 前言  一、需要添加的功能 1. 初始化——动态内存开辟 2.添加联系人——通讯录扩容 3.退出通讯录——通讯录销毁 二、具体操作 1.铺垫 2.修改初始化函数 3.修改添加函数  4.退出通讯录,新增销毁函数 上一篇文章我

    2023年04月08日
    浏览(21)
  • 【C语言】——通讯录(静态-动态增长-文件储存)

      目录 前言: 一:整体框架 关于通讯录结构体的创建  二:通讯录的功能实现(静态) 2.1初始化通讯录 2.2增加联系人 2.3打印通讯录 2.4删除联系人  2.5 查找联系人 2.6修改联系人  2.7排序联系人 三:通讯录优化——动态内存  3.1通讯录的创建 3.2初始化通讯录  3.3增加联系

    2024年02月07日
    浏览(30)
  • 【C语言实战项目】通讯录(动态增容版)

    🦄 个人主页 :修修修也 🎏 所属专栏 :数据结构 ⚙️ 操作环境 : Visual Studio 2022 目录 一.动态增容版简介 二.动态增容版逐步实现详解 1.创建通讯录 2. 初始化通讯录 3.增加联系人 4.通讯录增容 5.销毁通讯录 三.动态增容版代码整合 contact.c test.c contact.h 上篇博客我们一起用C语言

    2024年02月11日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包