c语言通讯录——动态版本(带详细文字解释)

news/2024/10/17 10:31:58/

在这里插入图片描述

1.定义一个用于存储一个人的信息的结构体

typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char addr[ADDR_MAX];char tele[TELE_MAX];
}PeoInfo;

定义了一个名为 “PeoInfo” 的结构体(struct)类型,用于存储有关一个人的信息。
该结构体包含以下字段:

“name” - 一个字符数组,最多可以存储 NAME_MAX 个字符,表示这个人的姓名。
“age” - 一个整数,表示这个人的年龄。
“sex” - 一个字符数组,最多可以存储 SEX_MAX 个字符,表示这个人的性别。
“addr” - 一个字符数组,最多可以存储 ADDR_MAX 个字符,表示这个人的地址。
“tele” - 一个字符数组,最多可以存储 TELE_MAX 个字符,表示这个人的电话号码。

这个结构体可以用于存储一个人的信息,并且可以作为需要处理人员数据的函数的参数或返回类型。通常使用 typedef 创建结构体的别名,以允许更简洁的代码。

2.定义一个表示通讯录的结构体

typedef struct Contact
{PeoInfo* data;//指向存放人的信息的空间int sz;//当前已经放的信息的个数int capacity;//当前通讯录的最大容量
}Contact;

这段代码定义了一个名为 Contact 的结构体类型,用于表示通讯录。

该结构体包含三个成员变量:

PeoInfo* data:指向存放联系人信息的空间的指针,该空间由动态内存分配获得。
int sz:当前已经存储的联系人信息的个数。
int capacity:当前通讯录的最大容量,即可以存储的联系人信息的最大个数。
该结构体类型定义了通讯录的基本信息和存储方式,可以用于管理通讯录中的联系人信息。

3.创建主函数框架

int input;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{menu();printf("请输入:");scanf("%d", &input);switch (input){case 1://添加联系人AddContact(&con);break;case 2://删除联系人DelContact(&con);break;case 3://查找联系人SearchContact(&con);break;case 4://更改联系人ModifyContact(&con);break;case 5://显示联系人ShowContact(&con);break;case 6://排序联系人SortContactName(&con);break;case 0:DestroyContact(&con);printf("退出程序");break;default:printf("输入错误,重新输入\n");break;

这段代码包含了一个主函数的框架,用于管理一个通讯录的信息。主函数的具体实现可能包括以下步骤:

创建一个 Contact 类型的变量 con 作为通讯录。
调用 InitContact 函数初始化通讯录。
使用 do-while 循环显示菜单,要求用户输入数字进行操作。
根据用户输入的数字,调用相应的函数进行操作
如果用户输入1,执行函数AddContact,添加联系人
如果用户输入2,执行函数DelContact,删除联系人
如果用户输入3,执行函数SearchContact,查找联系人
如果用户输入4,执行函数ModifyContact,更改联系人
如果用户输入5,执行函数ShowContact,显示联系人
如果用户输入6,执行函数SortContactName,排序联系人
如果用户输入了 0,则退出程序。
输入用户输入“其他”,显示“输入错误,重新输入”。

4.初始化通讯录

//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}pc->data = ptr;pc->capacity = DEFAULT_SZ;
}

这段代码定义了一个名为 “InitContact” 的函数,用于初始化通讯录。

该函数接受一个指向 Contact 类型的指针作为参数,表示要初始化的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。

在函数体中,首先将通讯录中已经存储的联系人信息个数 sz 初始化为 0。然后使用动态内存分配函数 calloc 分配 DEFAULT_SZ 个 PeoInfo 类型结构体的空间,并将返回的指针赋值给通讯录的 data 成员变量。同时,将通讯录的最大容量 capacity 设置为 DEFAULT_SZ。

这个函数可以用于初始化通讯录,将通讯录中已经存储的联系人信息个数 sz 初始化为 0,并分配 DEFAULT_SZ 个 PeoInfo 类型结构体的空间。

5.创建显示通讯录菜单的函数

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");
}

这段代码定义了一个名为 “menu” 的函数,用于显示通讯录操作的菜单,其中包括以下选项:
1.add——添加联系人
2.del——删除联系人
3.search——查找联系人
4.modify ——更改联系人
5.show——显示联系人
6.sort——排序联系人
0.exit ——销毁通讯录,退出程序

