【C语言实战项目】通讯录(动态增容版)

一.动态增容版简介

上篇博客我们一起用C语言实现了一个固定大小的通讯录程序,这篇博客里我们将把他改造成可以动态增加大小的版本.

二.动态增容版逐步实现详解

1.创建通讯录

创建部分与静态版不同的是,因为我们在通讯录成员个数扩容的时候需要有一个变量来记录当前通讯录的最大容量,因此我们在结构体中多创建一个变量capacity用来记录当前通讯录的最大容量.

该部分代码如下:

//动态版本
#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];//电话11位,留一位给'\0';
}PeoInfo;//动态版本
typedef struct Contact
{PeoInfo* data;//存放人的信息int sz;//用来记录当前已经存放的信息的个数int capacity;//记录当前通讯录的最大容量
}Contact;

2. 初始化通讯录

初始化的部分我们可以将原来的初始化方法替换成使用calloc函数动态开辟通讯录的初始大小的同时进行初始化.

//初始化通讯录成员(动态版)
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;}

3.增加联系人

增加联系人的部分则需要先判断通讯录当前是否满了,如果是,则转入扩容函数,如果不是则正常进行增加联系人操作.

//增加联系人(动态版)
void AddContact(Contact* pc)
{assert(pc);//检查是不是满了check_capacity(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].addr);printf("请输入电话;>");scanf("%s", pc->data[pc->sz].tele);//每次录入完,sz自增pc->sz++;printf("联系人添加成功:>\n");
}

4.通讯录增容

通讯录的增容部分使用realloc函数来实现,当然要记得检查realloc返回的指针是否为空,如果为空则要输出内容提醒程序员出错的原因.

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

 

5.销毁通讯录

销毁通讯录是动态内存开辟非常重要的一步,如果使用动态内存开辟后忘记销毁,就会造成内存泄漏.因此在程序结束退出时我们一定要记得使用free将前面动态开辟的空间释放掉.

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

三.动态增容版代码整合

我们将程序运行的代码分为三个模块分开书写,完整代码如下:

contact.c

