C语言实现通信录(C语言大作业这不就手到擒来了嘛~)

 呀呀呀,今天的博客来了哦!十分的干货,有关于一个简单的小通讯录的实现代码以及解析,欢迎大家来帮忙掌掌眼,有错误也还请大家斧正哦,十分的感谢!

目录

一,项目结构分析

二,项目文件划分

2.1,头文件(contact.h)

2.2,源文件

三,前期准备

3.1,创建通信录类

3.2,创建联系人类

四,基本功能实现

4.1,初始化通信录

4.2,添加功能

4.3,删除功能

4.4,查找功能

4.5,修改功能

4.6,排序功能

4.7,打印输出功能

五,主函数框架

六,项目源码

6.1,contact.h文件

6.2,contact.c文件

6.3,test.c文件


一,项目结构分析

二,项目文件划分

2.1,头文件(contact.h)

#pragma once
#include<string.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>
//头文件包含函数的声明 与 类型的声明

//宏定义将后面的一些具体数字进行替换,是代码后期便于更改维护
#define MAX 1000
#define name_max 20
#define sex_max 3
#define phone_max 12
#define address_max 30

//联系人具体信息结构体的声明
typedef struct perinfo {
	char name[name_max];
	int age;
	char sex[sex_max];
	char phone[phone_max];
	char address[address_max];
}perinfo;

//通信录结构体的声明
typedef struct contact {
	perinfo date[MAX];//定义了一个结构体数组,数组的每一个元素都是一个结构体类型,包含很多的成员属性,也就是具体的一个联系人的所有信息
	int sz;//用来记录通信录里面的人数
}contact;

//枚举类型的声明,因为case后面的数字不能很好的直接与功能挂上钩,所以对于我们的选择可以定义一个枚举类型,然后将case后的数字换成具体的功能的名字
//增加代码的可读性
enum option {
	EXIT,
	ADD,
	DEL,
	SER,
	MOD,
	SORT,
	PRINT,
};


//函数声明
//初始化函数
void init(contact* pc);
//添加函数
void ADDinfo(contact* pc);
//查找函数(此查找函数只是单纯找到人返回下标)
int ser_byname(const contact* pc);//只是查找,不会对指针指向的内容进行修改,用const修饰一下
//删除函数
void DELinfo(contact* pc);
//打印函数
void PRINTinfo(const contact* pc);
//查找函数
void SERinfo(const contact* pc);
//修改函数
void MODinfo(contact* pc);
//排序函数
void SORTinfo(contact* pc);
//比较函数
int comparestu(const void* e1, const void* e2);

头文件的主要作用就是对于整个项目可能用到的头文件进行包含,其次就是各种类型的声明以及函数的声明。

2.2,源文件

源文件包括contact.c以及test.c,contact.c文件主要是对于一些功能函数的实现,test.c文件就是主函数所在的文件,是整个项目的执行框架。

三,前期准备

3.1,创建通信录类

typedef struct contact {
	perinfo date[MAX];//定义了一个结构体数组,数组的每一个元素都是一个结构体类型,包含很多的成员属性,也就是具体的一个联系人的所有信息
	int sz;//用来记录通信录里面的人数
}contac

通信录类的成员就两个,一个是一个联系人类的结构体,另一个是一个记录通信录人数的变量。这里运用了结构体的嵌套,因为对于通信录而言,其自身包含有很多的属性,而联系人又有许多的属性,所以我们不能将他们塞进同一个结构体中,只能是分别建立结构体,让后嵌套让二者关联起来,这样结构也会更加清晰。

3.2,创建联系人类


//联系人具体信息结构体的声明
typedef struct perinfo {
	char name[name_max];
	int age;
	char sex[sex_max];
	char phone[phone_max];
	char address[address_max];
}perinfo;

联系人的结构体类的功能就十分的明确,包含着一个联系人所有的属性:姓名,年龄,性别,电话,地址。

