交易 网站备案,建筑设计网站免费,安阳网约车准入条件,市场调研公司是做什么的C语言程序设计笔记---039 C语言之实现通讯录1、介绍C/C程序的内存开辟2、C语言实现通讯录2.1、ContactMain.c程序大纲2.2、Contact2.h2.3、Contact2.c2.3.1 InitContact( )初始化通讯录函数2.3.2 AddContact( )添加联系人和CheckCapaticy( )检查容量函数2.3.3、ShowContact( )显… C语言程序设计笔记---039 C语言之实现通讯录1、介绍C/C程序的内存开辟2、C语言实现通讯录2.1、ContactMain.c程序大纲2.2、Contact2.h2.3、Contact2.c2.3.1 InitContact( )初始化通讯录函数2.3.2 AddContact( )添加联系人和CheckCapaticy( )检查容量函数2.3.3、ShowContact( )显示联系人函数2.3.4、DelContact( )删除联系人和FindByName( )函数2.3.5、SearchContact( )查找联系人2.3.6、ModifyContact( )修改联系人2.3.7、CleanContact( )清空联系人2.3.8、SortContact( )排序联系人 4、结语 C语言之实现通讯录
前言 通过C语言自定义类型的知识这篇将对动态内存的管理知识接下来进行应用学习写一个简易的通讯录。
/知识点汇总/
1、介绍C/C程序的内存开辟
大致整体空间的分配 内核空间用户代码…(不能读写) 栈区:局部变量、形式参数… 内存映射段:文件映射、动态库、匿名映射… 堆区:动态内存、malloc/calloc/free… 数据段(数据段):全局数据、静态数据、static常变量… 代码段:可执行代码、只读常量 具体如下图所示
2、C语言实现通讯录 实现一个通讯录 通讯录可以用来存储1000个人的信息每个人的信息包括姓名、性别、年龄、电话、住址 提供方法 1.添加联系人信息 2.删除指定联系人信息 3.查找指定联系人信息 4.修改指定联系人信息 5.显示所有联系人信息 6.清空所有联系人 7.以名字排序所有联系人 2.1、ContactMain.c程序大纲
首先从生活实际使用的角度出发我们需要一个显示的菜单显示我们需要的功能集。 这里可以前面篇章所学的menu( )自定义函数设计一个简易的菜单。
//菜单
void menu()
{printf(*************************************\n);printf(******** 1.add 2.del *****\n);printf(******** 3.sreach 4.modify*****\n);printf(******** 5.show 6.sort *****\n);printf(******** 7.clean 0.exit *****\n);printf(*************************************\n);
}为了让选项贴合实际数字0~7可以使用一个自定义类型所学的枚举类型来列举引用即可。
//枚举常量
enum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT,//6CLEAN//7
};其中可以看见我把EXIT写在第一个这样是为了利用枚举成员变量未初始化是默认从0开始的特点从而与选项一致对应。 那么接下来主函数中就是利用do while和 switch 搭建一个程序执行框架。
int main()
{int input 0;//创建通讯录Contact con;//初始化通讯录InitContatc(con);do{menu();printf(请选择:);scanf(%d, input);switch (input){case ADD:printf(\n添加联系人\n\n);AddContact(con);break;case DEL:printf(\n删除联系人\n\n);DelContact(con);break;case SEARCH:printf(\n搜索联系人\n\n);SearchContact(con);break;case MODIFY:printf(\n修改联系人\n\n);ModifyContact(con);break;case SHOW:printf(\n显示联系人\n\n);ShowContact(con);break;case SORT:printf(\n排序联系人\n\n);SortContact(con);break;case CLEAN:printf(\n清空联系人\n\n);CleanContact(con);break;case EXIT:printf(\n退出通讯录\n\n);break;default:printf(\n输入错误请重新输入\n\n);break;}} while (input);return 0;
}主函数首先定义一个input由玩家输入的变量然后同步switch语句根据选项进入不同的入口分别执行添加联系人、删除联系人、搜索联系人、修改联系人、显示联系人、排序联系人、清空联系人、退出通讯录以及输入数值不对做出一个反馈输入错误的提示信息。
2.2、Contact2.h
主要用于存放所自定义的函数和头文件等声明的程序 由于涉及多种类型的数据所以最好的方法就是定义一个结构体类型。 然后这里同时提供通讯录初始化的静态数组的版本也提供动态内存的写法利用前篇动态内存空间管理的知识申请动态开辟空间和管理。 其它的声明通俗易懂就不多赘述详见代码注释的说明。
#include stdio.h
#include assert.h
#include string.h
#include stdlib.h
#include windows.h#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 20
#define ADDR_MAX 20//#define MAX 100
#define DEFAULT_SZ 3 //默认容量
#define DEFAULT_INC 2 //增容量
//结构体类型申明
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;//创建通讯录 --- 静态版本
//typedef struct Contact
//{
// PeoInfo data[MAX];//通讯录容量
// int sz;//当前通讯录的信息个数
//}Contact;//创建通讯录 --- 动态版本
typedef struct Contact
{PeoInfo* data;//指向通讯录的数据int sz;//当前通讯录的信息个数int capacity;//记录当前通讯录的容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//销毁通讯录
void DestoryContact(Contact* pc);//显示通讯录
void ShowContact(Contact* pc);//删除联系人
void DelContact(Contact* pc);//查找联系人
void SearchContact(Contact* pc);//修改联系人
void ModifyContact(Contact* pc);//清空通讯录
void CleanContact(Contact* pc);//排序通讯录
void SortContact(Contact* pc);2.3、Contact2.c
主要用于存放对 ContactMain.c 程序大纲做提到的函数进行封装实现具体的功能的程序 说明基于ContactMain.c 程序大纲逻辑对代码进行讲解
2.3.1 InitContact( )初始化通讯录函数
首先在头文件中定义了结构体成员和创建好后根据主函数逻辑对通讯录进行初始化. 初始化可以理解为将通讯录的数据赋予一个初始值方便我们后续对其进行操作。 sz清零就是使得当前存放的长度为0capacity清零就是让容量为默认的3个容量 接下来就是将数据初始化这里为了直接方便的初始化所以选择使用calloc而不是malloc函数来初始化因为它们的区别就在于calloc会直接将每个字节初始化为0而malloc不会初始化。 然后结合参数的意思就是将申请开辟默认容量乘以结构体得的大小的空间。 为了代码的规范性、健壮性需要做开辟空间失败的反馈。
//初始化通讯录 -- 静态版本
//void InitContact(Contact* pc)
//{
// assert(pc);
// pc-sz 0;
// memset(pc-data, 0, sizeof(pc-data));//将数据以每个字节设置或初始化为0
//}//初始化通讯录 -- 动态版本
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity DEFAULT_SZ;pc-data calloc(pc-capacity , sizeof(PeoInfo));if (pc-data NULL){perror(InitContact-calloc\n);return;}
}2.3.2 AddContact( )添加联系人和CheckCapaticy( )检查容量函数
同样提供了静态版本和动态版本简单说明一下静态和动态的区别当我们不清楚需要多大的空间时比如需要存放1000个数据静态给10太小给10000太大所以存在空间资源的浪费甚至是溢出等情况那么就引用动态的方式存储就可以实现灵活的开辟空间和释放空间既满足需求也能合理使用空间资源。那么接下来都是以动态进行分享思路。 回到添加联系人的函数体我们每次存入数据前肯定需要检查是否能够存放得下那么就需要对当前空间的剩余量与数据的大小进行判断如果放不下那么就执行扩容反之就是放得下。 那么就可以继续执行添加联系人得信息利用的是按照逻辑访问结构体成员依次添加最后完成一个数据添加后sz当前通讯录的信息个数随着加1。 对于增容函数主要是依靠realloc函数实现增容。参数是开辟空间的首地址和增容的大小。 另外对于realloc还有一种特殊情况就不展开了详见前篇动态内存空间管理的知识。
//增加联系人 --- 静态版本
//void AddContact(Contact* pc)
//{
// assert(pc);
// if (pc-sz MAX)
// {
// printf(\n通讯录已满无法增加\n\n);
// return;
// }
// //增加信息
// 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增加成功\n\n);
//}//增容函数
static void CheckCapaticy(Contact* pc)
{if (pc-sz pc-capacity){PeoInfo* ptr realloc(pc-data, (pc-capacity DEFAULT_INC) * sizeof(PeoInfo));if (ptr ! NULL){pc-data ptr;pc-capacity DEFAULT_INC;printf(\n增容成功\n\n);}else{perror(AddContact-realloc\n);return;}}
}
//增加联系人 --- 动态版本
void AddContact(Contact* pc)
{assert(pc);//如果容量与信息相等自动增加容量CheckCapaticy(pc);//增加信息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增加成功\n\n);
}2.3.3、ShowContact( )显示联系人函数
这个函数的逻辑就比较简单了就是遍历数据成员依次打印出来就行重点在于对界面符合一定的审美包括占位符、缩进。标题行的重要性等比较灵活这里仅提供参考一种打印效果如下所示
//显示通讯录
void ShowContact(Contact* pc)
{assert(pc);if (pc-sz 0){printf(\n无法显示通讯录为空\n\n);return;}//显示联系人//打印标题 -- 美化printf(%-10s%-5s%-5s%-20s%-20s\n, 姓名, 年龄, 性别, 电话, 地址);//打印联系人信息int i 0;for (i 0; i pc-sz; i){printf(%-10s%-5d%-5s%-20s%-20s\n,pc-data[i].name, pc-data[i].age, pc-data[i].sex, pc-data[i].tele, pc-data[i].addr);}
}2.3.4、DelContact( )删除联系人和FindByName( )函数
对于删除函数我们需要先判断是否为空当数据为空没有删除的对象了顾名思义就不能删除了其次我们需要删除某个联系人对象与后面的查找联系人和修改联系人都需要去遍历查找所以为了方便调用就封装了一个匹配联系人的函数FindByName并且是根据联系人姓名来进行匹配的。直接使用strcmp即可。在删除目标联系人后后面的数据就得向前移动。使用for语句移动最后sz也需要随着减1。
//匹配联系人函数
static int FindByName(Contact* pc, char* name)
{assert(pc);int i 0;for (i 0; i pc-sz; i){if (strcmp(pc-data[i].name, name) 0){return i;}}return -1;
}
//删除联系人
void DelContact(Contact* pc)
{assert(pc);if (pc-sz 0){printf(\n无法删除通讯录为空\n\n);return;}//输入要删除的联系人姓名char name[NAME_MAX];printf(请输入要删除联系人的姓名:);scanf(%s, name);//查找匹配联系人int ret FindByName(pc, name);if (ret -1){printf(\n无此联系人\n\n);return;}//删除联系人int i 0;for (i ret; i pc-sz; i){pc-data[i] pc-data[ i 1];}//处理最后一个联系人pc-sz--;printf(\n删除成功\n\n);
}2.3.5、SearchContact( )查找联系人
查找联系人的套路都大相径庭了结合匹配函数找到对应的联系人然后单独打印输出即可。
//查找联系人
void SearchContact(Contact* pc)
{assert(pc);if (pc-sz 0){printf(\n无法查找通讯录为空\n\n);return;}//输入要查找的联系人姓名char name[NAME_MAX];printf(请输入要查找联系人的姓名:);scanf(%s, name);//查找匹配联系人int ret FindByName(pc, name);if (ret -1){printf(\n无此联系人\n\n);return;}//显示对应联系人//打印标题 -- 美化printf(%-10s%-5s%-5s%-20s%-20s\n, 姓名, 年龄, 性别, 电话, 地址);//打印联系人信息printf(%-10s%-5d%-5s%-20s%-20s\n,pc-data[ret].name,pc-data[ret].age,pc-data[ret].sex,pc-data[ret].tele,pc-data[ret].addr);
} 2.3.6、ModifyContact( )修改联系人
修改联系人在理解了前面的内容也不难理解结合匹配联系人的函数找到需要修改的联系人然后输入修改后的信息即可。但是这里比较冗余不难发现会修改联系人的所有属性。可以增加一个switch选择只需要更改的属性即可。值得注意的是在以上结合匹配函数的条件下使用的是返回值ret才能正确符合逻辑运行哦,不能盲目复制粘贴前面的添加联系人的输入信息部分的代码。
//修改联系人
void ModifyContact(Contact* pc)
{assert(pc);if (pc-sz 0){printf(\n无法修改通讯录为空\n\n);return;}//输入要修改的联系人姓名char name[NAME_MAX];printf(请输入要修改联系人的姓名:);scanf(%s, name);//查找匹配联系人int ret FindByName(pc, name);if (ret -1){printf(\n无此联系人\n\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修改成功\n\n);
}2.3.7、CleanContact( )清空联系人
清空通讯录跟初始化通讯录类似信息重新清零或者复位即可。
//清空通讯录
void CleanContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity 0;free(pc-data);pc-data NULL;//pc-data 0;printf(\n已清空通讯录\n\n);
}2.3.8、SortContact( )排序联系人
排序联系人主要结合了前面篇章的qsort函数的功能这里完成的是以姓名排序。
//排序通讯录
//void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
static cmp_by_name(const void* e1,const void* e2)
{return strcmp(((PeoInfo*)e1)-name, ((PeoInfo*)e2)-name);
}void SortContact(Contact* pc)
{assert(pc);if (pc-sz 0){printf(\n无法排序通讯录为空\n\n);return;}//排序联系人qsort(pc-data, pc-sz, sizeof(pc-data[0]), cmp_by_name);printf(\n排序成功\n\n);
}4、结语
相信通过这样一个简易通讯录的实现更具掌握了对数组、动态内存管理的操作以及对自定义函数的深刻认识 如果觉着文章对您有所帮助请不要吝啬的一赞三连哦谢谢阅读不足之处还请多多指教。 半亩方糖一鉴开天光云影共徘徊。 问渠哪得清如许?为有源头活水来。–朱熹观书有感