C语言进阶实战之通讯录项目

前言

大家好呀,我是Humble,今天我们对顺序表进行一个应用,即用顺序表来做一个通讯录的小项目

6a57f055456348d19aabd06de3042b47.jpg

好了,废话不多说,开始今天的通讯录项目吧~

首先我们先来回忆一下通讯录都有哪些基本功能~

1.增加联系人

2.删除指定联系人

3.修改制定联系人

4.查找指定联系人

5.查看通讯录

实现思路

好,接下来我们就来想想如何用动态顺序表实现通讯录


我们之前写的动态顺序表是这样的:
 

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;
	int capacity;    
	int size;   
     
}SL;

这里的arr只是一个单一类型的数组,

而通讯录中,我们需要联系人的 姓名,性别,年龄,电话,住址这些信息都存进去

所以我们将这里的arr换成结构体

这个结构体可以这么定义:

#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 12
#define ADDR_MAX 100


typedef struct PersonInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}Info;

然后我们就可以将这个Info作为原来的动态顺序表arr的新的类型了

我们可以这样写:



typedef Info SLDataType;

typedef struct Contact
{
	SLDataType* arr;
	int capacity;    
	int size;        

}contact; 

接下来我们只需要写出一个个函数来实现通讯录的功能就行了,我们在上篇博客在顺序表中其实已经基本实现了通讯录的功能,所以我们在那个SeqList的顺序表的工程上改就行了~
 

除了已有的SeqList.h 和 SeqList.c文件,我们再添加一个Contact.h 和 Contact.c 的文件

下面将所有的代码进行汇总:

SeqList.h

#pragma once
#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include<assert.h>
#include "Contact.h"

//动态顺序表
typedef Info SLDataType;

typedef struct SeqList
{
	SLDataType* arr; //存储数据的底层结构
	int capacity;    //记录顺序表的空间大小
	int size;        //记录顺序表当前有效的数据个数

}SL; //将struct SeqList这个结构体类型重命名为SL,之后使用起来更加方便~


void SLInit(SL* ps);//初始化
void SLDestroy(SL* ps);//销毁
void SLPrint(SL* ps); //保持接口一致性

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);

//顺序表的头部/尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置之前插入数据
//删除指定位置数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

SeqList.c

#include"SeqList.h"


//初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;

		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x)
{
	//断言
	assert(ps);


	//空间不够,扩容
	SLCheckCapacity(ps);

	//空间足够,直接插入
	ps->arr[ps->size++] = x;
	//ps->size++;
}


void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	//判断是否扩容
	SLCheckCapacity(ps);

	//旧数据往后挪动一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	ps->size++;
}

//顺序表的头部/尾部删除
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//顺序表不为空

	ps->size--;
}


void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//不为空执行挪动操作
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);

	//pos及之后的数据往后挪动一位,pos空出来
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[pos+1] = ps->arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;
}

//删除指定位置数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}





void SLDestroy(SL* ps)
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
 

Contact.h

typedef struct SeqList contact;


//通讯录数据类型  
typedef struct PersonInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}Info;


//初始化通讯录
void InitContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//展⽰通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//销毁通讯录数据
void DestroyContact(contact* con);

Contact.c

#include "SeqList.h"


//初始化
void InitContact(contact* con)
{
	SLInit(con);

}

//添加联系人
void AddContact(contact* con)
{
	Info info;

	printf("请输入姓名:\n");
	scanf("%s", info.name);

	printf("请输入性别:\n");
	scanf("%s", info.sex);

	printf("请输入年龄:\n");
	scanf("%d", &info.age);
	 
	printf("请输入联系电话:\n");
	scanf("%s", info.tel);

	printf("请输入地址:\n");
	scanf("%s", info.addr);

	SLPushBack(con, info);//保存数据到通讯录,尾插

}
  

//寻找通讯录中用户是否存在
int FindByName(contact* con, char name[]) 
{
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0 )
		{
			return i;
		}
	}
	return -1;
}

//删除联系人
void DelContact(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要删除的用户姓名:\n");
	scanf("%s", name);
	int pos = FindByName(con, name);

	if (pos < 0)
	{
		printf("要删除的用户不存在,删除失败!\n");
		return;
	}
	//执行删除操作 
	SLErase(con, pos);
	printf("联系人删除成功!\n");
}

//查看通讯录
void ShowContact(contact* con)
{
	    printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");//打印表头 
		for (int i = 0; i < con->size; i++)
		{
			printf("%s %s %d %s %s\n",
				con->arr[i].name,
				con->arr[i].sex,
				con->arr[i].age,
				con->arr[i].tel,
				con->arr[i].addr);
		}
}

//查找联系人
void FindContact(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的用户姓名:\n");
	scanf("%s", name);
	int pos = FindByName(con, name);

	if (pos < 0) //找不到
	{
		printf("要查找的用户不存在,查找失败!\n");
		return;
	}

	printf("查找成功!\n");//找到了
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");//打印表头 
	printf("%s %s %d %s %s\n",
		con->arr[pos].name,
		con->arr[pos].sex,
		con->arr[pos].age,
		con->arr[pos].tel,
		con->arr[pos].addr);
}

