C语言实现个人通讯录(功能优化)-1
https://developer.aliyun.com/article/1536733
3.6 通讯录的排序:
这个功能实现就相对于前面的功能来说就有意思多了,来听我细细道来:
- 排序算法有八种,各种排序都是很不错的思路,比如被用于教学的冒泡排序,简单易懂,思想也贴切排序思想,所以常常用来教学初级;(具体八大排序算法,之后也会写成博客)
- 这里我就选用八大排序最舒服的快排,为什么选用快排呢,当然是快咯,哈哈,但快排也在这里有一些缺陷,如果数据很少,或者有很多都是顺序输入,快排就有一点点吃亏,没事儿----会优化!!!
- 先来介绍一下快排的思路吧,快排最开始是Hoare大佬提出来的思路如图:
这就是最开始Hoare大佬的快排思路:
- 1.先定一个key值,把比key小的放key的以边,把比key大的放一边,这样key就找到了正确位置,这就是一趟的思路,不断二分,就可以排序了。
- 2.不断二分,可递归,可不用递归,这里我就只是说一下递归方式。
void Swap( int* left,int* right) { int t = *left; *left = *right; *right = t; } void Hoare_QuickSort(int* a, int left, int right) { //当二分到key值的一边只有一个数,或者没有时,便递归结束 if (left >= right) return; int end = right, begin = left; int keyi = left;//这里表示的是key的下标索引 while (left < right) { //左边做key,右边先走,可以保证相遇位置比key更小 //right找小找到和找不到: //找到:left没有找到大,直到相遇 //没找到:直接和left相遇,直接找到keyi值 while (left<right&&a[right] >= a[keyi])//right找小停下 right--; while (left<right&&a[left] <= a[keyi])//left找大(保证相遇小于key) left++; Swap( &a[left],&a [right]);//交换两者,分配 } //最后相遇位置便是key的位置: Swap(&a[left], &a[keyi]); keyi = left; //key左边数组的初末索引:begin,keyi-1 Hoare_QuickSort(a, begin, keyi - 1); //key右边数组的初末索引:keyi+1,end Hoare_QuickSort(a, keyi + 1, end); }
当然Hoare大佬提出的版本肯定是存在一定缺陷的,需要优化,但是这种思想真的厉害!
这里直接给出时间复杂度:O(NlgN)~O(N*N)
- 缺陷: 1.当所需要排的数列是顺序或者逆序时,快排时间复杂度是最大N的平方,严重影响快排的速度。2.快排在对数据少,并且部分具有一定顺序的排序并不是很完美。3.Hoare大佬的快排思路难以理解,思路理解困难。
对于上述缺陷我这里就不过度介绍了,但的确有优化方式(我会在后续的八大排序中介绍)在通讯录排序中用较优秀的方式来实现(这里就是和库里排序函数实现相近了):
void Swap(PeoInfo* left, PeoInfo* right) { PeoInfo t = *left; *left = *right; *right = t; } int GerMidNumi(PeoInfo* a, int left, int right) { int mid = (right + left) / 2; if (strcmp(a[left].name, a[mid].name) > 0) { if (strcmp(a[mid].name, a[right].name) > 0) { return mid; } else if (strcmp(a[left].name, a[right].name) < 0) { return left; } else { return right; } } else { if (strcmp(a[left].name, a[right].name) > 0) { return left; } else if (strcmp(a[mid].name, a[right].name) < 0) { return mid; } else { return right; } } } void DP_QuickSort(PeoInfo* a, int left, int right) { int end = right, begin = left; if (left >= right) return; //小区间优化: if ((right - left + 1) > 10) { //方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显) int midi = GerMidNumi(a, left, right); if (midi != left) Swap(&a[left], &a[midi]); int prev = left; int cur = prev + 1; int keyi = left; while (cur <= right) { if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur) Swap(&a[cur], &a[prev]); cur++; } Swap(&a[prev], &a[keyi]); keyi = prev; DP_QuickSort(a, begin, keyi - 1); DP_QuickSort(a, keyi + 1, end); } else { InsertSort(a, right - left + 1); } } void InsertSort(PeoInfo* a, int n) { for (int i = 1; i < n; i++) { int end = i - 1; PeoInfo tmp = a[i]; // 将tmp插入到[0,end]区间中,保持有序 while (end >= 0) { if (strcmp(tmp.name, a[end].name) < 0) { a[end + 1] = a[end]; --end; } else { break; } } a[end + 1] = tmp; } }
运行效果:
这里很有趣,但在这个部分就不过度介绍了,在后续博客会有详细介绍哈!
3.7 文件导入和导出功能:
我们当前所写的代码都是在内存里写的,一旦关闭数据便会清除,所以需要把数据导入到本地磁盘中进行保存,这里就需要文件相关知识了。知识掌握了,就十分简单了!
- 本地导入内存:
void LondContact(Contact* pc) { FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb"); if (NULL == pf) { perror("LondContact error"); } else { int i = 0; PeoInfo tmp = { 0 }; while (fread(&tmp, sizeof(PeoInfo), 1, pf)) { CapacityContact(pc); pc->data[i] = tmp; pc->sz++; i++; } fclose(pf); pf = NULL; } }
- 内存存入本地:
void SaveContact(const Contact* pc) { FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb"); if (NULL == pf) { perror("SaveContact error"); } else { int i = 0; for (i = 0; i < pc->sz; i++) { fwrite((pc->data + i), sizeof(PeoInfo), 1, pf); } fclose(pf); pf = NULL; printf("保存成功\n"); } }
这就实现了通讯录的基本功能喽
3.8 分组打印:
这里我的通讯录是把分组定义为联系人的属性了的,所以只需要按照分组查找打印即可:
void SearchByClass(const Contact* ps) { { int i = 0; char class[CLASS_MAX]; int flag = 0; int k = 1; printf("请输入需要查找联系人的组别:"); scanf("%s", class); for (i = 0; i < ps->sz; i++) { if (strcmp(class, ps->data[i].class) == 0) { flag = 1; if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); } } if (flag) { return; } else { printf("无法找到该联系人信息\n"); } } }
3.9 隐蔽空间的实现:
- 这里的思路就是另外开辟本地文件,作为存储空间,但要注意的是,调用隐蔽空间时,切记先保存通讯录原本空间,并且退出(销毁)。再打开隐蔽空间的文件,就相当于实现一个小的通讯录,功能可照搬所以就不过多介绍。
- 只介绍一下进入空间时的一些优化吧,比如ShowHide()函数,看似只是加载界面,其实他还可以实现清除屏幕(调用windows自带的cls)原先信息,做到更舒服的访问。代码如下:
void ShowHide() { char arr1[] = "Welcome to Hide Room !!!"; char arr2[] = "########################"; int left = 0; int right = strlen(arr1) - 1; while (left <= right) { arr2[left] = arr1[left]; arr2[right] = arr1[right]; printf("%s\n", arr2); Sleep(1000); //清屏 system("cls"); left++; right--; } printf("%s\n", arr1); }
- 输入密码进入bool EncryptionContact()函数,这个函数还有太多可优化的地方:比如三次密码输入失败,24小时重试,这里用C语言就不方便了,可以用linux实现(后续会出相关博客)这里只能打印表示,还有就是密码的修改,这里我想的是还可以实现一个管理程序(哈哈,写博客想着想着就去实现了个,现在和大家分享!!!)
void Administrators(char* password) { char newpassword[20]; printf("请输入修改密码》:"); scanf("%s", newpassword); strcpy(password, newpassword); printf("修改成功\n"); } bool EncryptionContact() { int i = 0; char password[20] = { 0 }; char insure[20] = { "123456" }; //打开一个文件夹用来记录空间密码: FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb"); if (NULL == pf1) { perror("password1 error"); } else { char tmp[20] = { 0 }; fread(&tmp, 20, 1, pf1); strcpy(insure, tmp); fclose(pf1); pf1 = NULL; } //判断的主要函数: printf("请输入进入密码》:"); for (i = 0; i < 3; i++) { scanf("%s", password); if (0 == strcmp(password, insure)) { return true; } else if (0==strcmp(password,"管理员入口")) { //进入管理员系统进行密码修改 Administrators(insure); //存入密码文件中 FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb"); if (NULL == pf2) { perror("password2 error"); } else { fwrite(insure, 20, 1, pf2); fclose(pf2); pf2 = NULL; printf("保存成功\n"); } printf("请输入进入密码》:"); } else { printf("第%d次密码输入错误\n", i + 1); if (i < 2) printf("请重新输入》:"); } } //linux操作系统实现 printf("密码输入三次错误!请在24小时后重试\n"); return false; }
运行效果:
这里可以形成一个对比,就是代码没有封装可读性就很差,这里可以把写入和写出封装成函数。这里关于隐蔽空间其他功能大致相同就不过多介绍了。
Contact.c完整代码:
#include"Contact.h" void mune() { printf("*******************************************************\n"); printf("********1.SearchByName 2.SearchByAge ***************\n"); printf("********3.SearchBySex 4.SearchByAddr ************\n"); printf("********5.SearchByPhone 6.SearchByclass ************\n"); printf("******************* 0.exit **************************\n"); printf("*******************************************************\n"); } void mune1() { printf("**************************************\n"); printf("********1.ADD 2.DEL ***************\n"); printf("********3.SEARCH 4.MODIFY ************\n"); printf("********5.SHOW 6.SORT ************\n"); printf("********0.EXIT ************\n"); } void func(Contact* pc) { int input; mune1(); do { printf("请输入选项>:"); scanf("%d", &input); //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面 //若输入为0,则判断为FALSE,跳出循环,退出通讯录 switch (input) { case ADD: AddContact(pc); break; case DEL: DelContact(pc); break; case SEARCH: SearchContact(pc); break; case MODIFY: ModifyContact(pc); break; case SHOW: PrintContact(pc); break; case SORT: SortContact(pc); break; case EXIT: //保存到文件中 Hide_SaveContact(pc); //销毁通讯录空间 DestroyContact(pc); printf("退出通讯录\n"); break; default: printf("输入错误,请重新输入\n"); break; } } while (input); return; } void LondContact(Contact* pc) { FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb"); if (NULL == pf) { perror("LondContact error"); } else { int i = 0; PeoInfo tmp = { 0 }; while (fread(&tmp, sizeof(PeoInfo), 1, pf)) { CapacityContact(pc); pc->data[i] = tmp; pc->sz++; i++; } fclose(pf); pf = NULL; } } //主要用于函数的实现操作,功能实现处 //动态内存处理 void InitContact(Contact* pc) { assert(pc); pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX); if (pc->data == NULL) { perror("malloc error"); } pc->sz = 0; pc->capacity = INIT_MAX; //读取文件 LondContact(pc); } void CapacityContact(Contact* pc) { if (pc->sz == pc->capacity) { pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2); if (pc->data == NULL) { perror("realloc error"); } pc->capacity = pc->capacity * 2; printf("扩容成功\n"); } } void AddContact(Contact* pc) { assert(pc); //自动扩容 CapacityContact(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].address); printf("请输入联系人电话:"); scanf("%s", pc->data[pc->sz].phone); printf("请设置联系人组别:"); scanf("%s", pc->data[pc->sz].class); pc->sz++; return; } void DelContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录中无对象可操作!请先增加!"); mune1(); return; } int ret = SearchByName(pc); if (ret == -1) { printf("删除失败请重新操作!"); mune1(); return; } int i = ret; for (i = ret; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } printf("删除成功!\n"); //这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间 pc->sz--; mune1(); } int SearchContact(const Contact* pc) { assert(pc); //多种方式查找: mune(); int input; int ret = -1; do { //选项的输入 printf("请输入选项>:"); scanf("%d", &input); //若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面 //若输入为0,则判断为FALSE,跳出循环, switch (input) { case S_ByName: ret = SearchByName(pc); break; case S_ByAge: SearchByAge(pc); break; case S_BySex: SearchBySex(pc); break; case S_ByAddr: SearchByAddr(pc); break; case S_ByPhone: ret = SearchByPhone(pc); break; case S_ByClass: SearchByClass(pc); break; case EXIT: printf("查找完成,已经返回上一级\n"); mune1(); break; default: printf("该查找方式还待开发哦,请重新输入\n"); break; } } while (input); return ret; } int SearchByName(const Contact* ps) { int i = 0; char name[NAME_MAX]; int k = 1; printf("请输入需要的联系人名字:"); scanf("%s", name); for (i = 0; i < ps->sz; i++) { if (strcmp(name, ps->data[i].name) == 0) { //暂时不考虑重名 if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); return i; } } printf("无法找到该联系人信息\n"); return -1; } void SearchByAge(const Contact* ps) { int i = 0; int age; int flag = 0; int k = 1; printf("请输入需要查找联系人的年龄:"); scanf("%d", &age); for (i = 0; i < ps->sz; i++) { if (age == ps->data[i].age) { flag = 1; if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); } } if (flag) { return; } else { printf("无法找到该联系人信息\n"); } } void SearchBySex(const Contact* ps) { int i = 0; char sex[SEX_MAX]; int flag = 0; int k = 1; printf("请输入需要查找联系人的性别:"); scanf("%s", sex); for (i = 0; i < ps->sz; i++) { if (strcmp(sex, ps->data[i].sex) == 0) { flag = 1; if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); } } if (flag) { return; } else { printf("无法找到该联系人信息\n"); } } void SearchByAddr(const Contact* ps) { { int i = 0; char addr[ADDR_MAX]; int flag = 0; int k = 1; printf("请输入需要查找联系人的地址:"); scanf("%s", addr); for (i = 0; i < ps->sz; i++) { if (strcmp(addr, ps->data[i].address) == 0) { flag = 1; if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); } } if (flag) { return; } else { printf("无法找到该联系人信息\n"); } } } void SearchByClass(const Contact* ps) { { int i = 0; char class[CLASS_MAX]; int flag = 0; int k = 1; printf("请输入需要查找联系人的组别:"); scanf("%s", class); for (i = 0; i < ps->sz; i++) { if (strcmp(class, ps->data[i].class) == 0) { flag = 1; if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); } } if (flag) { return; } else { printf("无法找到该联系人信息\n"); } } } int SearchByPhone(const Contact* ps) { int i = 0; char phone[PHONE_MAX]; int k = 1; printf("请输入需要查找联系人电话号码:"); scanf("%s", phone); for (i = 0; i < ps->sz; i++) { if (strcmp(phone, ps->data[i].phone) == 0) { if (k == 1) { printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); k--; } printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].address, ps->data[i].phone, ps->data[i].class); return i; } } printf("无法找到该联系人信息\n"); return -1; } void ModifyContact(Contact* pc) { int ret = -1; int i; i = SearchByName(pc); if (i != ret) { printf("请输入修改的内容(部分):\n"); printf("请输入联系人名字:"); scanf("%s", pc->data[i].name); printf("请输入联系人年龄:"); scanf("%d", &(pc->data[i].age)); printf("请输入联系人性别:"); scanf("%s", pc->data[i].sex); printf("请输入联系人地址:"); scanf("%s", pc->data[i].address); printf("请输入联系人电话:"); scanf("%s", pc->data[i].phone); } } void PrintContact(const Contact* pc) { assert(pc); int i = 0; printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别"); for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].address, pc->data[i].phone, pc->data[i].class); } } void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->capacity = 0; pc->sz = 0; pc = NULL; } void SaveContact(const Contact* pc) { FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb"); if (NULL == pf) { perror("SaveContact error"); } else { int i = 0; for (i = 0; i < pc->sz; i++) { fwrite((pc->data + i), sizeof(PeoInfo), 1, pf); } fclose(pf); pf = NULL; printf("保存成功\n"); } } void SortContact(const Contact* pc) { assert(pc); DP_QuickSort(pc->data, 0, pc->sz - 1); printf("排序完成\n"); } void Swap(PeoInfo* left, PeoInfo* right) { PeoInfo t = *left; *left = *right; *right = t; } int GerMidNumi(PeoInfo* a, int left, int right) { int mid = (right + left) / 2; if (strcmp(a[left].name, a[mid].name) > 0) { if (strcmp(a[mid].name, a[right].name) > 0) { return mid; } else if (strcmp(a[left].name, a[right].name) < 0) { return left; } else { return right; } } else { if (strcmp(a[left].name, a[right].name) > 0) { return left; } else if (strcmp(a[mid].name, a[right].name) < 0) { return mid; } else { return right; } } } void DP_QuickSort(PeoInfo* a, int left, int right) { int end = right, begin = left; if (left >= right) return; //小区间优化: if ((right - left + 1) > 10) { //方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显) int midi = GerMidNumi(a, left, right); if (midi != left) Swap(&a[left], &a[midi]); int prev = left; int cur = prev + 1; int keyi = left; while (cur <= right) { if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur) Swap(&a[cur], &a[prev]); cur++; } Swap(&a[prev], &a[keyi]); keyi = prev; DP_QuickSort(a, begin, keyi - 1); DP_QuickSort(a, keyi + 1, end); } else { InsertSort(a, right - left + 1); } } void InsertSort(PeoInfo* a, int n) { for (int i = 1; i < n; i++) { int end = i - 1; PeoInfo tmp = a[i]; // 将tmp插入到[0,end]区间中,保持有序 while (end >= 0) { if (strcmp(tmp.name, a[end].name) < 0) { a[end + 1] = a[end]; --end; } else { break; } } a[end + 1] = tmp; } } void Hide_InitContact(Contact* pc) { assert(pc); pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX); if (pc->data == NULL) { perror("Hide_malloc error"); } pc->sz = 0; pc->capacity = INIT_MAX; //读取文件 Hide_LondContact(pc); } void Hide_LondContact(Contact* pc) { FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "rb"); if (NULL == pf) { perror("Hide_LondContact error"); } else { int i = 0; PeoInfo tmp = { 0 }; while (fread(&tmp, sizeof(PeoInfo), 1, pf)) { CapacityContact(pc); pc->data[i] = tmp; pc->sz++; i++; } fclose(pf); pf = NULL; } } void ShowHide() { char arr1[] = "Welcome to Hide Room !!!"; char arr2[] = "########################"; int left = 0; int right = strlen(arr1) - 1; while (left <= right) { arr2[left] = arr1[left]; arr2[right] = arr1[right]; printf("%s\n", arr2); Sleep(1000); system("cls"); left++; right--; } printf("%s\n", arr1); } void Administrators(char* password) { char newpassword[20]; printf("请输入修改密码》:"); scanf("%s", newpassword); strcpy(password, newpassword); printf("修改成功\n"); } bool EncryptionContact() { int i = 0; char password[20] = { 0 }; char insure[20] = { "123456" }; FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb"); if (NULL == pf1) { perror("password1 error"); } else { char tmp[20] = { 0 }; fread(&tmp, 20, 1, pf1); strcpy(insure, tmp); fclose(pf1); pf1 = NULL; } printf("请输入进入密码》:"); for (i = 0; i < 3; i++) { scanf("%s", password); if (0 == strcmp(password, insure)) { return true; } else if (0==strcmp(password,"管理员入口")) { Administrators(insure); FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb"); if (NULL == pf2) { perror("password2 error"); } else { fwrite(insure, 20, 1, pf2); fclose(pf2); pf2 = NULL; printf("保存成功\n"); } printf("请输入进入密码》:"); } else { printf("第%d次密码输入错误\n", i + 1); if (i < 2) printf("请重新输入》:"); } } //linux操作系统实现 printf("密码输入三次错误!请在24小时后重试\n"); return false; } void Hide_SaveContact(const Contact* pc) { FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "wb"); if (NULL == pf) { perror("Hide_SaveContact error"); } else { int i = 0; for (i = 0; i < pc->sz; i++) { fwrite((pc->data + i), sizeof(PeoInfo), 1, pf); } fclose(pf); pf = NULL; printf("保存成功\n"); } }
4.代码缺陷,以及优化:
4.1 内存泄漏:
内存泄漏是必须注意的,这里开始malloc了空间,如果没有释放则会影响项目的速度,举个例子:
- 这里是一个死循环,用来模拟长期在线的服务器,当出现内存泄漏问题会有什么后果:
- 开始运行代码:
可以注意vs2019所占得内存以及多了这么多,这些没用的空间,会影响项目整体性能,当然在这里只需要把黑匣子关掉,就马上恢复了,这是结束的时候自动释放了。如果未来我们从事的是24小时在线的服务器(比如各种app),出现这种内存泄漏可是及其危险的。所以我们需要手动释放。
void DestroyContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->capacity = 0; pc->sz = 0; pc = NULL; }
代码简单不累,相当实惠哈哈,所以这是要养成的习惯,在申请空间后一定记住手动free多余空间;
4.2 代码可读性维护:
- 有句流传江湖的话:程序员写完代码,只有自己和上帝认识!
- 在项目合作过程中的,代码可读性十分重要
- 比如函数命名、Switch语句的case选项可以枚举代替、以及增加必要注释。增加代码可读性,这里就举case这个例子
是不是还是有些区别的呢?
4.3 代码的可调式性:
我们往往可以发现我们在写类似“项目”的时候,发现代码一长,是真的难调,一调就是一天,所以我们就要用一些技巧:
- 1.善用const关键字,对于一些参数无需修改的函数,大胆加上这个关键字,比如通讯录的打印函数
- 2.会用assert()函数,使用函数我们通常成为暴力检查,这个函数会让你的调试找到方向,明白什么地方错了,便于调试。
- 3.perror()函数也是如此,若不清楚可以自行查询。
PS:好久没写博客咯,后续会抓紧的哈哈!美图献上(夹带私货),一起加油!