6.创建检查通讯录扩容的函数

//检查通讯录是否需要扩容
void check_capacity(Contact* pc)
{if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");}
}

这段代码定义了一个名为 “check_capacity” 的函数,用于检查通讯录是否需要扩容。

该函数接受一个指向 Contact 类型的指针作为参数,表示要检查通讯录是否需要扩容的通讯录。在函数体中,函数检查通讯录中已经存储的联系人信息个数 sz 是否等于通讯录的最大容量 capacity。如果相等,则使用动态内存分配函数 realloc 重新分配内存,将新分配的内存大小设置为 (capacity + INC_SZ) * sizeof(PeoInfo),其中 INC_SZ 表示增加的容量大小。如果内存分配失败,则打印一条错误消息并返回函数。否则,将新分配的内存的指针赋值给通讯录的 data 成员变量,将通讯录的最大容量 capacity 更新为 (capacity + INC_SZ)。

这个函数可以用于检查通讯录是否需要扩容,并在需要扩容时增加容量。

7.创建添加联系人的函数

//添加联系人(动态版本)
void AddContact(Contact* pc)
{assert(pc);check_capacity(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].addr);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);pc->sz++;
}

这段代码定义了一个名为 “AddContact” 的函数,用于向通讯录中添加一个联系人信息。

该函数接受一个指向 Contact 类型的指针作为参数,表示要添加联系人信息的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。另外,check_capacity 函数用于检查通讯录是否需要扩容。

在函数体中,首先使用 check_capacity 函数检查通讯录是否需要扩容。如果通讯录已满,则打印一条消息并返回函数。否则,提示用户输入新添加联系人的信息,包括姓名、年龄、性别、地址和电话号码,并将这些信息存储在通讯录中下一个位置的 PeoInfo 类型结构体中。最后,将通讯录中已经存储的联系人信息个数 sz 加 1。

这个函数可以用于向通讯录中添加一个联系人信息,如果通讯录已满则返回函数。

8.创建删除联系人的函数

//删除指定联系人的信息
void DelContact(Contact* pc)
{char name[NAME_MAX] = { 0 };assert(pc);if (pc->sz == 0){printf("通信录为空,无法删除\n");return;}//删除printf("请输入要删除人的名字:\n");scanf("%s", name);int ret=FindByName(pc,name);if (-1==ret){printf("要删除的人不存在\n");return;}int i = 0;for (i = ret;i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}

这段代码定义了一个名为 “DelContact” 的函数,用于从通讯录中删除指定联系人的信息。

该函数接受一个指向 Contact 类型的指针作为参数,表示要删除联系人信息的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。另外,如果通讯录中没有联系人信息则打印一条消息并返回函数。

在函数体中,首先提示用户输入要删除的联系人姓名,并使用 FindByName 函数查找该联系人在通讯录中的位置。如果该联系人不存在,则打印一条消息并返回函数。否则,从该位置开始遍历通讯录中的所有联系人,并将每个联系人的信息向前移动一个位置,以覆盖要删除的联系人信息。最后,将通讯录中已经存储的联系人信息个数 sz 减 1,并打印一条删除成功的消息。

这个函数可以用于从通讯录中删除指定联系人的信息。

9.创建查找指定联系人的函数

//查找指定联系人
void SearchContact(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n","姓名", "年龄", "性别", "地址", "电话");printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].addr,pc->data[pos].tele);
}

这段代码定义了一个名为 “SearchContact” 的函数,用于在通讯录中查找指定联系人的信息。

该函数接受一个指向 const Contact 类型的指针作为参数,表示要查找联系人信息的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。

在函数体中,首先提示用户输入要查找的联系人姓名,并使用 FindByName 函数查找该联系人在通讯录中的位置。如果该联系人不存在,则打印一条消息并返回函数。否则,打印联系人的姓名、年龄、性别、地址和电话信息。

这个函数可以用于在通讯录中查找指定联系人的信息。

10.创建修改指定联系人信息的函数

//修改指定联系人的信息
void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要修改的人不存在\n");return;}printf("请输入名字:");scanf("%s", pc->data[pos].name);printf("请输入年龄:");scanf("%d", &(pc->data[pos].age));printf("请输入性别:");scanf("%s", pc->data[pos].sex);printf("请输入地址:");scanf("%s", pc->data[pos].addr);printf("请输入电话:");scanf("%s", pc->data[pos].tele);printf("修改完成\n");
}

