C语言小程序:通讯录

C/C++
35
0
0
2024-05-03

1.实现功能

本文将采用C语言来实现一个简单的通讯录,要求功能如下

代码语言:javascript

复制

//实现一个通讯录
//1.可以保存100个人的信息
//2.增加人的信息
//3.删除指定联系人的信息
//4.查找
//5.修改
//6.排序
//7.显示所有联系人

下面我们来一步步实现

2.实现细节与具体思路

1.主程序设计

首先,设计一个主程序来对于通讯录进行一个整体的设计,它的功能我们用函数来进行包装,这样可以增加代码的可读性。

代码语言:javascript

复制

#include"contact.h"
void menu()
{
	printf("*************************************\n");
	printf("********1.add*************2.del*******\n");
	printf("*************************************\n");
	printf("*************************************\n");
	printf("******3.search**********4.mobify*********\n");
	printf("*************************************\n");
	printf("******5.show***********6sort******\n");
	printf("*0.exit******************************\n");
}
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);
			ShowContact(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
		

	} while (input);



	return 0;
}

 这里我们对于通讯录的功能用一个枚举常量来包装(枚举常量默认从0开始),虽然也可以直接数字来代替进入switch,但这样可以增加代码的阅读性,方便我们进行接下来的操作。这里我们用一个头文件contact.h来包装我们所需要的头文件以及函数的声明,使代码看上去更加整洁.

头文件contact.h

代码语言:javascript

复制

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30
#define DATA_MAX 100
//类型声明
typedef struct PeopleINfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;

typedef struct Contact
{
	//创建通讯录
	PeoInfo data[DATA_MAX];//可以存放100个人的信息
	//一开始里面没有信息
	int sz;//记录已经存放的信息个数
}Contact;

//初始化
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//展示所有联系人
void ShowContact(const Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
void SearchContact(Contact* pc);
//修改指定联系人的相关信息
void ModifyContact(Contact* pc);
//排序
void SortContact(Contact* pc);

里面是一些函数的声明以及一些变量的初始化.下面会讲到.

功能设计

1.创建一个通讯录并进行初始化

首先我们要明确,一个通讯录里放的应该是什么样的信息,既然是通讯录,肯定得有名字和电话号码,除此之外,也可以有性别,住址或者年龄,为了简单,我们就设计这些元素.我们用一个结构体来存放这些变量,命名为PeopleInfo类型代表联系人的信息.接下来创建通讯录,通讯录里要有联系人的信息,同时还得记录通讯录里人的个数,这里我们也可以用一个结构体Contact来存放它们.

代码语言:javascript

复制

typedef struct Contact
{
	//创建通讯录
	PeoInfo data[DATA_MAX];//可以存放100个人的信息
	//一开始里面没有信息
	int sz;//记录已经存放的信息个数
}Contact;

 下面进行初始化

代码语言:javascript

复制

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

assert函数判断pc指向的地址是否为空,memset函数用来给pc里的data数组进行初始化.

这里要注意的是,创建通讯录变量一定是在主函数里创建的(在初始化函数里创建,函数结束后会销毁) ,同时,给结构体传参时,传值和传址的效果是一样的,只是传址的话不用开辟空间,效率更高.

2.增加功能

代码语言:javascript

复制

void AddContact(Contact* pc)
{
	assert(pc);
	//判断通讯录满没满
	if (pc->sz == DATA_MAX)
	{
		printf("通讯录已满,无法增加\n");
	}
	//增加信息
	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");
}

每设计一个函数功能时,我们都可以用assert判断一下,这样运行会更加安全.

3.删除功能

 这里要注意的是,我们要求的是删除指定联系人而不是全删,所以必须要先找到相应联系人才能进行删除,同时后面的修改功能也得找到相应联系人才能删除,所以我们可以定义一个寻找函数进行调用

代码语言:javascript

复制

FindByName(Contact* pc, char name[])//name字符串来存储我们输入的那个需要的名字
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->data[i].name)==0)
		{
			return i;//找到了
		}
	}
	return -1;//没找到
}

 接下来是删除,删除的算法有说法,我们知道,数组在内存里是连续存储的,我们可以利用它的下标,用它的下一个值赋给它来达到删除的效果,这里要循环赋值,否则会出现两个一样值,从需要删除的值的下标到最后,删完后,别忘了给sz(数据的个数)-1.

代码语言:javascript

复制

void DelContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}
	//找到指定联系人
	printf("请输入你要删除的联系人名字:\n");

	scanf("%s", name);
	int ret=FindByName(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//删除
	int i = 0;
	for (i = ret; i <pc->sz-1 ; i++)
	{
		pc->data[i] = pc->data[i + 1];//结构体对象可以整个赋值,两边结构一样即可
	}
	pc->sz--;
	printf("删除成功\n");
}
4. 查找功能

查找功能的实现,不仅要找到还要输出出来,这里刚刚创建的查找函数可以直接在这里使用

代码语言:javascript

复制

void SearchContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要查找人的名字:");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//找到了,显示出来
	printf("%-20s %-5s %-5s %-12s %-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

为了方便查看,可以输出对应的标识名,注意格式对齐就行.

5.显示所有联系人

代码语言:javascript

复制

void ShowContact(const Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	int i = 0;
	//进行标题修饰
	printf("%-20s %-5s %-5s %-12s %-30s\n", "名字", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s %-5d %-5s %-12s %-30s\n",
			pc->data[i].name, pc->data[i].age, pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);
	}

 这个功能只是简单的循环数组打印出来,没什么好说的,唯一要注意的是如果为空的话就不需要打印了,这里判断一下

6.修改功能

代码语言:javascript

复制

void ModifyContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要修改人的名字:");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//修改
	/*printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].sex);
	printf("请输入号码:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
	printf("修改成功\n");*/
	//修改单独一个
	printf("请输入你要修改的类型:1.名字 2.年龄 3.性别 4.电话号码 5.住址 0.取消修改\n");
	int input = 0;
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		printf("请输入名字:");
		scanf("%s", pc->data[ret].name);
		printf("修改成功\n");
		break;
	case 2:
		printf("请输入年龄:");
		scanf("%d", &(pc->data[ret].age));
		printf("修改成功\n");
		break;
	case 3:
		printf("请输入性别:");
		scanf("%s", pc->data[ret].sex);
		printf("修改成功\n");
		break;
	case 4:
		printf("请输入号码:");
		scanf("%s", pc->data[ret].tele);
		printf("修改成功\n");
		break;
	case 5:
		printf("请输入地址:");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
		break;
	case 0:
		printf("成功取消\n");
		break;
	}
	
}

整体思路就是:先找到相应联系人,找到后要么全部修改,要么输入相应的数字修改相应的信息

7.排序

这里先介绍一下qsort函数的用法

 它的功能是对所传入的元素进行排序,要传入的参数是需要比较元素的起始地址,比较的个数,所比较元素的单个大小,以及一个比较函数.

比较函数这里有说法,我们来看看

大概意思是,如果p1的值大于p2就返回大于0的值,反之返回小于0的值,相等则返回0,通常的通讯录是按照名字排序(字典序),所以这里要比较字符串的大小,不能直接相减,得用strcmp函数,这里用它的好处就是,它的返回值和这个比较函数的规则是一样的,

比较函数 

代码语言:javascript

复制

int cmp_by_name(const void* p1, const void* p2)
{
	return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
}
void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
	printf("排序成功!\n");
}

 cmp接收的参数必须是void*类型,所以进入函数要记住强转一下.

3.完整代码

代码语言:javascript

复制

#include"contact.h"

void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}



void AddContact(Contact* pc)
{
	assert(pc);
	//判断通讯录满没满
	if (pc->sz == DATA_MAX)
	{
		printf("通讯录已满,无法增加\n");
	}
	//增加信息
	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 ShowContact(const Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	int i = 0;
	//进行标题修饰
	printf("%-20s %-5s %-5s %-12s %-30s\n", "名字", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s %-5d %-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(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(name, pc->data[i].name)==0)
		{
			return i;//找到了
		}
	}
	return -1;//没找到
}
void DelContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}
	//找到指定联系人
	printf("请输入你要删除的联系人名字:\n");

	scanf("%s", name);
	int ret=FindByName(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//删除
	int i = 0;
	for (i = ret; i <pc->sz-1 ; i++)
	{
		pc->data[i] = pc->data[i + 1];//结构体对象可以整个赋值,两边结构一样即可
	}
	pc->sz--;
	printf("删除成功\n");
}

void SearchContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要查找人的名字:");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//找到了,显示出来
	printf("%-20s %-5s %-5s %-12s %-30s\n", "名字", "年龄", "性别", "电话", "地址");
	printf("%-20s %-5d %-5s %-12s %-30s\n",
		pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}

void ModifyContact(Contact* pc)
{
	char name[NAME_MAX];
	assert(pc);
	printf("请输入要修改人的名字:");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (ret == -1)
	{
		printf("该联系人不存在\n");
		return;
	}
	//修改
	/*printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].sex);
	printf("请输入号码:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
	printf("修改成功\n");*/
	//修改单独一个
	printf("请输入你要修改的类型:1.名字 2.年龄 3.性别 4.电话号码 5.住址 0.取消修改\n");
	int input = 0;
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		printf("请输入名字:");
		scanf("%s", pc->data[ret].name);
		printf("修改成功\n");
		break;
	case 2:
		printf("请输入年龄:");
		scanf("%d", &(pc->data[ret].age));
		printf("修改成功\n");
		break;
	case 3:
		printf("请输入性别:");
		scanf("%s", pc->data[ret].sex);
		printf("修改成功\n");
		break;
	case 4:
		printf("请输入号码:");
		scanf("%s", pc->data[ret].tele);
		printf("修改成功\n");
		break;
	case 5:
		printf("请输入地址:");
		scanf("%s", pc->data[ret].addr);
		printf("修改成功\n");
		break;
	case 0:
		printf("成功取消\n");
		break;
	}
	
}

int cmp_by_name(const void* p1, const void* p2)
{
	return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
}
void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
	printf("排序成功!\n");
}