四,基本功能实现

4.1,初始化通信录

//初始化函数实现
void init(contact *pc) {
	assert(pc);
	memset(pc->date, 0, sizeof(pc->date));//date是结构体数组的数组名,求出整个数组的大小,按字节初始化为0 
	pc->sz = 0;
}

对于一个通信录来说,最开始是没有初值的,所以需要我们来进行初始化,这里的初始化我们运用的是内存操作函数memset(),这样可以快速的进行初始化。可能有人会想怎么不直接大括号给它赋值为0,更加简单,首先这里我们将其包装成一个函数是为了长远的考虑,假如未来我们不能简单的给他初始化为0呢,那还是需要用函数的。

4.2,添加功能

//添加函数
void ADDinfo(contact* pc) {
	assert(pc);
	if (pc->sz == MAX) {
		printf("通信录已满,无法添加!\n");
		return;
	}
	printf("请输入联系人姓名>>\n");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入联系人年龄>>\n");
	scanf("%d", &(pc->date[pc->sz].age));//这里要注意,因为其他属性都是用数组存储的,所以数组名就是地址,而age是需要取地址才行的
	printf("请输入联系人性别>>\n");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入联系人电话>>\n");
	scanf("%s", pc->date[pc->sz].phone);
	printf("请输入联系人地址>>\n");
	scanf("%s", pc->date[pc->sz].address);

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

添加函数的本质逻辑很简单,就是scanf函数输入然后赋值,然后每添加一个联系人的完整信息后,那个记录人数的变量就自增。

4.3,删除功能

//删除函数
void DELinfo(contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		printf("通信录已经为空,无法删除!");
		return;
	}
	//1,先找到
	char delname[name_max] = { 0 };
	printf("请输入你要删除的联系人的名字>>\n");
	scanf("%s", &delname);
	int ret = ser_byname(pc,delname);
	//2,删除
	for (int j = ret;j < (pc->sz - 1);j++) {
		pc->date[j] = pc->date[j + 1];
	}
	pc->sz--;
	printf("删除成功!\n");
}

删除的基本逻辑就是先找到人,然后进行覆盖删除。这里因为后面的修改,查找都是需要找到特定的联系人的,所以我们会先定义一个专门用来查找的函数,也就是ser_byname函数。

//查找函数
int ser_byname(const contact* pc,char* sername) {
	assert(pc);
	for (int i = 0;i < pc->sz;i++) {
		if (0 == strcmp(pc->date[i].name, sername)) {
			return i;//找到了就返回下标
		}
	}
	return -1;//最终找不到就返回-1
}

查找函数会去遍历那个储存联系人的结构体数组,一个个的与你想查找的联系人名进行对比,找到了就返回下标,找不到就返回-1。

4.4,查找功能

//查找函数
void SERinfo(const contact* pc) {
	assert(pc);
	//1,先找到
	char sername[name_max] = { 0 };
	printf("请输入你要查找的联系人的名字>>\n");
	scanf("%s", &sername);
	int ret = ser_byname(pc, sername);//利用之前的查找函数拿到下标
	//2,输出
	if (-1 == ret) {
		printf("对不起,查无此人!\n");
		return;
	}
	else {
		printf("已找到如下相关信息>>\n");
		printf("%-10s %-10s %-10s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s %-10d %-10s %-12s %-20s\n", pc->date[ret].name, pc->date[ret].age, pc->date[ret].sex, pc->date[ret].phone, pc->date[ret].address);
	}
	return;
}

查找功能函数的逻辑就是运用上面所说的查找函数,找到特定的联系人的下标后,对指定的联系人信息进行打印就可。

4.5,修改功能