这段代码定义了一个名为 “ModifyContact” 的函数,用于修改通讯录中指定联系人的信息。

该函数接受一个指向 Contact 类型的指针作为参数,表示要修改联系人信息的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。

在函数体中,首先提示用户输入要修改的联系人姓名,并使用 FindByName 函数查找该联系人在通讯录中的位置。如果该联系人不存在,则打印一条消息并返回函数。否则,提示用户输入新的联系人信息,包括姓名、年龄、性别、地址和电话号码,并将这些信息存储在通讯录中指定位置的 PeoInfo 类型结构体中。最后,打印一条修改完成的消息。

这个函数可以用于修改通讯录中指定联系人的信息。

11.创建显示通讯录信息的函数

//显示通讯录的信息
void ShowContact(const Contact* pc)
{assert(pc);printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n","姓名", "年龄", "性别", "地址", "电话");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].tele);}
}

这段代码定义了一个名为 “ShowContact” 的函数,用于显示通讯录中所有联系人的信息。

该函数接受一个指向 const Contact 类型的指针作为参数,表示要显示联系人信息的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。在函数体中,首先打印联系人信息的表头,包括姓名、年龄、性别、地址和电话。然后遍历通讯录中的所有联系人,逐个打印其姓名、年龄、性别、地址和电话信息。

这个函数可以用于显示通讯录中所有联系人的信息。

12.创建查找对应联系人位置的函数

int FindByName(Contact*pc,char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}

13.创建按名字排序联系人信息的函数

//按名字排序联系人的信息
void SortContactName(Contact* pc)
{assert(pc);PeoInfo temp;for (int i = 0; i < pc->sz - 1; i++){for (int j = 0; j < pc->sz - 1 - i; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序后为:\n");printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n","姓名", "年龄", "性别", "地址", "电话");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].tele);}
}

这段代码定义了一个名为 “SortContactName” 的函数,用于按照联系人姓名对通讯录中的联系人信息进行排序。

该函数接受一个指向 Contact 类型的指针作为参数,表示要排序联系人信息的通讯录。函数使用 assert 宏检查指针是否为空,以确保程序不会崩溃。在函数体中,使用冒泡排序算法对通讯录中的联系人信息进行排序,排序的关键字为联系人的姓名,使用 strcmp 函数进行比较。排序完成后,打印排序后的联系人信息表头和每个联系人的姓名、年龄、性别、地址和电话。

这个函数可以用于按照联系人姓名对通讯录中的联系人信息进行排序。

14.创建销毁通讯录的函数

//销毁通讯录
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;pc = NULL;
}

这段代码定义了一个名为 “DestroyContact” 的函数,用于销毁通讯录并释放内存。

该函数接受一个指向 Contact 类型的指针作为参数,表示要销毁的通讯录。在函数体中,首先使用 free 函数释放通讯录中的联系人信息所占用的内存。然后将通讯录的容量和大小都设置为 0,并将通讯录指针设置为 NULL。

这个函数可以用于销毁通讯录并释放内存,避免内存泄漏。

15.完整源代码

