C语言实现通讯录静态版本

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

通讯录中首先要有人的信息然后是存放多少个人的信息

再丰富一下通讯录的功能例如增删查改、显示、排序。

我们分三个文件来实现。

1、实现简易的菜单通讯录的整体逻辑 

#include"contact.h"

void menu()
{
	printf("***********通讯录contact**************\n");
	printf("*****1、add      2、del   3、search***\n");
	printf("*****4、update   5、show  6、sort1 ** \n");
	printf("*****7、sort2    0、exit**************\n");
	printf("**************************************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择要使用的功能\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 0:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误请重新选择\n");
			break;
		}
	} while (input);
}

case的不同情况对应菜单中的不同功能。考虑到枚举常量的知识点可以将上面的功能对应枚举常量的数字用来代替单一的case+数字从而更加直观。

enum
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	UPDATE,
	SHOW,
	SORT1,
	SORT2,
};

优化后的菜单代码

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择要使用的功能\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case DEL:
			break;
		case SEARCH:
			break;
		case UPDATE:
			break;
		case SHOW:
			break;
		case SORT1:
			break;
		case SORT2:
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误请重新选择\n");
			break;
		}
	} while (input);
}

2、实现每个人信息包含的内容

一个人的信息包含姓名、年龄、电话等不同类型的数据因此对于每个人的信息我们可以选择使用结构体类型的数据。

struct peopleinfo
{
	char name[20];
	int age;
	char sex[5];
	char tel[12];
	char dres[10];
};

这里我们暂时规定  姓名  年龄   性别   电话   地址  五个元素。除年龄外均为字符数组。

为了我们代码灵活性的考虑我们在实现某个功能时尽量不要把数字写死逻辑功能除外相反我们可以采用#define定义的标识符常量来替换它。

#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TEL 12
#define MAX_DRES 10

替换后的人员信息

struct peopleinfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tel[MAX_TEL];
	char dres[MAX_DRES];
};

3、通讯录N个人的包含

定义完每个人的个人信息我们就需要将N个人的信息统一起来。

这里我们可以用创建一个结构体数组其中包含N个元素。

在这之前我们可以用typedef使结构体的名字简化一些。

typedef struct peopleinfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tel[MAX_TEL];
	char dres[MAX_DRES];
}peopleinfo;
#define N 1000


peopleinfo date[N];

这里我们定义数组有1000个元素即可以存储1000个人的信息。

为了方便实现后续增删查改时确定我们操作数组的范围这里我们可以定义一个变量sz用来标记接下来要操作的元素的下标。

然后我们可以将date数组和sz再封装为一个结构体类型contact。并用typedef简化 

typedef struct contact
{
	peopleinfo date[1000];
	int sz;
}contact;

4、通讯录的初始化

得到contact这个结构体后我们可以对它进行初始化。

sz可初始化为0date数组可按需初始化这里我们统一初始化为0但为了代码灵活性考虑我们将其封装为一个函数。

contact con;
contact_init(&con);
void contact_init(contact* pc)
{
	pc->sz = 0;
	//初始化可以才用循环遍历这里我使用memset直接设置
	//   设置的起始地址  要设置成的内容   设置的字节数
	memset(pc->date, 0, sizeof(pc->date));
	//这里用结构体指针直接指向其中的数组即数组名表示找到这个数组
	//  sizeof内部单独放数组名求的是整个数组的大小
}

这里因为是结构体传参为了保证性能我们才用传址调用用一个结构体指针pc接收然后再函数内部用pc操作结构体。

5、增加人员信息功能

//增加人员信息
void contact_add(contact* pc)
{
	//增加前确保通讯没满
	if (pc->sz == N)
	{
		printf("通讯录已满无法添加\n");
		return;  //直接返回不进行后续功能
	}
	//通讯录没满添加信息
	printf("请输入姓名\n");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄\n");
	scanf("%d", &pc->date[pc->sz].age);
	//由于其它的都是字符数组数组名就是地址不用再加&int的年龄需要&
	printf("请输入性别\n");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入电话\n");
	scanf("%s", pc->date[pc->sz].tel);
	printf("请输入地址\n");
	scanf("%s", pc->date[pc->sz].dres);
	//输入后再到下一个元素
	pc->sz++;
}

 6、显示通讯录