void MODinfo(contact* pc) {
	assert(pc);
	//1,先找到
	char modname[name_max] = { 0 };
	printf("请输入你要修改的联系人的人的名字>>\n");
	scanf("%s", &modname);
	int ret = ser_byname(pc, modname);//利用之前的查找函数拿到下标
	//2,修改
	if (-1 == ret) {
		printf("对不起,无法修改,此通信录下无此人!\n");
		return;
	}
	else {
		printf("请输入修改后的联系人姓名>>\n");
		scanf("%s", pc->date[ret].name);
		printf("请输入修改后的联系人年龄>>\n");
		scanf("%d", &(pc->date[ret].age));
		printf("请输入修改后的联系人性别>>\n");
		scanf("%s", pc->date[ret].sex);
		printf("请输入修改后的联系人电话>>\n");
		scanf("%s", pc->date[ret].phone);
		printf("请输入修改后的联系人地址>>\n");
		scanf("%s", pc->date[ret].address);
		printf("修改成功!\n");
	}
	return;
}

修改函数的基本逻辑就是先得找到特定的人,运用查找函数拿到下标后,在对信息进行修改就可。

4.6,排序功能

//自定义比较函数
int comparestu(const void* e1,const void* e2) {
	return ((struct perinfo*)e1)->age - ((struct perinfo*)e2)->age;//以年龄作为比较对象
}

//排序函数
void SORTinfo(contact* pc) {
	//这里的排序我们可以用qsort来实现
	qsort(pc->date, pc->sz, sizeof(pc->date[0]), comparestu);
	printf("排序完毕,可使用打印查看!\n");
}

对于排序,这里是以年龄为依据进行排序的,主要实现方法是运用了qsort函数进行排序,qsort函数需要有一个自定义的比较函数,所以同时也定义了一个比较函数,当比较的而言前者较大时,返回值大于0,qsort函数就会对比较的二者进行交换。当然,qsort函数的底层原理实现博主之前的文章就有,大家不懂的可以去看看。

4.7,打印输出功能

//打印函数
void PRINTinfo(const contact* pc) {
	assert(pc);
	printf("%-10s %-10s %-10s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0;i < pc->sz;i++) {
		printf("%-10s %-10d %-10s %-12s %-20s\n", pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].phone, pc->date[i].address);
	}

}

打印功能是最简单的函数,逻辑就是遍历联系人的结构体数组,然后把每一个联系人的信息进行格式化的输出就行。

五,主函数框架

#define  _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
void menu() {
	printf("****   通信录系统   ****\n");
	printf("****1,ADD    2,DEL  ****\n");
	printf("****3,SER    4,MOD  ****\n");
	printf("****5,SORT   6,PRINT****\n");
	printf("****0,EXIT          ****\n");
	printf("************************\n");
}

void test() {
	int input = 0;
	contact con;//创建通信录对象
	init(&con);//初始化这个通信录
	do {
		menu();
		printf("请进行选择>>");
		scanf("%d", &input);
		switch (input) {
		case ADD:
			ADDinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case DEL:
			//要删除,得先找到你想删除的人,所以删除函数里面得有一个查找函数
			DELinfo(&con);
			Sleep(3000);//控制3秒会清屏一次,让屏幕输出看起来不冗杂
			system("cls");
			break;
		case SER:
			SERinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case MOD:
			MODinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case SORT:
			SORTinfo(&con);//这里排序我们就按照年龄大小来排序
			Sleep(3000);
			system("cls");
			break;
		case PRINT:
			PRINTinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case EXIT:
			printf("退出通信录!\n");
			break;
		default:
			printf("输入有误,请重新输入!\n");
			break;
		}
		
	} while (input);
}
int main() {
	test();
	return 0;
}

主函数首先就是菜单函数输出,用户根据菜单提示进行选择,选择的值会对应着后面switch结构的相应case语句,然后执行相应的函数。这里case语句后面我们跟着的是枚举常量,枚举常量是有值的,既可以对应相应的功能代号,又可以让代码可读性更高,让人一看就知道某个case后面的功能是干什么的。

六,项目源码

6.1,contact.h文件

#pragma once
#include<string.h>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>
//头文件包含函数的声明 与 类型的声明