#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12
#define DEFAULT_SZ 3
#define INC_SZ 2
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char addr[ADDR_MAX];char tele[TELE_MAX];
}PeoInfo;
typedef struct Contact
{PeoInfo* data;//指向存放人的信息的空间int sz;//当前已经放的信息的个数int capacity;//当前通讯录的最大容量
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
//显示通讯录的信息
void ShowContact(const Contact* pc);
//查找指定联系人
void SearchContact(const Contact* pc);
//修改指定联系人的信息
void ModifyContact(Contact* pc);
//按名字排序联系人的信息
void SortContactName(Contact* pc);
//销毁通讯录
void DestroyContact(Contact* pc);//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}pc->data = ptr;pc->capacity = DEFAULT_SZ;
}//检查通讯录是否需要扩容
void check_capacity(Contact* pc)
{if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");}
}
//添加联系人(动态版本)
void AddContact(Contact* pc)
{assert(pc);check_capacity(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].addr);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);pc->sz++;
}//显示通讯录的信息
void ShowContact(const Contact* pc)
{assert(pc);printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n","姓名", "年龄", "性别", "地址", "电话");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].tele);}
}int FindByName(Contact*pc,char name[])
{int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}
//删除指定联系人的信息
void DelContact(Contact* pc)
{char name[NAME_MAX] = { 0 };assert(pc);if (pc->sz == 0){printf("通信录为空,无法删除\n");return;}//删除printf("请输入要删除人的名字:\n");scanf("%s", name);int ret=FindByName(pc,name);if (-1==ret){printf("要删除的人不存在\n");return;}int i = 0;for (i = ret;i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找指定联系人
void SearchContact(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n","姓名", "年龄", "性别", "地址", "电话");printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].addr,pc->data[pos].tele);
}//修改指定联系人的信息
void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要修改的人不存在\n");return;}printf("请输入名字:");scanf("%s", pc->data[pos].name);printf("请输入年龄:");scanf("%d", &(pc->data[pos].age));printf("请输入性别:");scanf("%s", pc->data[pos].sex);printf("请输入地址:");scanf("%s", pc->data[pos].addr);printf("请输入电话:");scanf("%s", pc->data[pos].tele);printf("修改完成\n");
}//按名字排序联系人的信息
void SortContactName(Contact* pc)
{assert(pc);PeoInfo temp;for (int i = 0; i < pc->sz - 1; i++){for (int j = 0; j < pc->sz - 1 - i; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序后为:\n");printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t\n","姓名", "年龄", "性别", "地址", "电话");int i = 0;for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].tele);}
}//销毁通讯录
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;pc = NULL;
}
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");
}
int main()
{int input;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{menu();printf("请输入:");scanf("%d", &input);switch (input){case 1://添加联系人AddContact(&con);break;case 2://删除联系人DelContact(&con);break;case 3://查找联系人SearchContact(&con);break;case 4://更改联系人ModifyContact(&con);break;case 5://显示联系人ShowContact(&con);break;case 6://排序联系人SortContactName(&con);break;case 0:DestroyContact(&con);printf("退出程序");break;default:printf("输入错误,重新输入\n");break;}} while (input);return 0;
}

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

相关文章

el-date-picker设置今天之前的日期不可选

<el-date-pickerv-model"editForm.offlineTime"type"date"placeholder"选择日期"style"width: 150px":picker-options"{disabledDate: (time) >time.getTime() <new Date(new Date().setHours(0, 0, 0, 0))}">&…

【python】web应用开发DRF框架

DRF 【python】web应用开发DRF框架 Django rest_framework, 简称 drf, 可以更方便的使用django写出符合 RESTful 规范的接口, (缩减编写api接口的代码) Django REST framework是一个建立在Django基础之上的Web应用开发框架(Django的一个app)&#xff0c;可以快速的开发REST A…

剑指 Offer 12: 矩阵中的路径

这道题看着简直是完全没思路&#xff0c;看了下发现是使用回溯的方法。 下面这里要注意&#xff0c;newi是旧的i加上新的偏移值&#xff01;newj同理&#xff0c;并不是加自己&#xff0c;别昏头&#xff01; s是String类型的变量&#xff0c;要写成size() 下面是正确的代码&a…

6.S081——设备中断与驱动部分(串口驱动与Console)——xv6源码完全解析系列(8)

0.briefly speaking 点此返回上一篇博客 上一篇博客中我们简单介绍了UART和PLIC的初始化过程&#xff0c;并迭代式的分析了console的读写操作&#xff0c;这篇博客接着上一篇的话题&#xff0c;研究一下一个字符是怎么一步步被显示到我们的屏幕上的&#xff0c;经过了哪些设备…

mac文件夹 文件重命名快捷键

选中文件&#xff0c;再 回车键&#xff01;&#xff01;&#xff01; 即可重命名

重命名快捷键

第一种是使用按键F2。选中文件&#xff0c;按下F2&#xff0c;文件就会处于重命名状态。 第二种是左键选中文件&#xff0c;在文件处于选中的状态下同样左键点击文件名部分&#xff0c;就可以使文件处于重命名的状态。当然&#xff0c;两次单击的时间间隔不要过短&#xff0c;过…