手机在线做ppt模板下载网站,做淘宝客网站需要多大空间,郑州seo公司哪家好,做封面电脑网站目录 1、通讯录系统介绍 2、代码分装 3、代码实现步骤
3.1制作菜单函数以及游戏运行逻辑流程 3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型
3.3、初始化通讯录InitContact函数
3.4、增加联系人AddContact函数 3.5、显示所有联系人ShowContact函数 3.6、删除联系人D…目录 1、通讯录系统介绍 2、代码分装 3、代码实现步骤
3.1制作菜单函数以及游戏运行逻辑流程 3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型
3.3、初始化通讯录InitContact函数
3.4、增加联系人AddContact函数 3.5、显示所有联系人ShowContact函数 3.6、删除联系人DelContact函数以及判断是否存在FindByName函数 3.7、查找指定联系人SearchContact函数
3.8、修改指定联系人ModifyContact函数 3.9、以年龄排序联系人SortContact函数 4、使用动态规划优化通讯录 1、通讯录系统介绍 实现一个通讯录 可以保存100个人的信息后续优化成动态开辟增加人的信息删除指定联系人的信息修改指定联系人的信息 查询指定联系人的信息显示所有联系人的信息排序通讯录的信息 其中人的信息包括名字、年龄、性别、电话 、地址 2、代码分装 源文件tect.c 测试通讯录的基本功能 contact.c 相关函数的实现 头文件 contact.h相关函数和类型的声明包含要引用的头文件和宏 3、代码实现步骤
3.1制作菜单函数以及游戏运行逻辑流程 在 test.c 中定义一个menu函数打印菜单提示玩家进行选择增删查改等选线 scanf接收玩家输入并用switch判断针对判断进行相应操作输入错误时提示选择错误重新选择。 用到do while语句为了能够让用户重新选择以及完成一个功能操作时再继续下一个功能操作需要使用do while语句将它们包含起来。 使用枚举一一列举菜单选择的可能取值便于后续使用时能够见名知意增加代码可读性而且枚举变量的值是默认从0开始。 【test.c】
void menu()
{printf(***********************************\n);printf(****** 1.add 2.del ******\n);printf(****** 3.search 4.modify ******\n);printf(****** 5.show 6.sort ******\n);printf(****** 0.exit ******\n);printf(***********************************\n);
}enum Option //枚举常量
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};int main()
{int input 0;do{menu();printf(请输入你的选择:);scanf(%d, input);switch (input){case ADD:break;case DEL:break;case SEARCH:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:printf(退出通讯录\n);break;default:printf(选择错误重新选择\n);break;}} while (input);return 0;
} 3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型 一个人的信息包括很多名字、年龄、性别、电话 、地址。这些成员是不同类型所以创建一个结构体变量来保存人的信息Peoinfo。 同理通讯录也是使用一个结构体要包括人的信息也要知道已经存入多少个人的信息了。 【contact.h】
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30#define MAX 100typedef 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; Contact这个结构体类型中包含了PeoInfo类型的数组data数组的元素是 PeoInfo类型。 还包括sz用于记录当前保存了多少个联系人的信息。 3.3、初始化通讯录InitContact函数
【contact.h】
//初始化通讯录
void InitContact(Contact* pc); 【contact.c】 void InitContact(Contact* pc)
{assert(pc);pc-sz 0;memset(pc-data, 0, sizeof(pc-data));
} 在contact.c中具体的实现这个函数采用指针箭头操作符来访问初始化con中的data成员。 将data和sz初始化为0 assert断言对传入的指针进行判断防止对空指针进行操作。 使用 memset函数 初始化结构体中的数据。 【test.c】
int main()
{int input 0;Contact con; //通讯录InitContact(con);//初始化通讯录do{menu();printf(请输入你的选择:);scanf(%d, input);switch (input){case ADD:break;case DEL:break;case SEARCH:break;case MODIFY:break;case SHOW:break;case SORT:break;case EXIT:printf(退出通讯录\n);break;default:printf(选择错误重新选择\n);break;}} while (input);return 0;
} 创建了一个Contact类型的结构体变量con调用初始化函数把con的地址作为参数传出 在contact.c中具体的实现这个函数采用指针箭头操作符来访问初始化con中的data成员。 3.4、增加联系人AddContact函数
同样是函数的声明
函数的实现
函数的调用
函数的声明【contact.h】
//增加联系人
void AddContact(Contact* pc); 函数的实现【contact.c】
void AddContact(Contact* pc)
{assert(pc);if (pc-sz MAX){printf(通讯录已满无法增加\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);} pc-data[pc-sz].name 就是访问data数组中的第sz个元素的name。也就是用户要添加的是第几个联系人他的名字年龄性别.... 3.5、显示所有联系人ShowContact函数
【contact.h】
//显示所有联系人
void ShowContact(const Contact* pc);
【contact.c】
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);}
} 名为ShowContact的函数用于打印通讯录对象的内容。函数的参数是一个指向const Contact类型的指针。在函数内部首先使用assert宏对传入的指针进行断言确保指针非空。然后判断通讯录的大小sz字段是否为0如果为0则说明通讯录为空打印提示信息并返回。接下来使用一个循环来遍历通讯录的每个联系人对象并使用printf函数按照一定的格式打印联系人的信息。第一次循环打印标题行后续循环每次打印一个联系人的信息。打印的信息包括名字name、年龄age、性别sex、电话tele和地址addr。 【test.c】
在switch语句中的case show调用函数
switch (input){case ADD:AddContact(con);break;case DEL:break;case SEARCH:break;case MODIFY:break;case SHOW:ShowContact(con);break;case SORT:break;case EXIT:printf(退出通讯录\n);break;default:printf(选择错误重新选择\n);break;} 3.6、删除联系人DelContact函数以及判断是否存在FindByName函数 【contact.h】
//删除联系人
void DelContact(Contact* pc); 【contact.c】 因为通过名字判断此人是否存在的FindByName函数这个功能在其他操作上也需要使用到所以最好将它封装成一个函数减少代码冗余并且提高写代码效率。当FindByName函数在通讯录中找到此人时返回此人在data数组中的下标找不到是返回-1。返回-1就是为假又因为FindByName函数只在contact.c中被使用因此可以加上static关键字修饰。 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) //两个字符串比较用strcmpreturn i;}return -1;
}void DelContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc-sz 0){printf(通讯录为空无法删除\n);return;}printf(请输入要删除人的名字:);scanf(%s, name);//查找名字为name的人int ret FindByName(pc, name);if (ret -1){printf(要删除的人不存在\n);return;}//删除这个人int i 0;for (i ret; i pc-sz - 1; i) //注意此处的sz - 1 {pc-data[i] pc-data[i 1];}pc-sz--;printf(删除成功\n);
} DelContact函数中创建的char类型的数组name是为了存储要删除的联系人的名字。这是因为在循环中进行联系人比较时我们需要将要删除的联系人的名字与contacts数组中的每个联系人的名字进行比较以找到要删除的联系人的索引。如果没有name数组并且直接在循环中将contacts[i].name与要删除的联系人的名字进行比较那么在找到要删除的联系人之后我们将无法在后续的循环中对其进行操作。因为我们只能访问到contacts[i]和contacts[i-1]找不到要删除的联系人的索引。通过将要删除的联系人的名字存储在name数组中我们可以在找到要删除的联系人之后继续使用它的索引进行相应操作例如移动后面的联系人、更新sz等等。这样就可以正确地删除联系人并保持contacts数组的完整性。 在代码中DelContact函数的最后一个循环是为了从contacts数组中删除指定的联系人。循环通过将指定位置后面的联系人逐个向前移动一位来实现。因此循环条件是i sz-1即i的值需要小于sz-1。这是因为删除联系人时需要将后面的联系人向前移动一个位置。而不是用后面的一个联系人来覆盖要删除的联系人。如果循环条件是i sz那么最后一个联系人将无法被移动因为没有后面的联系人可以填充它的位置。比如现在是10个联系人因此循环条件为i sz-1确保了所有联系人都能被正确地向前移动一位保证了联系人信息的完整性。 将ret后面的所有内容向前平移一位就可以覆盖掉要ret指向的内容然后再对sz--这样变相地完成了对信息的删除。等将来又有新联系人加入时因为sz--了所以写入信息时会覆盖掉下标为ret中的内容。 3.7、查找指定联系人SearchContact函数
【contact.h】
//查找指定联系人
void SearchContact(Contact* pc); 【contact.c】 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);} 3.8、修改指定联系人ModifyContact函数 【contact.h】 //修改指定联系人
void ModifyContact(Contact* pc); 【contact.c】 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);
} 调用FindByName函数进行判断有此人则返回下标没有此人则返回-1。 找到之后直接将该下标下的所有信息都重新接收并覆盖就完成了修改操作。 3.9、以年龄排序联系人SortContact函数 【contact.h】 //排序联系人
void SortContact(Contact* pc); 【contact.c】 int cmp_age(const void* e1, const void* e2)
{return ((PeoInfo*)e1)-age - ((PeoInfo*)e2)-age;
}void SortContact(Contact* pc)
{assert(pc);if (pc-sz 0){printf(通讯录为空无需排序\n);return;}qsort(pc, pc-sz, sizeof(PeoInfo), cmp_age);printf(排序成功\n);
} 仍然存在的问题 1.录入的信息等程序结束后就不存在了这是因为数据存放在内存中的。为了解决这个问题需要使用到文件存储的知识。 2.通讯录的大小是固定的100个元素只能最多存放100个人。当信息太少时就会导致空间剩余过大浪费空间而当信息太多时空间又太小了无法进行存入而解决这个问题需要使用到动态内存管理的知识。下面就来优化一下通讯录。 4、使用动态规划优化通讯录 规定 通讯录刚开始时可以存放3个人的信息。#define DEFAULT_SZ 3当空间放满时自动增加容量每次增加2个信息的空间。#define DEFAULT_INC 2 定义通讯录Contact结构体 首先是通讯录这个结构体要修改因为原来定死了是100人这里使用一个PeoInfo类型的指针空间是malloc开辟的方便我们使用realloc来调整大小 【静态】
静态版本
typedef struct Contact
{PeoInfo data[MAX];int sz; //记录的是当前通讯录中存放的人的信息个数
}Contact; 【动态】
动态版本
typedef struct Contact
{PeoInfo* data;int sz; //记录的是当前通讯录中存放的人的信息个数int capacity; //记录的时通讯录当前的最大容量
}Contact; sz记录的是当前通讯录中存放的人的信息个数 capacity记录的时通讯录当前的最大容量 当szcapacit就要考虑增容了 初始化通讯录InitContact函数 使用calloc对data指针进行动态开辟空间如果开辟失败则用perror打印错误信息 【静态】 静态版本
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;memset(pc-data, 0, sizeof(pc-data));
}【动态】 初始化szcapacitydata使用calloc来开辟就要判断返回的指针是不是为NULL void InitContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity DEFAULT_SZ; //#define DEFAULT_SZ 3pc-data (PeoInfo*)calloc(pc-capacity, sizeof(PeoInfo));if (pc-data NULL){perror(InitContact-calloc);return;}
}增加联系人AddContact函数 人满了就要增加容量判断条件是当szcapacit就要考虑增容了。使用if语句。使用realloc函数增容记得要先创建一个指针tmp来判断返回的指针是不是为NULL不为NULL是赋值给p 【静态】 静态版本
void AddContact(Contact* pc)
{assert(pc);if (pc-sz MAX){printf(通讯录已满无法增加\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);}【动态】 void AddContact(Contact* pc)
{assert(pc);if (pc-sz pc-capacity){PeoInfo* tmp (PeoInfo*)realloc(pc-data, (pc-capacity DEFAULT_INC) * sizeof(PeoInfo));if (tmp ! NULL){pc-data tmp;pc-capacity DEFAULT_INC; //#define DEFAULT_INC 2printf(增容成功\n);}else{perror(AddContact-realloc);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);}pc-data就是指针这个data是一个PeoInfo类型的指针 也可以把这个增容的操作单独封装成一个函数
if (pc-sz pc-capacity){PeoInfo* tmp (PeoInfo*)realloc(pc-data, (pc-capacity DEFAULT_INC) * sizeof(PeoInfo));if (tmp ! NULL){pc-data tmp;pc-capacity DEFAULT_INC; //#define DEFAULT_INC 2printf(增容成功\n);}else{perror(AddContact-realloc);return;}} 在EXIT退出通讯录时候记得对动态开辟的空间进行free操作
【contact.h】
//销毁通讯录
void DestroyContact(Contact* pc);
【contact.c】
void DestroyContact(Contact* pc)
{free(pc-data);pc-data NULL;pc-sz 0;pc-capacity 0;
} 结束