//宏定义将后面的一些具体数字进行替换,是代码后期便于更改维护
#define MAX 1000
#define name_max 20
#define sex_max 3
#define phone_max 12
#define address_max 30

//联系人具体信息结构体的声明
typedef struct perinfo {
	char name[name_max];
	int age;
	char sex[sex_max];
	char phone[phone_max];
	char address[address_max];
}perinfo;

//通信录结构体的声明
typedef struct contact {
	perinfo date[MAX];//定义了一个结构体数组,数组的每一个元素都是一个结构体类型,包含很多的成员属性,也就是具体的一个联系人的所有信息
	int sz;//用来记录通信录里面的人数
}contact;

//枚举类型的声明,因为case后面的数字不能很好的直接与功能挂上钩,所以对于我们的选择可以定义一个枚举类型,然后将case后的数字换成具体的功能的名字
//增加代码的可读性
enum option {
	EXIT,
	ADD,
	DEL,
	SER,
	MOD,
	SORT,
	PRINT,
};


//函数声明
//初始化函数
void init(contact* pc);
//添加函数
void ADDinfo(contact* pc);
//查找函数(此查找函数只是单纯找到人返回下标)
int ser_byname(const contact* pc);//只是查找,不会对指针指向的内容进行修改,用const修饰一下
//删除函数
void DELinfo(contact* pc);
//打印函数
void PRINTinfo(const contact* pc);
//查找函数
void SERinfo(const contact* pc);
//修改函数
void MODinfo(contact* pc);
//排序函数
void SORTinfo(contact* pc);
//比较函数
int comparestu(const void* e1, const void* e2);

6.2,contact.c文件

#define  _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
//函数实现
//初始化函数实现
void init(contact *pc) {
	assert(pc);
	memset(pc->date, 0, sizeof(pc->date));//date是结构体数组的数组名,求出整个数组的大小,按字节初始化为0 
	pc->sz = 0;
}

//添加函数
void ADDinfo(contact* pc) {
	assert(pc);
	if (pc->sz == MAX) {
		printf("通信录已满,无法添加!\n");
		return;
	}
	printf("请输入联系人姓名>>\n");
	scanf("%s", pc->date[pc->sz].name);
	printf("请输入联系人年龄>>\n");
	scanf("%d", &(pc->date[pc->sz].age));//这里要注意,因为其他属性都是用数组存储的,所以数组名就是地址,而age是需要取地址才行的
	printf("请输入联系人性别>>\n");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入联系人电话>>\n");
	scanf("%s", pc->date[pc->sz].phone);
	printf("请输入联系人地址>>\n");
	scanf("%s", pc->date[pc->sz].address);

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

//查找函数
int ser_byname(const contact* pc,char* sername) {
	assert(pc);
	for (int i = 0;i < pc->sz;i++) {
		if (0 == strcmp(pc->date[i].name, sername)) {
			return i;//找到了就返回下标
		}
	}
	return -1;//最终找不到就返回0
}

//删除函数
void DELinfo(contact* pc) {
	assert(pc);
	if (pc->sz == 0) {
		printf("通信录已经为空,无法删除!");
		return;
	}
	//1,先找到
	char delname[name_max] = { 0 };
	printf("请输入你要删除的联系人的名字>>\n");
	scanf("%s", &delname);
	int ret = ser_byname(pc,delname);
	//2,删除
	for (int j = ret;j < (pc->sz - 1);j++) {
		pc->date[j] = pc->date[j + 1];
	}
	pc->sz--;
	printf("删除成功!\n");
}

//打印函数
void PRINTinfo(const contact* pc) {
	assert(pc);
	printf("%-10s %-10s %-10s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0;i < pc->sz;i++) {
		printf("%-10s %-10d %-10s %-12s %-20s\n", pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].phone, pc->date[i].address);
	}

}