//显示通讯录已有信息
void contact_show(const contact* pc)
{
	//先打印一个目录
	printf("%-20s\t%-10s\t%-10s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
	//各个信息分别打印
	int i = 0;
	for (i=0;i<pc->sz;i++)
	{
		printf("%-20s\t%-10d\t%-10s\t%-12s\t%-10s\n",   pc->date[i].name,
														pc->date[i].age,
														pc->date[i].sex,
														pc->date[i].tel,
														pc->date[i].dres);
	}
}

用i遍历数组挨个结构体挨个成员打印。 

输入两个人的信息后显示。

 7、查找某个人的信息是否存在

在删除查找更新等功能中都需要先找到某个人的信息是否存在因此我们封装一个查找函数用来反复使用。

//按名字查找某个人是否存在
int seek_by_name(contact* pc,char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->date[i].name, name) == 0)
		{
			int pos = i;
			return i;//找到后返回数组下标
		}
	}
	//遍历完扔没有返回即没有找到
	return -1;
}

8、删除指定人的信息

删除时有多种方式

1、找到后直接从后往前覆盖。然后sz--使访问权限-1完成删除。

2、将最后一个元素直接覆盖到要删除的位置但是会改变元素的顺序。

这里我们选择往前覆盖的方法。

//删除指定人员信息
void contact_del(contact* pc)
{
	assert(pc);
	//先判断通讯录内是否还有人员信息
	if (pc->sz == 0)
	{
		printf("通讯录内已无信息无法删除\n");
		return;  //直接返回不进行后续
	}
	//可以删除时
	//先查找要删除的人例如按照名字
	char name[20];
	printf("请输入要删除的人的名字\n");
	scanf("%s", name);
	//查找要删除的人的名字
	int del=seek_by_name(pc,name);
	if (del == -1)
	{
		printf("没有找到要删除人的信息\n");
		return;//没找到直接返回不进行后续操作
	}
	//找到要删除的元素进行删除操作
	int i = 0;
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->date[i] = pc->date[i + 1];//结构体的两个元素直接覆盖即可
	}
	//完成删除后sz--缩小访问权限
	pc->sz--;
}

 9、查找指定人的信息

//查找指定人员的信息
void contact_search(const contact* pc)
{
	printf("请输入要查找的人的名字\n");
	char name[20];
	scanf("%s", name);
	int pos=seek_by_name(pc, name);
	if (pos == -1)
	{
		printf("查无此人\n");
		return;//找不到直接返回
	}
	//找到后打印出来
	printf("查找成功信息为\n");
	int i = 0;
	printf("%-20s\t%-10s\t%-10s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = pos; i < pc->sz; i++)
	{
		printf("%-20s\t%-10d\t%-10s\t%-12s\t%-10s\n", 
			pc->date[pos].name,
			pc->date[pos].age,
			pc->date[pos].sex,
			pc->date[pos].tel,
			pc->date[pos].dres);
	}
	
}

 10、更改/更新指定人的信息

//更改指定人员信息
void contact_update(contact* pc)
{
	printf("请输入要更改的人的姓名\n");
	char name[20];
	scanf("%s", name);
	int pos=seek_by_name(pc, name);
	if (pos == -1)
	{
		printf("查无此人无法更改\n");
		return;
	}
	printf("开始更改\n");
	printf("请输入姓名\n");
	scanf("%s", pc->date[pos].name);
	printf("请输入年龄\n");
	scanf("%d", &pc->date[pos].age);
	printf("请输入性别\n");
	scanf("%s", pc->date[pos].sex);
	printf("请输入电话\n");
	scanf("%s", pc->date[pos].tel);
	printf("请输入地址\n");
	scanf("%s", pc->date[pos].dres);
	printf("信息更新成功\n");
}

 11、按照年龄排序升序

12、按照名字排序

排序函数可以使用我们之前讲解的bubble_qsort函数来实现

下面附上源码

头文件contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TEL 12
#define MAX_DRES 10
#define N 1000
enum
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	UPDATE,
	SHOW,
	SORT1,
	SORT2,
};
typedef struct peopleinfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tel[MAX_TEL];
	char dres[MAX_DRES];
}peopleinfo;