//修改联系人
void ModifyContact(contact* con) 
{
	char name[NAME_MAX];
	printf("请输入要修改的用户名称:\n");
	scanf("%s", name);
	int pos = FindByName(con, name);

	if (pos < 0) 
	{
		printf("要查找的用户不存在,修改失败!\n");
		return;
	}

	//找到了,执行修改操作

	printf("请输入要修改的姓名:\n");
	scanf("%s", &con->arr[pos].name);

	printf("请输入要修改的性别:\n");
	scanf("%s", &con->arr[pos].sex);

	printf("请输入要修改的年龄:\n");
	scanf("%d", &con->arr[pos].age);

	printf("请输入要修改的联系电话:\n");
	scanf("%s", &con->arr[pos].tel);

	printf("请输入要修改的地址:\n");
	scanf("%s", &con->arr[pos].addr);

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


void DestroyContact(contact* con) 
{
	SLDestroy(con);
}

测试

好,到此我们通讯录的所有功能都实现了,我们在测试文件test.c中玩一下测试一下吧

test.c

#include "SeqList.h"

void menu() //与之前的扫雷一样,我们在这做一个菜单界面,这样也能使这个项目更像回事
{
	
		printf("**************************************\n");
		printf("*****1、添加联系人 2、删除联系人******\n");
		printf("*****3、修改联系人 4、查找联系人******\n");
		printf("*****5、查看通讯录 0、退出 ***********\n");
		printf("**************************************\n");
		printf("请选择您的操作:\n");
}

int main()
{
	contact con;
	InitContact(&con);

	int op = -1;
	do {
		menu();
		scanf("%d", &op);
		switch(op)
		{
		case 1:
			//添加联系人
			AddContact(&con); 
			break;
		case 2:
			//删除联系人
			DelContact(&con);
			break;
		case 3:
          //修改联系人
			ModifyContact(&con);
			break;
		case 4:
			//查找联系人
			FindContact(&con);
			break;
		case 5:
			//查看通讯录
			ShowContact(&con);
			break;
		case 0:
			//退出
			printf("通讯录退出...\n");
			break;
		default:
			printf("输入有误,请重新输入\n");
			break;
		}
	} while (op != 0);

	//销毁通讯录
	DestroyContact(&con);

	return 0;
}

运行结果如下:(下面是博主随便测试的,大家也可以自己去按照自己的想法测试)

测完后,每个函数的功能都能实现,也说明我们通讯录的实现成功了(鼓掌鼓掌!!!)

拓展

在实现了这个简单的通讯录之后,我们也发现它还可以做得更好,这里Humble给大家提供一个改进的思路:

如何保证程序结束后,历史通讯录信息不会丢失

即我们如何将历史的通讯录信息在程序结束后保存及在下次想看的时候重新载入   ?

不过这个功能的实现就靠聪明的大家了,毫无疑问,这是要用到我们之前学的关于文件操作的知识的~

结语

好了,今天的这个通讯录小项目的分享就到这里了

在学习编程的道路上Humble与各位同行,加油吧各位!

最后希望大家点个免费的赞或者关注吧(感谢感谢),也欢迎大家订阅我的专栏

让我们在接下来的时间里一起成长,一起进步吧!

1d8bd2383fe54a7aa576bdd8d41dc462.png

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
嵌入式C语言之道,可以涉及以下几个方面: 1. 熟悉硬件平台:嵌入式开发需要对目标硬件平台有深入了解,包括处理器架构、寄存器、外设等。学习并理解硬件的特性和工作原理,能够更好地行底层编程和优化。 2. 掌握低级编程技巧:嵌入式开发常常需要行底层编程,因此需要熟悉C语言的底层特性,如指针操作、位操作、内存管理等。掌握这些技巧可以提高代码的效率和可靠性。 3. 理解中断和定时器:在嵌入式系统中,中断和定时器是常用的机制,用于实时响应和时间触发的任务。学习如何使用中断和定时器,并了解其原理和应用场景,可以实现更加高效和可靠的嵌入式系统。 4. 学习RTOS:实际的嵌入式系统往往需要处理多个任务,并具有实时性要求。学习实时操作系统(RTOS)的使用和原理,可以帮助开发者更好地管理任务、调度和资源。 5. 行性能优化:嵌入式系统通常资源有限,需要行性能优化以提高系统的效率和响应速度。了解编译器优化、代码压缩、数据结构选择等技术,可以帮助优化嵌入式系统的性能。 总之,嵌入式C语言之道包括对硬件平台的深入了解、掌握底层编程技巧、理解中断和定时器、学习RTOS以及行性能优化。通过不断学习和实践,可以提升嵌入式开发的能力和水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃肉的Humble

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值