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

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#include#include#include#include//头文件包含函数的声明 与 类型的声明//宏定义将后面的一些具体数字进行替换,是代码后期便于更改维护#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 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 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 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#include#include#include#include//头文件包含函数的声明 与 类型的声明//宏定义将后面的一些具体数字进行替换,是代码后期便于更改维护#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 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 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 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;}

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