typedef struct contact
{
	peopleinfo date[1000];
	int sz;
}contact;

//初始化通讯录
void contact_init(contact* pc);
//增加人员信息
void contact_add(contact* pc);
//显示通讯录已有信息
void contact_show(const contact* pc);
//删除指定人员信息
void contact_del(contact* pc);
//查找指定人员信息
void contact_search(const contact* pc);
//更改指定人员信息
void contact_update(contact* pc);
//按年龄升序
void contact_sort_byage(contact* pc);
//按名字升序
void contact_sort_byname(contact* pc);

test.c

#include"contact.h"

void menu()
{
	printf("***********通讯录contact**************\n");
	printf("*****1、add      2、del   3、search***\n");
	printf("*****4、update   5、show  6、sort1 ** \n");
	printf("*****7、sort2    0、exit**************\n");
	printf("**************************************\n");
}
int main()
{
	contact con;
	contact_init(&con);
	int input = 0;
	do
	{
		menu();
		printf("请选择要使用的功能\n");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			contact_add(&con);
			break;
		case DEL:
			contact_del(&con);
			break;
		case SEARCH:
			contact_search(&con);
			break;
		case UPDATE:
			contact_update(&con);
			break;
		case SHOW:
			contact_show(&con);
			break;
		case SORT1:
			contact_sort_byage(&con);
			break;
		case SORT2:
			contact_sort_byname(&con);
			break;
		case EXIT:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误请重新选择\n");
			break;
		}
	} while (input);
}

contact.c

#include"contact.h"
//通讯录初始化
void contact_init(contact* pc)
{
	assert(pc);
	pc->sz = 0;
	//初始化可以才用循环便利这里我使用memset直接设置
	//   设置的起始地址  要设置成的内容   设置的字节数
	memset(pc->date, 0, sizeof(pc->date));
	//这里用结构体指针直接指向其中的数组即数组名表示找到这个数组
	//  sizeof内部单独放数组名求的是整个数组的大小
}

//增加人员信息
void contact_add(contact* pc)
{
	assert(pc);
	//增加前确保通讯没满
	if (pc->sz == N)
	{
		printf("通讯录已满无法添加\n");
		return;  //直接返回不进行后续功能
	}
	//通讯录没满添加信息
	printf("请输入姓名\n");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入年龄\n");
	scanf("%d", &pc->date[pc->sz].age);
	//由于其它的都是字符数组数组名就是地址不用再加&int的年龄需要&
	printf("请输入性别\n");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入电话\n");
	scanf("%s", pc->date[pc->sz].tel);
	printf("请输入地址\n");
	scanf("%s", pc->date[pc->sz].dres);
	//输入后再到下一个元素
	pc->sz++;
}


//显示通讯录已有信息
void contact_show(const contact* pc)
{
	assert(pc);
	//先打印一个目录
	printf("%-20s\t%-10s\t%-10s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
	//各个信息分别打印
	int i = 0;
	for (i=0;i<pc->sz;i++)
	{
		printf("%-20s\t%-10d\t%-10s\t%-12s\t%-10s\n",   pc->date[i].name,
														pc->date[i].age,
														pc->date[i].sex,
														pc->date[i].tel,
														pc->date[i].dres);
	}
}

//按名字查找某个人是否存在
int seek_by_name(const contact* pc,char name[])
{
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->date[i].name, name) == 0)
		{
			int pos = i;
			return i;//找到后返回数组下标
		}
	}
	//遍历完扔没有返回即没有找到
	return -1;
}


