遵义网站建设gzyhg,怎么在网上找接单做网站的公司,php网站开发程序编译软件,注册公司如何做网站⚪前言 前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客#xff0c;但是静态版通讯录的空间是无法被改变的#xff0c;而且空间利用率也不高。为了解决静态通讯录这一缺点#xff0c;这时就要有一个能够随着存入联系人数量的增加而增大…⚪前言 前面详细介绍了静态版通讯录【C语言】静态通讯录 -- 详解_炫酷的伊莉娜的博客-CSDN博客但是静态版通讯录的空间是无法被改变的而且空间利用率也不高。为了解决静态通讯录这一缺点这时就要有一个能够随着存入联系人数量的增加而增大空间的通讯录。接下来我们将探讨动态通讯录在能够实现静态版通讯录的基础上能够灵活调整通讯录联系人数量并实现其基本功能。 以下内容是在静态通讯录的基础上进行修改大致思路不变。 一、实现目标
1、功能 保存 1000 个联系人的信息添加联系人删除联系人修改联系人查找联系人排序 2、个人信息结构体 名字年龄性别电话地址 动态版通讯录的要求 默认能够存放 3 个联系人信息。不够的话每次增加 2 个联系人信息。 二、创建文件 test.c专门测试通讯录的功能contact.c接口的实现contact.h接口的声明 三、初始页面的实现
1、实现主菜单页面
// test.c
1menu()
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);
}
效果图如下 2main()
int main()
{int input 0;// 创建通讯录struct Contact con; // con就是通讯录里边包含data指针和sizecapacity// 初始化通讯录InitContact(con);do{menu();printf(请选择);scanf(%d, input);switch (input){case ADD:AddContact(con);break;case DEL:DelContact(con);break;case SEARCH:SearchContact(con);break;case MODIFY:ModifyContact(con);break;case SHOW:ShowContact(con);break;case SORT:SortContact(con);break;case EXIT:DestoryContact(con); // 销毁通讯录-释放动态开辟的内存printf(退出通讯录\n);break;default:printf(选择错误\n);break;}} while (input);return 0;
}
main() 函数代码中与之前的区别主要就是要在初始化的时候开辟动态内存空间在输入 0 退出程序时会将通讯录删除。其实仔细想想确实需要这一步因为在整个程序都没有结束时动态开辟内存也并没有结束所以只能是在整个程序结束的时候才能将动态开辟的内存释放掉。 2、在contact.h 中引用所需要的文件和必要的定义
首先我们要 声明一个结构体其中 包含了我们想要保存的信息可以自己设置 typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo; 定义结构体与静态通讯录不同 动态通讯录在定义结构体时应该增加一个元素capacity来记录当前通讯录的最大容量当达到这个最大容量的时候就对动态通讯录进行扩容增加内存空间这样就能够很好地实现动态通讯录。 静态通讯录与动态通讯录最大的不同就在这静态版是直接使用一个开辟好的数组而动态版是使用一个指针变量用于指向使用动态内存申请函数 malloc 所开辟的空间然后使用开辟的这块空间对联系人信息进行储存最大的优点是可以使用 realloc 函数对其进行扩容。这样就解决了静态通讯录在空间上的不足。 // 动态通讯录类型
typedef struct Contact
{struct PeoInfo *data; // 存放数据int size; // 记录当前已经有的元素个数int capacity; // 记录当前通讯录的最大容量
}Contact;// 静态通讯录类型
struct Contact
{struct PeoInfo data[MAX];// 可以存放1000个人的信息int size;// 记录通讯录中已经保存的信息个数
}; 整体逻辑
// contact.h
#pragma once // 避免头文件被重复引用// #define MAX 1000#define DEFAULT_SZ 3 // 通讯录初始状态的容量大小#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30#include stdio.h
#include string.h // memset strcmp
#include stdlib.h // qsort malloc realloc
#include assert.h // assertenum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};// 动态通讯录类型
typedef struct Contact
{struct PeoInfo *data; // 存放数据int size; // 记录当前已经有的元素个数int capacity; // 记录当前通讯录的最大容量
}Contact;// 声明函数
// 初始化通讯录
void InitContact(struct Contact* ps);
// 增加联系人
void AddContact(struct Contact* ps);
// 展示通讯录信息
void ShowContact(const struct Contact* ps);
// 删除指定联系人信息
void DelContact(struct Contact* ps);
// 查找指定联系人信息
void SearchContact(const struct Contact* ps);
// 修改指定联系人信息
void ModifyContact(struct Contact* ps);
// 排序通讯录内容按姓名排
void SortContact(struct Contact* ps);
// 销毁通讯录
void DestoryContact(Contact* ps); 四、在 contact.c 上实现各个接口函数
1、初始化通讯录 malloc 函数在这里并没有把其数据初始化为 0 这里可以使用 memset 函数初始化存放联系人信息的结构体数组 data。 对于动态通讯录的初始化就是申请一块初始的空间用来存放信息如果满了在在此基础上进行扩容。 // 初始化通讯录
void InitContact(struct Contact* ps)
{assert(ps);ps-size 0;ps-capacity DEFAULT_SZ;ps-data (struct PeoInfo*)malloc(ps-capacity * sizeof(struct PeoInfo));if (ps-data NULL){perror(InitContact::malloc);return;}memset(ps-data, 0, ps-capacity * sizeof(struct PeoInfo));
} 2、添加联系人 先判断通讯录人数是否已满满了需要扩容对已经申请过的空间进行扩容可以使用库函数 realloc 实现。满了一次扩容 2 联系人信息的空间。 // 检测当前通讯录的容量
void CheckCapacity(struct Contact* ps)
{if (ps-size ps-capacity){//增容struct PeoInfo* ptr realloc(ps-data, (ps-capacity 2) * sizeof(PeoInfo));if (ptr ! NULL){ps-data ptr;ps-capacity 2;printf(增容成功\n);}else{printf(增容失败\n);}}
}// 添加联系人
void AddContact(struct Contact* ps)
{assert(ps);// 检测当前通讯录的容量// 1、如果满了就增加空间// 2、如果没满无需任何操作CheckCapacity(ps);// 增加数据printf(请输入名字);scanf(%s, ps-data[ps-size].name);printf(请输入年龄);scanf(%d, (ps-data[ps-size].age)); // 年龄是一个整型变量 需要取地址printf(请输入性别);scanf(%s, ps-data[ps-size].sex);printf(请输入电话);scanf(%s, ps-data[ps-size].tele);printf(请输入地址);scanf(%s, ps-data[ps-size].addr);ps-size;printf(添加成功\n);
} 注意由于 age 在这里是一个整型变量所以要加上 。 3、展示通讯录中的信息
// 展示通讯录中的信息
void ShowContact(const struct Contact* ps)
{if (ps-size 0){printf(通讯录为空\n); // 判断通讯录人数是否为0}else{int i 0;// 打印标题printf(%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n, 名字, 年龄, 性别, 电话, 地址);// 打印数据for (i 0; i ps-size; i){printf(%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n,ps-data[i].name,ps-data[i].age,ps-data[i].sex,ps-data[i].tele,ps-data[i].addr);}}
} 注意因为只是打印信息不会修改内容所以加上 const 更加安全。 为了让结果更美观采用了左对齐的方式。printf 中 %-20s 中的 20 是指输出字段的宽度负号表示左对齐如省略表示右对齐如果输出的数据位数小于 20则在数据右端补齐空格。 4、通过姓名查找指定联系人所在的下标
// 通过姓名查找指定联系人所在下标
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{int i 0;for (i 0; i ps-size; i){if (0 strcmp(ps-data[i].name, name)){return i; // 查找到返回联系人的下标}}return -1; // 找不到返回-1
} 为了解决代码的冗余我们不妨分装一个函数来完成查找功能。该函数会在删除 / 修改 / 查找指定联系人信息的函数中被调用到这些函数刚好又在同一源文件中所以用 static 修饰函数只能在所在此文件内使用。 5、删除指定联系人信息 先判断通讯录是否为空如果不为空再通过 FindByName() 函数查找通讯录中是否有你要删除的联系人如果有则删除。 原理把要删除的联系人后面一个人的信息依次从前向后往前移动一位覆盖掉其信息然后再将人数 -1。 // 删除指定联系人
void DelContact(struct Contact* ps)
{char name[MAX_NAME];int pos 0;printf(请输入要删除人的名字);scanf(%s, name);// 1、查找要删除的人在什么位置// 找到了返回名字所在元素的下标// 找不到返回 -1pos FindByName(ps, name);// 2、删除if (pos -1){printf(要删除的人不存在\n);}else{// 删除数据int j 0;for (j pos; j ps-size - 1; j){// 把要删除的人后面一个人的信息依次从前向后往前移动一位覆盖掉其信息ps-data[j] ps-data[j 1];}ps-size--;printf(删除成功\n);}
} 6、查找指定联系人信息 通过 FindByName() 函数查找通讯录中是否有你要查找的联系人如果查找到则打印该联系人的信息。 // 查找指定联系人信息
void SearchContact(const struct Contact* ps)
{int pos 0;char name[MAX_NAME];printf(请输入要查找人的名字);scanf(%s, name);pos FindByName(ps, name); // 查找if (pos -1){printf(要查找的人不存在\n);}else{printf(%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n, 名字, 年龄, 性别, 电话, 地址);//数据printf(%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n,ps-data[pos].name,ps-data[pos].age,ps-data[pos].sex,ps-data[pos].tele,ps-data[pos].addr);}
} 注意因为只是查找信息不会修改内容所以加上 const 更加安全 。 7、修改指定联系人信息 通过 FindByName() 函数查找通讯录中是否有你要修改信息的联系人如果有则修改。 // 修改指定联系人信息
void ModifyContact(struct Contact* ps)
{int pos 0;char name[MAX_NAME];printf(请输入要修改人的名字);scanf(%s, name);pos FindByName(ps, name);if (pos -1){printf(要修改人的信息不存在\n);}else{printf(请输入名字);scanf(%s, ps-data[pos].name);printf(请输入年龄);scanf(%d, ps-data[pos].age);printf(请输入性别);scanf(%s, ps-data[pos].sex);printf(请输入电话);scanf(%s, ps-data[pos].tele);printf(请输入地址);scanf(%s, ps-data[pos].addr);printf(修改完成\n);}
} 8、排序通讯录内容 // 排序通讯录内容
// 比较结构体数组中两个元素的姓名成员
int compareStructType_name(const void* elem1, const void* elem2)
{// 姓名成员是字符串用strcmp比较return strcmp(((struct PeoInfo*)elem1)-name, ((struct PeoInfo*)elem2)-name);
}// 以名字排序所有联系人
void SortContact(struct Contact* ps)
{// 判断通讯录是否为空if (ps-size 0){printf(通讯录为空无法排序\n);return;}else{// 根据姓名成员对结构体数组升序排列qsort(ps-data, ps-size, sizeof(ps-data[0]), compareStructType_name);printf(以名字排序联系人成功\n);}
} 该函数排序用的是姓名作为标准也可以自己更换其他的排序方式。 9、销毁通讯录 使用动态内存开辟的空间是需要归还的当通讯录使用完后是需要归还内存的也就需要我们销毁通讯录。 // 销毁通讯录
void DestoryContact(Contact* ps)
{free(ps-data);ps-data NULL;ps-capacity 0;ps-size 0;printf(销毁成功\n);
} 五、代码整合
1、test.c
// test.c
#define _CRT_SECURE_NO_WARNINGS 1#include contact.hvoid 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);
}int main()
{int input 0;// 创建通讯录struct Contact con; // con就是通讯录里边包含data指针和sizecapacity// 初始化通讯录InitContact(con);do{menu();printf(请选择);scanf(%d, input);switch (input){case ADD:AddContact(con);break;case DEL:DelContact(con);break;case SEARCH:SearchContact(con);break;case MODIFY:ModifyContact(con);break;case SHOW:ShowContact(con);break;case SORT:SortContact(con);break;case EXIT:DestoryContact(con); // 销毁通讯录-释放动态开辟的内存printf(退出通讯录\n);break;default:printf(选择错误\n);break;}} while (input);return 0;
} 2、contact.h
// contact.h
#pragma once // 避免头文件被重复引用// #define MAX 1000#define DEFAULT_SZ 3 // 通讯录初始状态的容量大小#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30#include stdio.h
#include string.h // memset strcmp
#include stdlib.h // qsort malloc realloc
#include assert.h // assertenum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};// 动态通讯录类型
typedef struct Contact
{struct PeoInfo *data; // 存放数据int size; // 记录当前已经有的元素个数int capacity; // 记录当前通讯录的最大容量
}Contact;// 声明函数
// 初始化通讯录
void InitContact(struct Contact* ps);
// 增加联系人
void AddContact(struct Contact* ps);
// 展示通讯录信息
void ShowContact(const struct Contact* ps);
// 删除指定联系人信息
void DelContact(struct Contact* ps);
// 查找指定联系人信息
void SearchContact(const struct Contact* ps);
// 修改指定联系人信息
void ModifyContact(struct Contact* ps);
// 排序通讯录内容按姓名排
void SortContact(struct Contact* ps);
// 销毁通讯录
void DestoryContact(Contact* ps); 3、contact.c
// contact.c
#define _CRT_SECURE_NO_WARNINGS 1#include contact.h// 初始化通讯录
void InitContact(struct Contact* ps)
{assert(ps);ps-size 0;ps-capacity DEFAULT_SZ;ps-data (struct PeoInfo*)malloc(ps-capacity * sizeof(struct PeoInfo));if (ps-data NULL){perror(InitContact::malloc);return;}memset(ps-data, 0, ps-capacity * sizeof(struct PeoInfo));
}// 检测当前通讯录的容量
void CheckCapacity(struct Contact* ps)
{if (ps-size ps-capacity){//增容struct PeoInfo* ptr realloc(ps-data, (ps-capacity 2) * sizeof(PeoInfo));if (ptr ! NULL){ps-data ptr;ps-capacity 2;printf(增容成功\n);}else{printf(增容失败\n);}}
}// 添加联系人
void AddContact(struct Contact* ps)
{assert(ps);// 检测当前通讯录的容量// 1、如果满了就增加空间// 2、如果没满无需任何操作CheckCapacity(ps);// 增加数据printf(请输入名字);scanf(%s, ps-data[ps-size].name);printf(请输入年龄);scanf(%d, (ps-data[ps-size].age)); // 年龄是一个整型变量 需要取地址printf(请输入性别);scanf(%s, ps-data[ps-size].sex);printf(请输入电话);scanf(%s, ps-data[ps-size].tele);printf(请输入地址);scanf(%s, ps-data[ps-size].addr);ps-size;printf(添加成功\n);
}// 展示通讯录中的信息
void ShowContact(const struct Contact* ps)
{if (ps-size 0){printf(通讯录为空\n); // 判断通讯录人数是否为0}else{int i 0;// 打印标题printf(%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n, 名字, 年龄, 性别, 电话, 地址);// 打印数据for (i 0; i ps-size; i){printf(%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n,ps-data[i].name,ps-data[i].age,ps-data[i].sex,ps-data[i].tele,ps-data[i].addr);}}
}// 通过名字查找指定联系人所在的下标
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{int i 0;for (i 0; i ps-size; i){if (0 strcmp(ps-data[i].name, name)){return i;}}return -1; // 找不到返回-1
}// 删除指定联系人
void DelContact(struct Contact* ps)
{char name[MAX_NAME];int pos 0;printf(请输入要删除人的名字);scanf(%s, name);// 1、查找要删除的人在什么位置// 找到了返回名字所在元素的下标// 找不到返回 -1pos FindByName(ps, name);// 2、删除if (pos -1){printf(要删除的人不存在\n);}else{// 删除数据int j 0;for (j pos; j ps-size - 1; j){// 把要删除的人后面一个人的信息依次从前向后往前移动一位覆盖掉其信息ps-data[j] ps-data[j 1];}ps-size--;printf(删除成功\n);}
}// 查找指定联系人信息
void SearchContact(const struct Contact* ps)
{int pos 0;char name[MAX_NAME];printf(请输入要查找人的名字);scanf(%s, name);pos FindByName(ps, name); // 查找if (pos -1){printf(要查找的人不存在\n);}else{printf(%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n, 名字, 年龄, 性别, 电话, 地址);//数据printf(%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n,ps-data[pos].name,ps-data[pos].age,ps-data[pos].sex,ps-data[pos].tele,ps-data[pos].addr);}
}// 修改指定联系人信息
void ModifyContact(struct Contact* ps)
{int pos 0;char name[MAX_NAME];printf(请输入要修改人的名字);scanf(%s, name);pos FindByName(ps, name);if (pos -1){printf(要修改人的信息不存在\n);}else{printf(请输入名字);scanf(%s, ps-data[pos].name);printf(请输入年龄);scanf(%d, ps-data[pos].age);printf(请输入性别);scanf(%s, ps-data[pos].sex);printf(请输入电话);scanf(%s, ps-data[pos].tele);printf(请输入地址);scanf(%s, ps-data[pos].addr);printf(修改完成\n);}
}// 排序通讯录内容
// 比较结构体数组中两个元素的姓名成员
int compareStructType_name(const void* elem1, const void* elem2)
{// 姓名成员是字符串用strcmp比较return strcmp(((struct PeoInfo*)elem1)-name, ((struct PeoInfo*)elem2)-name);
}// 以名字排序所有联系人
void SortContact(struct Contact* ps)
{// 判断通讯录是否为空if (ps-size 0){printf(通讯录为空无法排序\n);return;}else{// 根据姓名成员对结构体数组升序排列qsort(ps-data, ps-size, sizeof(ps-data[0]), compareStructType_name);printf(以名字排序联系人成功\n);}
}// 销毁通讯录
void DestoryContact(Contact* ps)
{free(ps-data);ps-data NULL;ps-capacity 0;ps-size 0;printf(销毁成功\n);
} 六、程序运行效果