C语言/动态通讯录

news/2024/12/30 2:39:43/

本文使用了malloc、realloc、calloc等和内存开辟有关的函数。

 

 


文章目录

前言

二、头文件

三、主界面

四、通讯录功能函数

1.全代码

2.增加联系人

3.删除联系人

4.查找联系人

5.修改联系人

6.展示联系人

7.清空联系人

8.退出通讯录

总结


前言

为了使用通讯录时,可以随时调整大小,所以使用动态开辟内存函数写通讯录,可增加联系人容量。

动态开辟函数,即在内存的栈区开辟空间,所以使用完毕后,需要释放内存空间


一、通讯录运行图

二、头文件

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdlib.h>#define Max 10enum function
{quit,//退出  默认值为0increase,//增加  默认值为1delete,//删除  默认值为2find,//查找   默认值为3revise,//修改   默认值为4show,//展示   默认值为5empty,//清空   默认值为6sort//排序   默认值为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 ContactMaxcon->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 ContactMaxcon->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)找到它们。


http://www.ppmy.cn/news/32485.html

相关文章

哈佛与冯诺依曼结构

1. 下图是典型的冯诺依曼结构 2. CPU分为三部分&#xff1a;ALU运算单元&#xff0c;CU控制单元&#xff0c;寄存器组。 3. 分析51单片机为何能使用汇编进行编程 51指令集&#xff08;Instruction Set&#xff09;是单片机CPU能够执行的所有指令的集合。在编写51单片机程序时&a…

线程池的使用:如何写出高效的多线程程序?

目录1.线程池的使用2.编写高效的多线程程序Java提供了Executor框架来支持线程池的实现&#xff0c;通过Executor框架&#xff0c;可以快速地创建和管理线程池&#xff0c;从而更加方便地编写多线程程序。 1.线程池的使用 在使用线程池时&#xff0c;需要注意以下几点&#xff…

Spark SQL支持DataFrame操作的数据源

DataFrame提供统一接口加载和保存数据源中的数据&#xff0c;包括&#xff1a;结构化数据、Parquet文件、JSON文件、Hive表&#xff0c;以及通过JDBC连接外部数据源。一个DataFrame可以作为普通的RDD操作&#xff0c;也可以通过&#xff08;registerTempTable&#xff09;注册成…

【基础算法】单链表的OJ练习(5) # 环形链表 # 环形链表II # 对环形链表II的解法给出证明(面试常问到)

文章目录前言环形链表环形链表 II写在最后前言 本章的OJ练习相对于OJ练习(4)较为简单。不过&#xff0c;本章的OJ最重要的是要我们证明为何可以这么做。这也是面试中常出现的。 对于OJ练习(4)&#xff1a;-> 传送门 <-&#xff0c;分割链表以一种类似于归并的思想解得&a…

数据库基础语法

sql&#xff08;Structured Query Language 结构化查询语言&#xff09; SQL语法 use DataTableName; 命令用于选择数据库。set names utf8; 命令用于设置使用的字符集。SELECT * FROM Websites; 读取数据表的信息。上面的表包含五条记录&#xff08;每一条对应一个网站信息&…

vue3集成Mitt发布订阅库

先从git上扒来一段话介绍一下mitt这个库:Mitt是一个小巧的JavaScript发布-订阅库&#xff0c;用于在应用程序中实现事件监听和触发。它只有70行代码&#xff0c;并支持ES模块、CommonJS和UMD等多种模块化规范。使用Mitt&#xff0c;您可以轻松地将消息传递给订阅者&#xff0c;…

【华为OD机试真题 JAVA】TLV编码问题

标题:TLV编码问题 | 时间限制:1秒 | 内存限制:262144K | 语言限制:不限 TLV编码是按TagLengthValue格式进行编码的,一段码流中的信元用tag标识,tag在码流中唯一不重复,length表示信元value的长度,value表示信元的值,码流以某信元的tag开头,tag固定占一个字节,lengt…

C/C++每日一练(20230314)

目录 1. 移动数组中的元素 2. 搜索二维矩阵 3. 三角形最小路径和 &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang 每日一练 专栏 C/C 每日一练 ​专栏 Python 每日一练 专栏 Java 每日一练 专栏 1. 移动数组中的元素 将一维数组中的元素循环左移 k 个位置 输入…