本文使用了malloc、realloc、calloc等和内存开辟有关的函数。
文章目录
前言
为了使用通讯录时,可以随时调整大小,所以使用动态开辟内存函数写通讯录,可增加联系人容量。
动态开辟函数,即在内存的栈区开辟空间,所以使用完毕后,需要释放内存空间。
一、通讯录运行图
二、头文件
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<assert.h> #include<stdlib.h> #define Max 10 enum function { quit,//退出 默认值为0 increase,//增加 默认值为1 delete,//删除 默认值为2 find,//查找 默认值为3 revise,//修改 默认值为4 show,//展示 默认值为5 empty,//清空 默认值为6 sort//排序 默认值为7 }; //创建人 typedef struct Person { char name[20];//姓名 size_t age;//年龄 char sex[8];//性别 char address[15];//地址 char phone[12];//电话 }person; //动态 //创建通讯录 typedef struct contact { person *per;//指向人这个结构体类型 size_t sz;//通讯录已有人员个数 size_t ContactMax;//通讯录当前最大容量 }contact; //初始化 void init_contact(contact* con); //增容 void tune(contact* con); //增加 void increase_contact(contact* con); //删除 void delete_contact(contact* con); //查找 //return -1(no) / address(yes) int find1(const contact** con); void find_contact(const contact* con); //修改 void revise_contact(contact* con); //展示 void show_contact(const contact* con); //排序通讯录 void sort_contact(contact* con); //销毁通讯录 void destroy_contact(contact* con); //保存文件 void save_contact(contact* con); //将文件信息保存到通讯录中 void load_contact(contact* con);
三、主界面
#include "contact.h" void menu1() { printf("**************************************\n"); printf("******* Simplified address book ******\n"); printf("******* 1> increase contact ******\n"); printf("******* 2> delete contact ******\n"); printf("******* 3> find contact ******\n"); printf("******* 4> revise contact ******\n"); printf("******* 5> Show all contacts ******\n"); printf("******* 6> Empty all contacts ******\n"); printf("******* 7> Sort by name ******\n"); printf("******* 0> Quit Contacts ******\n"); printf("**************************************\n"); } void test() { //创建通讯录 contact con; //初始化通讯录 init_contact(&con); //将文件信息保存到通讯录中 load_contact(&con); size_t choice = 0; do { menu1(); printf("请输入您的选择性:"); scanf("%u", &choice); switch (choice) { case increase: //增加 increase_contact(&con); break; case delete: //删除 delete_contact( &con ); break; case find: //查找 find_contact(&con); break; case revise: //修改 revise_contact(&con); break; case show: //展示 show_contact(&con); break; case empty: //清空 init_contact(&con); break; case sort: //排序 sort_contact(&con); break; case quit: //保存 save_contact(&con); //销毁 destroy_contact(&con); printf("Exiting Contacts...\n"); break; default: printf("You entered the wrong number, please re-enter it.\n"); break; } } while (choice); printf("Exited Contacts.\n"); } int main() { test(); return 0; }
四、通讯录功能函数
1.全代码
#include"contact.h" void menu2() { system("cls"); printf("1> name \t 2> age\n"); printf("3> sex \t 4> address\n"); printf("5> phone\n"); printf("Please select:"); } //动态 void init_contact(contact* con) { assert(con); // per sz ContactMax con->sz = 0; person* p = (person*)calloc(Max, sizeof(person)); if (p == NULL) { perror("init_contact::calloc"); return; } con->per = p; con->ContactMax = Max; } //将文件信息保存到通讯录中 void load_contact(contact* con) { //打开文件 FILE* p = fopen("contact.txt", "rb"); if (p == NULL) { perror("load_contact::fopen"); return; } person tmp = { 0 }; size_t i = 0; while(fread(&tmp, sizeof(person), 1, p)) { //考虑增容 tune(con); con->per[i] = tmp; con->sz++; i++; } //关闭文件 fclose(p); p = NULL; } void tune(contact* con) { if (con->sz == con->ContactMax) { person *p = (person *)realloc(con->per, (con->ContactMax + Max) * sizeof(person)); if (p == NULL) { perror("tune::realloc"); return; } con->per = p; con->ContactMax += Max; } } //动态开辟 void increase_contact(contact* con) { assert(con); //检测当前通讯录是否需要增容 tune(con); printf("name:"); scanf("%s", &(con->per[con->sz].name)); printf("age:"); scanf("%u", &(con->per[con->sz].age)); printf("sex:"); scanf("%s", &(con->per[con->sz].sex)); printf("address:"); scanf("%s", &(con->per[con->sz].address)); printf("phone:"); scanf("%s", &(con->per[con->sz].phone)); (con->sz)++; } void delete_contact(contact* con) { assert(con); int result = find1(&con); if (result != -1) { char true[5] = { 0 }; printf("Are you sure you want to delete %s's information?", &con->per[result].name); printf("yes/no:"); scanf("%s", true); if (!strcmp(true, "yes")) { if ( con->sz ) { memmove(con->per[result].name, con->per[(con->sz) - 1].name, sizeof(con->per[0])); } else { memset(con->per[result].name, 0, sizeof(con->per[0])); } (con->sz)--; printf("The deletion was successful, thanks for using!\n"); } else { printf("Delete failed, please try again!\n"); } } else { printf("Delete failed, please try again!\n"); } } int find1(const contact** con) { assert(*con); size_t i = 0; char sample1[20] = { 0 }; printf("请输入你要查找的名字:"); scanf("%s", sample1); while (i < (*con)->sz) { if (!strcmp(sample1, (*con)->per[i].name)) { return i; } else { i++; } } return -1; } void find_contact(const contact* con) { assert(con); int result = find1(&con); if (result != -1) { printf("Found, the basic information of the contact is:"); printf("name:%-20s\tage:%-4d\tsex:%-5s\taddress:%-30s\tphone:%-12s\n", con->per[result].name, con->per[result].age, con->per[result].sex, con->per[result].address, con->per[result].phone); } else { printf("Didn't find it!\n"); } } void revise_contact(contact* con) { assert(con); int result = find1(&con); if (result != -1) { char choice1[5] = { 0 }; printf("Are you sure you want to revise %s's information?", con->per[result].name); printf("yes/no:"); scanf("%s", choice1); if (!strcmp(choice1, "yes")) { menu2(); printf("Please enter the option you want to modify:"); int choice2 = -1; scanf("%d", &choice2); char sample1[30] = { 0 }; size_t sample2 = 0; printf("请输入:"); switch ( choice2 ) { case 1: case 3: case 4: case 5: scanf("%s", sample1); break; case 2: scanf("%d", sample2); break; } switch (choice2) { case 1: memmove(con->per[result].name, sample1, sizeof(sample1)); break; case 3: memmove(con->per[result].sex, sample1, sizeof(sample1)); break; case 4: memmove(con->per[result].address, sample1, sizeof(sample1)); break; case 5: memmove(con->per[result].phone, sample1, sizeof(sample1)); break; case 2: con->per[result].age = sample2; break; } printf("修改成功,感谢使用!!!\n"); } else { printf("修改失败,请再次尝试!!!\n"); } } else { printf("修改失败,请再次尝试!!!\n"); } } void show_contact(const contact* con) { assert(con); printf("\n\n================================================\n"); printf("================================================\n\n"); if ( con->sz ) { size_t i = 0; for (; i < (con->sz); i++) { printf("name:%-20s\tage:%-4d\tsex:%-8s\taddress:%-15s\tphone:%-12s\n", con->per[i].name, con->per[i].age, con->per[i].sex, con->per[i].address, con->per[i].phone); } printf("\n\n"); } else { printf("There is no contact information in the address book!\n"); } } int cmp_char(const void* str1, const void* str2) { return strcmp(((person*)str1)->name, ((person*)str2)->name); } void sort_contact(contact* con) { qsort(con -> per[0].name, con -> sz, sizeof(con -> per[0]), cmp_char); } void destroy_contact(contact* con) { free(con->per); con->per = NULL; con->ContactMax = 0; con->sz = 0; con = NULL; } void save_contact(contact* con) { //写文件 FILE* p = fopen("contact.txt", "wb"); if (p == NULL) { perror("save_contact::fopen"); return; } int i = 0; for (i = 0; i < con->sz; i++) { fwrite(con->per + i, sizeof(person), 1, p); } //关闭文件 fclose(p); p = NULL; printf("保存成功\n"); }
2.增加联系人
使用realloc()调整通讯录大小。
联系人信息图为:
void tune(contact* con) { if (con->sz == con->ContactMax) { person *p = (person *)realloc(con->per, (con->ContactMax + Max) * sizeof(person)); if (p == NULL) { perror("tune::realloc"); return; } con->per = p; con->ContactMax += Max; } } //动态开辟 void increase_contact(contact* con) { assert(con); //检测当前通讯录是否需要增容 tune(con); printf("name:"); scanf("%s", &(con->per[con->sz].name)); printf("age:"); scanf("%u", &(con->per[con->sz].age)); printf("sex:"); scanf("%s", &(con->per[con->sz].sex)); printf("address:"); scanf("%s", &(con->per[con->sz].address)); printf("phone:"); scanf("%s", &(con->per[con->sz].phone)); (con->sz)++; }
3.删除联系人
通过联系人的姓名来查找需要删除的联系人,找到之后确认删除该联系人。
例如:
int find1(const contact** con) { assert(*con); size_t i = 0; char sample1[20] = { 0 }; printf("请输入你要查找的名字:"); scanf("%s", sample1); while (i < (*con)->sz) { if (!strcmp(sample1, (*con)->per[i].name)) { return i; } else { i++; } } return -1; } void delete_contact(contact* con) { assert(con); int result = find1(&con); if (result != -1) { char true[5] = { 0 }; printf("Are you sure you want to delete %s's information?", &con->per[result].name); printf("yes/no:"); scanf("%s", true); if (!strcmp(true, "yes")) { if ( con->sz ) { memmove(con->per[result].name, con->per[(con->sz) - 1].name, sizeof(con->per[0])); } else { memset(con->per[result].name, 0, sizeof(con->per[0])); } (con->sz)--; printf("The deletion was successful, thanks for using!\n"); } else { printf("Delete failed, please try again!\n"); } } else { printf("Delete failed, please try again!\n"); } }
4.查找联系人
通过联系人姓名查找联系人。
int find1(const contact** con) { assert(*con); size_t i = 0; char sample1[20] = { 0 }; printf("请输入你要查找的名字:"); scanf("%s", sample1); while (i < (*con)->sz) { if (!strcmp(sample1, (*con)->per[i].name)) { return i; } else { i++; } } return -1; } void find_contact(const contact* con) { assert(con); int result = find1(&con); if (result != -1) { printf("Found, the basic information of the contact is:"); printf("name:%-20s\tage:%-4d\tsex:%-5s\taddress:%-30s\tphone:%-12s\n", con->per[result].name, con->per[result].age, con->per[result].sex, con->per[result].address, con->per[result].phone); } else { printf("Didn't find it!\n"); } }
5.修改联系人
先查找,再修改。
可以修改联系人的任一信息。
int find1(const contact** con) { assert(*con); size_t i = 0; char sample1[20] = { 0 }; printf("请输入你要查找的名字:"); scanf("%s", sample1); while (i < (*con)->sz) { if (!strcmp(sample1, (*con)->per[i].name)) { return i; } else { i++; } } return -1; } void revise_contact(contact* con) { assert(con); int result = find1(&con); if (result != -1) { char choice1[5] = { 0 }; printf("Are you sure you want to revise %s's information?", con->per[result].name); printf("yes/no:"); scanf("%s", choice1); if (!strcmp(choice1, "yes")) { menu2(); printf("Please enter the option you want to modify:"); int choice2 = -1; scanf("%d", &choice2); char sample1[30] = { 0 }; size_t sample2 = 0; printf("请输入:"); switch ( choice2 ) { case 1: case 3: case 4: case 5: scanf("%s", sample1); break; case 2: scanf("%d", sample2); break; } switch (choice2) { case 1: memmove(con->per[result].name, sample1, sizeof(sample1)); break; case 3: memmove(con->per[result].sex, sample1, sizeof(sample1)); break; case 4: memmove(con->per[result].address, sample1, sizeof(sample1)); break; case 5: memmove(con->per[result].phone, sample1, sizeof(sample1)); break; case 2: con->per[result].age = sample2; break; } printf("修改成功,感谢使用!!!\n"); } else { printf("修改失败,请再次尝试!!!\n"); } } else { printf("修改失败,请再次尝试!!!\n"); } }
6.展示联系人
展示所有联系人及其所有信息。
void show_contact(const contact* con) { assert(con); printf("\n\n================================================\n"); printf("================================================\n\n"); if ( con->sz ) { size_t i = 0; for (; i < (con->sz); i++) { printf("name:%-20s\tage:%-4d\tsex:%-8s\taddress:%-15s\tphone:%-12s\n", con->per[i].name, con->per[i].age, con->per[i].sex, con->per[i].address, con->per[i].phone); } printf("\n\n"); } else { printf("There is no contact information in the address book!\n"); } }
7.清空联系人
又名初始化通讯录。
重新向内存申请一片空间,存储联系人信息。
void init_contact(contact* con) { assert(con); // per sz ContactMax con->sz = 0; person* p = (person*)calloc(Max, sizeof(person)); if (p == NULL) { perror("init_contact::calloc"); return; } con->per = p; con->ContactMax = Max; }
8.退出通讯录
通过free()释放内存栈区的空间,避免内存泄露。
void destroy_contact(contact* con) { free(con->per); con->per = NULL; con->ContactMax = 0; con->sz = 0; con = NULL; }
总结
在使用完内存函数之后,一定一定要记得释放空间哦~
上述代码展示就是整个动态通讯录的全部啦,如果你有兴趣想要了解,可以通过C_Ccpp/C_study/contact at main · Yjun6/C_Ccpp (github.com)找到它们。