//查找函数
void SERinfo(const contact* pc) {
	assert(pc);
	//1,先找到
	char sername[name_max] = { 0 };
	printf("请输入你要查找的联系人的名字>>\n");
	scanf("%s", &sername);
	int ret = ser_byname(pc, sername);//利用之前的查找函数拿到下标
	//2,输出
	if (-1 == ret) {
		printf("对不起,查无此人!\n");
		return;
	}
	else {
		printf("已找到如下相关信息>>\n");
		printf("%-10s %-10s %-10s %-12s %-20s\n", "姓名", "年龄", "性别", "电话", "地址");
		printf("%-10s %-10d %-10s %-12s %-20s\n", pc->date[ret].name, pc->date[ret].age, pc->date[ret].sex, pc->date[ret].phone, pc->date[ret].address);
	}
	return;
}

//修改函数
void MODinfo(contact* pc) {
	assert(pc);
	//1,先找到
	char modname[name_max] = { 0 };
	printf("请输入你要修改的联系人的人的名字>>\n");
	scanf("%s", &modname);
	int ret = ser_byname(pc, modname);//利用之前的查找函数拿到下标
	//2,修改
	if (-1 == ret) {
		printf("对不起,无法修改,此通信录下无此人!\n");
		return;
	}
	else {
		printf("请输入修改后的联系人姓名>>\n");
		scanf("%s", pc->date[ret].name);
		printf("请输入修改后的联系人年龄>>\n");
		scanf("%d", &(pc->date[ret].age));
		printf("请输入修改后的联系人性别>>\n");
		scanf("%s", pc->date[ret].sex);
		printf("请输入修改后的联系人电话>>\n");
		scanf("%s", pc->date[ret].phone);
		printf("请输入修改后的联系人地址>>\n");
		scanf("%s", pc->date[ret].address);
		printf("修改成功!\n");
	}
	return;
}

//自定义比较函数
int comparestu(const void* e1,const void* e2) {
	return ((struct perinfo*)e1)->age - ((struct perinfo*)e2)->age;//以年龄作为比较对象
}

//排序函数
void SORTinfo(contact* pc) {
	//这里的排序我们可以用qsort来实现
	qsort(pc->date, pc->sz, sizeof(pc->date[0]), comparestu);
	printf("排序完毕,可使用打印查看!\n");
}

6.3,test.c文件

#define  _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
void menu() {
	printf("****   通信录系统   ****\n");
	printf("****1,ADD    2,DEL  ****\n");
	printf("****3,SER    4,MOD  ****\n");
	printf("****5,SORT   6,PRINT****\n");
	printf("****0,EXIT          ****\n");
	printf("************************\n");
}

void test() {
	int input = 0;
	contact con;//创建通信录对象
	init(&con);//初始化这个通信录
	do {
		menu();
		printf("请进行选择>>");
		scanf("%d", &input);
		switch (input) {
		case ADD:
			ADDinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case DEL:
			//要删除,得先找到你想删除的人,所以删除函数里面得有一个查找函数
			DELinfo(&con);
			Sleep(3000);//控制3秒会清屏一次,让屏幕输出看起来不冗杂
			system("cls");
			break;
		case SER:
			SERinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case MOD:
			MODinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case SORT:
			SORTinfo(&con);//这里排序我们就按照年龄大小来排序
			Sleep(3000);
			system("cls");
			break;
		case PRINT:
			PRINTinfo(&con);
			Sleep(3000);
			system("cls");
			break;
		case EXIT:
			printf("退出通信录!\n");
			break;
		default:
			printf("输入有误,请重新输入!\n");
			break;
		}
		
	} while (input);
}
int main() {
	test();
	return 0;
}

最后最后,终于将这篇博客写完了,篇幅较长,也是感谢大家能够看完,十分感谢!当然也希望大家能够帮忙多多三连,你们的支持将是我最大的动力!

猜你喜欢

转载自blog.csdn.net/qq_61688804/article/details/123782825