//contact.c通讯录的实现
#include"contact.h"//初始化通讯录成员(动态版)
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 DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;pc = NULL;
}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;}
}//增加联系人(动态版)
void AddContact(Contact* pc)
{assert(pc);//检查是不是满了check_capacity(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].addr);printf("请输入电话;>");scanf("%s", pc->data[pc->sz].tele);//每次录入完,sz自增pc->sz++;printf("联系人添加成功:>\n");
}//按人名查找联系人
int FindByName(const Contact* pc, char* name)
{assert(pc);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)
{assert(pc);char name[NAME_MAX] = { 0 };//防止通讯录删完了if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}//找到要删除的对象printf("请输入要删除的人的名字:>");scanf("%s", name);int del = FindByName(pc, name);if (-1 == del){printf("抱歉,没有找到您要删除的对象;<\n");return;}int i = 0;//删除for (i = del; 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 sea = FindByName(pc, name);if (-1 == sea){printf("抱歉,没有找到您要查找的对象;<\n");return;}//打印信息printf("________________________________________________________________________________________\n");printf("%-4s\t%-20s\t%-4s\t%-6s\t%-20s\t%-12s\n", "|序号", "|姓名", "|年龄", "|性别", "|地址", "|电话");printf("________________________________________________________________________________________\n");printf("|%-4d\t|%-20s\t|%-4d\t|%-6s\t|%-20s\t|%-12s\n", sea + 1,pc->data[sea].name,pc->data[sea].age,pc->data[sea].sex,pc->data[sea].addr,pc->data[sea].tele);printf("________________________________________________________________________________________\n");
}//修改联系人信息
void modifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };//找到要修改的对象printf("请输入要修改的人的名字:>");scanf("%s", name);int mod = FindByName(pc, name);if (-1 == mod){printf("抱歉,没有找到您要修改的对象;<\n");return;}printf("请输入修改后的联系人信息\n");printf("请输入名字;>");scanf("%s", pc->data[mod].name);printf("请输入年龄;>");scanf("%d", &(pc->data[mod].age));printf("请输入性别;>");scanf("%s", pc->data[mod].sex);printf("请输入地址;>");scanf("%s", pc->data[mod].addr);printf("请输入电话;>");scanf("%s", pc->data[mod].tele);printf("修改成功;>\n");printf("________________________________________________________________________________________\n");printf("%-4s\t%-20s\t%-4s\t%-6s\t%-20s\t%-12s\n", "|序号", "|姓名", "|年龄", "|性别", "|地址", "|电话");printf("________________________________________________________________________________________\n");printf("|%-4d\t|%-20s\t|%-4d\t|%-6s\t|%-20s\t|%-12s\n", mod + 1,pc->data[mod].name,pc->data[mod].age,pc->data[mod].sex,pc->data[mod].addr,pc->data[mod].tele);printf("________________________________________________________________________________________\n");
}//显示通讯录中的信息
void ShowContact(const Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法显示\n");return;}int i = 0;printf("________________________________________________________________________________________\n");printf("%-4s\t%-20s\t%-4s\t%-6s\t%-20s\t%-12s\n", "|序号", "|姓名", "|年龄", "|性别", "|地址", "|电话");for (i = 0; i < pc->sz; i++){printf("________________________________________________________________________________________\n");printf("|%-4d\t|%-20s\t|%-4d\t|%-6s\t|%-20s\t|%-12s\n", i + 1,pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].addr,pc->data[i].tele);}printf("________________________________________________________________________________________\n");}//清空联系人信息
void EmptyContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无需清空\n");return;}pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));printf("清空成功:>\n");}//comper按姓名排序
int comper_name(const void* a, const void* b)
{const PeoInfo* personA = (const PeoInfo*)a;const PeoInfo* personB = (const PeoInfo*)b;return strcmp(personA->name, personB->name);
}
//comper按年龄排序
int comper_age(const void* a, const void* b)
{const PeoInfo* personA = (const PeoInfo*)a;const PeoInfo* personB = (const PeoInfo*)b;return (personA->age - personB->age);
}
//comper按性别排序
int comper_sex(const void* a, const void* b)
{const PeoInfo* personA = (const PeoInfo*)a;const PeoInfo* personB = (const PeoInfo*)b;return strcmp(personA->sex, personB->sex);
}
//comper按住处排序
int comper_addr(const void* a, const void* b)
{const PeoInfo* personA = (const PeoInfo*)a;const PeoInfo* personB = (const PeoInfo*)b;return strcmp(personA->addr, personB->addr);
}//给联系人排序
void SortContact(Contact* pc)
{int cho = 0;if (pc->sz == 0){printf("通讯录为空,请先加入联系人\n");return;}printf("******************************\n");printf("********   1.按姓名  *********\n");printf("********   2.按年龄  *********\n");printf("********   3.按性别  *********\n");printf("********   4.按地址  *********\n");printf("******************************\n");printf("请选择您想使用的排序方式:>");scanf("%d", &cho);int (*compare_func)(const void*, const void*) = NULL;switch (cho){case 1:compare_func = comper_name;break;case 2:compare_func = comper_age;break;case 3:compare_func = comper_sex;break;case 4:compare_func = comper_addr;break;default:printf("排序选项无效:<\n");return;}// 使用qsort函数进行排序qsort(pc->data, pc->sz, sizeof(PeoInfo), compare_func);printf("排序成功:>\n");ShowContact(pc);
}

test.c

//test.c测试通讯录#include"contact.h"void menu()
{printf("******************************************\n");printf("******************************************\n");printf("*******      1.add      2.del      *******\n");printf("*******      3.search   4.modify   *******\n");printf("*******      5.show     6.empty    *******\n");printf("*******      7.sort     0.exit     *******\n");printf("******************************************\n");printf("******************************************\n");
}int main()
{int input = 0;//创建通讯录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:EmptyContact(&con);break;case 7:SortContact(&con);break;case 0:DestroyContact(&con);printf("退出程序:>\n");break;default:printf("输入非法,请重新输入!\n");break;}} while (input);return 0;
}

contact.h

#pragma once
//contact.h函数的声明
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>#define NAME_MAX 20
#define SEX_MAX 6
#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];//电话11位,留一位给'\0';
}PeoInfo;//动态版本
typedef struct Contact
{PeoInfo* data;//存放1000个人的信息int sz;//用来记录当前已经存放的信息的个数int capacity;//记录当前通讯录的最大容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);//销毁通讯录
void DestroyContact(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 EmptyContact(Contact* pc);//给联系人排序
void SortContact(Contact* pc);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/51943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

后端项目开发:整合全局异常处理

新建exception目录&#xff0c;用来进行自定义的全局异常处理。 &#xff08;1&#xff09;新建自定义的GlobalException基 类继承RuntimeException类&#xff0c;我们自定义的异常类全部需要继承GlobalException基类进行处理。 这里我们直接利用之前定义的错误码接口类。 /…

Qt 获取文件图标、类型 QFileIconProvider

Qt中获取系统图标、类型是通过QFileIconProvider来实现的&#xff0c;具体如下&#xff1a; 一、Qt获取系统文件图标1、获取文件夹图标QFileIconProvider icon_provider;QIcon icon icon_provider.icon(QFileIconProvider::Folder);2、获取指定文件图标QFileInfo file_info(n…

【JVM基础】JVM入门基础

目录 JVM的位置三种 JVMJVM体系结构类加载器双亲委派机制概念例子作用 沙箱安全机制组成沙箱的基本组件 NativeJNI&#xff1a;Java Native Interface&#xff08;本地方法接口&#xff09;Native Method Stack&#xff08;本地方法栈&#xff09; PC寄存器&#xff08;Program…

牛客python练习2

1 解析&#xff1a;赋值操作&#xff08;aXX,ba&#xff09;&#xff0c;a&#xff0c;b指向同一内存空间。当a,b是不可变类型时&#xff0c;a变&#xff0c;a 值变&#xff0c;id变&#xff0c;但是b不变&#xff0c;b的id也不变&#xff1b;当a,b是可变类型时&#xff0c;a变…

c语言函数指针和指针函数的区别,以及回调函数的使用。

函数指针是什么&#xff0c;函数指针本质也是指针&#xff0c;不过是指向函数的指针&#xff0c;存储的是函数的地址。 指针函数是什么,指针函数其实就是返回值是指针的函数&#xff0c;本质是函数。 函数指针是如何定义的呢&#xff0c;如下 void (*pfun)(int a,int b) 这…

解决redis-server.exe不是内部或外部命令

报错&#xff1a;redis-server.exe不是内部或外部命令 原因&#xff1a;未进入到redis的安装目录下 解决&#xff1a;先找到redis安装路径&#xff0c;复制之后&#xff0c;在终端中输入cd xxxxx(redis的安装路径)&#xff0c;进入安装目录之后再次输入redis-server.exe就成功了…

车联网技术介绍

上图是目前车联网架构图&#xff0c;基于“云-管-端”的车联网系统架构以支持车联网应用的实现&#xff0c; “云”是指 V2X 基础平台、高基于精度定位平台等基础能力&#xff0c;可实现车辆动态厘米级定位&#xff0c;这将满足现阶段以及未来车联网应用场景的定位精度需求。 “…

手机NFC功能是什么?

手机NFC功能是什么&#xff1f; 随着智能手机的不断发展和普及&#xff0c;NFC(近场通讯)功能已经成为了我们生活中不可或缺的一部分。NFC是一种无线通信技术&#xff0c;可以让手机和其他设备之间进行快速的数据交换和支付操作。那么&#xff0c;手机NFC功能是什么&#xff1…

自动化编排工具Terraform介绍(一)

Terraform是什么&#xff1f;: Terraform 是 HashiCorp 公司旗下的 Provision Infrastructure 产品, 是 AWS APN Technology Partner 与 AWS DevOps Competency Partner。Terraform 是一个 IT 基础架构自动化编排工具&#xff0c;它的口号是“Write, Plan, and Create …

vue 简单实验 自定义组件 局部注册

1.概要 2.代码 <html> </html> <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <body><div id"counter"><component-a></component-a></div> </body&g…

什么是算法评价指标

在我们建立一个学习算法时&#xff0c;或者说训练一个模型时&#xff0c;我们总是希望最大化某一个给定的评价指标&#xff08;比如说准确度Acc&#xff09;&#xff0c;但算法在学习过程中又会尝试优化某一个损失函数&#xff08;比如说均方差MSE或者交叉熵Cross-entropy&…

golang云原生项目☞redis配置

配置redis适用与golang云原生架构。包括redis与数据库一致性等重要内容 1、编写redis配置文件、使用viper读取 配置文件 db.yml redis:addr: 127.0.0.1port: 6379password: tiktokRedisdb: 0 # 数据库编号读取配置文件 var (config viper.Init("db")zapL…

【面试经典150题】删除有序数组中的重复项-JavaScript版

题目链接 思路1&#xff1a;使用set。 /*** param {number[]} nums* return {number}*/ var removeDuplicates function(nums) {const uniqueSetnew Set();for(let i0;i<nums.length;i){uniqueSet.add(nums[i]);}const uniqueArrayArray.from(uniqueSet);nums.length0;nu…

软考高级系统架构设计师系列论文七十九:论软件产品线技术

软考高级系统架构设计师系列论文七十九:论软件产品线技术 一、摘要二、正文三、总结一、摘要 根据公司软件系统开发的需要,我们在软件的开发过程中引入了软件产品线技术,成立了基于软件产品线的项目组。本人有幸参加了该项目,并在其中担任软件分析与设计、软件产品线核心资…

控制疫情蔓延嵌入式物联网能帮大忙

联合国所订定之永续发展目标之一&#xff0c;便是针对防治传染病的蔓延做好准备。在新型冠状病毒(COVID-19)流行期间&#xff0c;防疫已成为当前最重要目标&#xff0c;科技在对抗传染病方面扮演重要角色&#xff0c;而物联网(IoT)相关技术正是我们重要的防疫武器──降低成本、…

基于Java+SpringBoot+vue前后端分离华强北商城二手手机管理系统设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

win10系统rust串口通信实现

一、用cargo创建新工程 命令&#xff1a;cargo new comport use std::env; use std::{thread, time}; use serialport::{DataBits, StopBits, Parity, FlowControl}; use std::io::{self, Read, Write}; use std::time::Duration;fn main() -> io::Result<()> {let m…

Matlab分割彩色图像

彩色图像 彩色图像除有亮度信息外&#xff0c;还包含有颜色信息。以最常见的RGB&#xff08;红绿蓝&#xff09;彩色空间为例来简要说明彩色图像&#xff1a; 彩色图像可按照颜色的数目来划分。例如&#xff0c;256色图像和真彩色图像&#xff08;2的16次方&#xff1d;21677…

『C语言入门』C语言数组详解

文章目录 引言一、一维数组1.1 数组的创建1.2 数组的初始化1.3 一维数组的使用1.4 一维数组在内存中的存储1.4.1 内存中的数组布局1.4.2 计算元素的内存地址1.4.3 内存中的数组可视化1.4.4 指针与数组的关系1.5.5 内存布局的影响 二、二维数组2.1 二维数组的创建2.2 二维数组的…

JDK JRE JVM 三者之间的详解

JDK : Java Development Kit JRE: Java Runtime Environment JVM : JAVA Virtual Machine JDK : Java Development Kit JDK : Java Development Kit【 Java开发者工具】&#xff0c;可以从上图可以看出&#xff0c;JDK包含JRE&#xff1b;java自己的一些开发工具中&#…