//删除指定人员信息
void contact_del(contact* pc)
{
	assert(pc);
	//先判断通讯录内是否还有人员信息
	if (pc->sz == 0)
	{
		printf("通讯录内已无信息无法删除\n");
		return;  //直接返回不进行后续
	}
	//可以删除时
	//先查找要删除的人例如按照名字
	char name[20];
	printf("请输入要删除的人的名字\n");
	scanf("%s", name);
	//查找要删除的人的名字
	int del=seek_by_name(pc,name);
	if (del == -1)
	{
		printf("没有找到要删除人的信息\n");
		return;//没找到直接返回不进行后续操作
	}
	//找到要删除的元素进行删除操作
	int i = 0;
	for (i = del; i < pc->sz - 1; i++)
	{
		pc->date[i] = pc->date[i + 1];//结构体的两个元素直接覆盖即可
	}
	//完成删除后sz--缩小访问权限
	pc->sz--;
}

//查找指定人员的信息
void contact_search(const contact* pc)
{
	printf("请输入要查找的人的名字\n");
	char name[20];
	scanf("%s", name);
	int pos=seek_by_name(pc, name);
	if (pos == -1)
	{
		printf("查无此人\n");
		return;//找不到直接返回
	}
	//找到后打印出来
	printf("查找成功信息为\n");
	int i = 0;
	printf("%-20s\t%-10s\t%-10s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = pos; i < pc->sz; i++)
	{
		printf("%-20s\t%-10d\t%-10s\t%-12s\t%-10s\n", 
			pc->date[pos].name,
			pc->date[pos].age,
			pc->date[pos].sex,
			pc->date[pos].tel,
			pc->date[pos].dres);
	}
	
}

//更改指定人员信息
void contact_update(contact* pc)
{
	printf("请输入要更改的人的姓名\n");
	char name[20];
	scanf("%s", name);
	int pos=seek_by_name(pc, name);
	if (pos == -1)
	{
		printf("查无此人无法更改\n");
		return;
	}
	printf("开始更改\n");
	printf("请输入姓名\n");
	scanf("%s", pc->date[pos].name);
	printf("请输入年龄\n");
	scanf("%d", &pc->date[pos].age);
	printf("请输入性别\n");
	scanf("%s", pc->date[pos].sex);
	printf("请输入电话\n");
	scanf("%s", pc->date[pos].tel);
	printf("请输入地址\n");
	scanf("%s", pc->date[pos].dres);
	printf("信息更新成功\n");
}
//按照   结构体   年龄大小判断是否交换的函数
int exchange_by_age(const void* e1, const void* e2)
{
	return ((peopleinfo*)e1)->age - ((peopleinfo*)e2)->age;
}
//按照  结构体    字符串大小比较判断是否交换的函数
int exchange_by_name(const void* e1, const void* e2)
{
	return strcmp(((peopleinfo*)e1)->name, ((peopleinfo*)e2)->name);
}


//逐字节交换函数
void swap_by_byte(char* low, char* high, size_t width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *low;
		*low = *high;
		*high = tmp;
		low++;
		high++;
	}
}
//排序函数
void bubble_sort(void* base, size_t num, size_t width, int (*pf)(const void*, const void*))
{
	int i = 0;
	//冒泡排序的躺数
	for (i = 0; i < num - 1; i++)
	{
		//每一趟冒泡排序
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//判断是否需要交换
			int ret = pf((char*)base + j * width, (char*)base + (j + 1) * width);
			if (ret > 0)
			{
				//交换相邻的两个元素
				swap_by_byte((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}


}

//按年龄升序排列
void contact_sort_byage(contact* pc)
{
	bubble_sort(pc->date, pc->sz, sizeof(peopleinfo), exchange_by_age);
	printf("按照年龄排序成功\n");
}
//按名字升序排列
void contact_sort_byname(contact* pc)
{
	bubble_sort(pc->date, pc->sz, sizeof(peopleinfo), exchange_by_name);
	printf("按名字排序成功\n");
}

大家可以动手敲一敲遇到困难就去解决一下。

目录

1、实现简易的菜单通讯录的整体逻辑 

2、实现每个人信息包含的内容

3、通讯录N个人的包含

4、通讯录的初始化

5、增加人员信息功能

​编辑

 6、显示通讯录

 7、查找某个人的信息是否存在

8、删除指定人的信息

 9、查找指定人的信息

 10、更改/更新指定人的信息

 11、按照年龄排序升序

12、按照名字排序


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6