C语言静态动态两版本通讯录实战源码
目录
- 正片开始
- 静态版本
- 头文件( phonebook.h)
- 接口(test.c)
- 功能板块(phonebook.c)
- 1. 初始化:
- 2. 增添:
- 3.查找
- 4.删除
- 5.修改
- 6.排序
- 7.全览
- 静态版全部代码
- test.c(接口)
- phonebook.h(头文件)
- phonebook.c(功能)
- 动态版
- 动态初始化:
- 扩容函数
- 动态版全部代码
- test.c
- phonebook.h
正片开始 这里为了方便对照,我搬出整个程序的前后修改版本,并分别作为静态和动态版本,实际差距并不大,提供出来只供君参考
动机
为什么要写一个通讯录?
1.当然是一部分原因是看了b站上的资源自己比较感兴趣
2.其次就是在C语言实际应用上可以深化和巩固,其实都看得出来我中间断更了好久的数据结构与算法的博客,主要想法还是想把C语言从里到外不遗余力的杀穿,又走了一遍底层原理,不过我相信费时是值得的
3.在学习数据结构和算法这板块,需要C语言基础高度的掌握,所以这部分算对前边理论部分的一个实战项目,数据结构数据结构,无非就是数据的增删查改,这里我们提前热身一下也不错。
静态版本
头文件( phonebook.h)
我们这里依旧使用之前写扫雷的分装思想,将这个通讯录分为 头文件,接口,功能三个部分。
首先我们写出头文件,就是我们需要用到什么,给他整出来,我们简单粗暴给命名为“ phonebook.h ”,展示为下面三个部分:
#pragma once# define _CRT_SECURE_NO_WARNINGS # include#include#include#include
#define max 1000#define x 30#define y 30#define z 20typedef struct num{ char name[x]; int age; char sex[y]; char addr[y]; char num[z]; }num; typedef struct book{ num data[max]; int count; }book; enum conmenu{ 退出, 增添, 删减, 查找, 修改, 排序, 全览,};
void start(book* p); //初始化通讯录void add(book* p); //增添信息void show(const book* p); //展示信息void delete(book* p); //删除信息int search(book* p,char name[]); //库中搜寻要查找信息void find(book* p); //查找信息void modify(book* p); //修改信息void sort(book* p); //排序信息
整个一坨掰成三瓣就是为了方便理解,从上到下分别是菜单(展示必要),自定义类型变量(结构体,枚举类型),需要实现的功能函数名。
为什么结构体变量有两个
book结构体是我们整个通讯录的骨骼,包含count(成员数量)和data(成员数据),这里就相当于模拟了一个数组出来,更方便管理; num 结构体则是存放各个成员数据的细节成分(姓名,年龄,性别……)。
接口(test.c)
【C语言静态动态两版本通讯录实战源码】设置接口的目的就相当于是设置了一个大门,就是一个统揽全局的作用,我们把菜单,和功能模块在这里作展示作用,代码的实现我们会放在功能板块实现。
#include"phonebook.h"void menu(){ printf("-----------------------------\n"); printf("----欢迎使用通讯录----\n"); printf("-----------------------------\n"); printf("----- 1.增添|2.删减-----\n"); printf("----- 3.查找|4.修改-----\n"); printf("----- 5.排序|6.全览-----\n"); printf("-----0.退出-----\n"); printf("-----------------------------\n"); }int main(){ int input; book con; start(&con); do { menu(); printf("请选择:\n"); scanf("%d", &input); switch (input){case 增添:add(&con); break; case 删减:delete(&con); break; case 查找:find(&con); break; case 修改:modify(&con); break; case 排序:sort(&con); break; case 全览:show(&con); break; case 退出:break; default:printf("錯誤输入!\n"); return 0; } } while (input); return 0; }
抛开菜单部分,do-while 语句就是对应了菜单给出的功能遥控器,需要什么点什么。
为什么我们需要一个枚举类型,其原因就是为了对应上面菜单中的功能(枚举类型成员在未赋值情况下,第一个成员默认值为 0 ,其下依次递增,从而实现一一对应),我们作为设计者,主要是为了方便我们自己写代码,switch-case 语句中,case 条件我们一眼瞄过去如果是 1,2,3 的数字,我们在完善时就可能云里雾里,还要去查目录,就很麻烦,所以我们用枚举类型来避免这种小尴尬。
功能板块(phonebook.c)
我们在通讯录中需要达到的目的有基本的增删查改,以及作为称得上完美通讯录的全览,排序和退出,下面我们 一 一 实现:
1. 初始化:
void start(book* p){ assert(p); p->count = 0; memset(p->data, 0, sizeof(p->data)); }
初识化首先就要避免空指针和随机数,所以这里安排一手 assert 和 置0 就够了。
2. 增添:
void add(book* p){ assert(p); if (p->count == max) {printf("已满,请先进行删除\n"); return; } else {printf("请输入姓名:"); scanf("%s", p->data[p->count].name); printf("请输入年龄:"); scanf("%d", &(p->data[p->count].age)); printf("请输入性别(F\\M):"); scanf("%s", p->data[p->count].sex); printf("请输入地址:"); scanf("%s", p->data[p->count].addr); printf("请输入电话:"); scanf("%s", p->data[p->count].num); p->count++; printf("\n增添成功!\n"); }}
增添数据我们要对应好结构体中的类型,因为年龄比较特殊,它是 %d 的形式,输入类型不是字符串,所以我们要进行取地址操作
3.查找
void find(book* p){ assert(p); if (p->count == 0)printf("\n目录为空!\n"); else {char name[max] = { 0 }; printf("请输入查找对象:\n"); scanf("%s", &name); int i = search(p, name); if (i != -1){printf("联系人存在,在第%d位\n", i + 1); }else{printf("联系人不存在!\n"); } }}
注意在开始要判断一下现在通讯录状态是否为空,空就无法查找,注意要在库中寻找我们的查找对象,我们还要需要一个对信息进行筛选比对的函数来找出该对象,因此我们引入 search 函数:
int search(book* p, char name[]){ for (int i = 0; i < p->count; i++) {if (strcmp(name , p->data[i].name)==0){return i; }else{return -1; } }}
4.删除
void delete(book* p){ assert(p); if (p->count == 0) {printf("\n为空,无法删除!\n"); return; } else {printf("请输入删除对象:\n"); char name[max] = {0}; scanf("%s", &name); int f = search(p,name); if (f == -1){printf("该对象不存在!\n"); }else{for (int j = f; j < p->count-1; j++){p->data[j] = p->data[j + 1]; }p->count--; printf("\n删除成功!\n"); } }}
注意在开始要判断一下现在通讯录状态是否为空,空就无法删除;确定不为空再找到删除对象,我们所谓的删除本质就是用后面的数据进行依次覆盖,最后让数组大小 count -1 即可。
5.修改
void modify(book* p){ assert(p); if (p->count == 0) {printf("为空,无法删除!\n"); return; } else {printf("请输入对象姓名:\n"); char name[max] = { 0 }; scanf("%s", &name); int i = search(p,name); if(i!=-1){printf("该对象存在\n"); printf("请输入修改内容:\n"); printf("请输入姓名:\n"); scanf("%s", p->data[i].name); printf("请输入年龄:\n"); scanf("%d", &(p->data[p->count].age)); printf("请输入性别(F\M):\n"); scanf("%c", &(p->data[p->count].sex)); printf("请输入地址:\n"); scanf("%s", p->data[p->count].addr); printf("请输入电话:\n"); scanf("%s", p->data[p->count].num); printf("\n修改成功!\n"); }else{printf("该对象不存在!\n"); return 0; } }}
6.排序
int compare(const void* a, const void* b){ return strcmp(((book*)a)->data->name , ((book*)b)->data->name); }int compare2(const void* a, const void* b){ return strcmp(((book*)b)->data->name, ((book*)a)->data->name); }void sort(book* p){ printf("请选择:\n"); printf("-----------------------------\n"); printf("----- 1.顺序|2.逆序-----\n"); printf("-----------------------------\n"); int in; scanf("%d", &in); switch (in) { case 1:qsort(p->data, p->count, sizeof(p->data[0]), compare); case 2:qsort(p->data, p->count, sizeof(p->data[0]), compare2); } printf("\n 排序完成!\n"); }
排序我细分为了顺序和逆序两种,基本思想就是 qsort 函数一步到胃,不再赘述。
7.全览
void show(book* p){ assert(p); int i = 0; printf("%10s %5s %5s %10s %13s\n","姓名","年龄","性别","地址","电话"); for (i = 0; i < p->count; i++) {printf("%10s %5d %5s %10s %13s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].addr, p->data[i].num); }}
就是全部打印出来即可,注意信息之间的间隔调整,读者可自主更改其大小。
到这里我们所有功能就算实现完了,来康康实际效果如何(仅展示其中几个):
文章图片
文章图片
文章图片
静态版全部代码
为了方便读者查看与创作,我把三个部分的代码全部贴出来:
test.c(接口)
#include"phonebook.h"void menu(){ printf("-----------------------------\n"); printf("----欢迎使用通讯录----\n"); printf("-----------------------------\n"); printf("----- 1.增添|2.删减-----\n"); printf("----- 3.查找|4.修改-----\n"); printf("----- 5.排序|6.全览-----\n"); printf("-----0.退出-----\n"); printf("-----------------------------\n"); }int main(){ int input; book con; start(&con); do { menu(); printf("请选择:\n"); scanf("%d", &input); switch (input){case 增添:add(&con); break; case 删减:delete(&con); break; case 查找:find(&con); break; case 修改:fix(&con); break; case 排序:sort(&con); break; case 全览:show(&con); break; case 退出:break; default:printf("錯誤输入!\n"); return 0; } } while (input); return 0; }
phonebook.h(头文件)
#pragma once# define _CRT_SECURE_NO_WARNINGS # include#include#include#include#define max 1000#define x 30#define y 30#define z 20typedef struct num{ char name[x]; int age; char sex[y]; char addr[y]; char num[z]; }num; typedef struct book{ num data[max]; int count; int capacity; }book; enum conmenu{ 退出, 增添, 删减, 查找, 修改, 排序, 全览,}; void start(book* p); void add(book* p); void show(const book* p); void delete(book* p); int search(book* p,char name[]); void find(book* p); void fix(book* p); void sort(book* p);
phonebook.c(功能)
# define _CRT_SECURE_NO_WARNINGS #include"phonebook.h"void start(book* p){ assert(p); p->count = 0; memset(p->data, 0, sizeof(p->data)); }void add(book* p){ assert(p); if (p->count == max) {printf("已满,请先进行删除\n"); return; } else {printf("请输入姓名:"); scanf("%s", p->data[p->count].name); printf("请输入年龄:"); scanf("%d", &(p->data[p->count].age)); printf("请输入性别(F\\M):"); scanf("%s", p->data[p->count].sex); printf("请输入地址:"); scanf("%s", p->data[p->count].addr); printf("请输入电话:"); scanf("%s", p->data[p->count].num); p->count++; printf("\n增添成功!\n"); }}void show(book* p){ assert(p); int i = 0; printf("%10s %5s %5s %10s %13s\n","姓名","年龄","性别","地址","电话"); for (i = 0; i < p->count; i++) {printf("%10s %5d %5s %10s %13s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].addr, p->data[i].num); }}int search(book* p, char name[]){ for (int i = 0; i < p->count; i++) {if (strcmp(name , p->data[i].name)==0){return i; }else{return -1; } }}void delete(book* p){ assert(p); if (p->count == 0) {printf("\n为空,无法删除!\n"); return; } else {printf("请输入删除对象:\n"); char name[max] = {0}; scanf("%s", &name); int f = search(p,name); if (f == -1){printf("该对象不存在!\n"); }else{for (int j = f; j < p->count-1; j++){p->data[j] = p->data[j + 1]; }p->count--; printf("\n删除成功!\n"); } }}void find(book* p){ assert(p); if (p->count == 0)printf("\n目录为空!\n"); else {char name[max] = { 0 }; printf("请输入查找对象:\n"); scanf("%s", &name); int i = search(p, name); if (i != -1){printf("联系人存在,在第%d位\n", i + 1); }else{printf("联系人不存在!\n"); } }}void fix(book* p){ assert(p); if (p->count == 0) {printf("为空,无法删除!\n"); return; } else {printf("请输入对象姓名:\n"); char name[max] = { 0 }; scanf("%s", &name); int i = search(p,name); if(i!=-1){printf("该对象存在\n"); printf("请输入修改内容:\n"); printf("请输入姓名:\n"); scanf("%s", p->data[i].name); printf("请输入年龄:\n"); scanf("%d", &(p->data[p->count].age)); printf("请输入性别(F\M):\n"); scanf("%c", &(p->data[p->count].sex)); printf("请输入地址:\n"); scanf("%s", p->data[p->count].addr); printf("请输入电话:\n"); scanf("%s", p->data[p->count].num); printf("\n修改成功!\n"); }else{printf("该对象不存在!\n"); return 0; } }}int compare(const void* a, const void* b){ return strcmp(((book*)a)->data->name , ((book*)b)->data->name); }int compare2(const void* a, const void* b){ return strcmp(((book*)b)->data->name, ((book*)a)->data->name); }void sort(book* p){ printf("请选择:\n"); printf("-----------------------------\n"); printf("----- 1.顺序|2.逆序-----\n"); printf("-----------------------------\n"); int in; scanf("%d", &in); switch (in) { case 1:qsort(p->data, p->count, sizeof(p->data[0]), compare); case 2:qsort(p->data, p->count, sizeof(p->data[0]), compare2); } printf("\n 排序完成!\n"); }
动态版 动态版的区别就在于他的内存是活的,按需索取,要多少拿多少,绝不少给也绝不浪费空间,在空间上做出了质的优化,原理就是动态内存分配。
typedef struct book{ num data[max]; int count; int capacity; }book;
首先我们在 book 定义的结构体中引入一个 capacity 变量,意为容量,它就相当于一个空间使用的指标变量。
动态初始化:
void start(book* p){ assert(p); num* container = (num*)malloc(DEFAULT * sizeof(num)); if (container != NULL) {p->data = https://www.it610.com/article/container; p->count = 0; p->capacity = DEFAULT; } else { printf("%s\n", strerror(errno)); return; }}
重点是这里不再使用死板的数组,改用 malloc 函数先开辟一块默认大小,这个大小我们随意设置但避免浪费我们要尽量往小了设置。注意空指针,我们后面设置一个查看错误类型方便排空(注意引
扩容函数
则扩容的关键就在于我们的 capa_city 函数:
void capa_city(book* p){ num* container = (num*)realloc(p->data, sizeof(book) * (p->capacity + 2)); if (container != NULL) {p->data = https://www.it610.com/article/container; p->capacity += 2 ; printf("增容成功!\n"); } else {printf("%s\n", strerror(errno)); return; }}
我们为了体现空间利用的得当,我们每次扩容控制在 +2 数据空间即可。
接下来不用变动即可实现动态版本了,我直接上代码:
动态版全部代码
test.c
#include"phonebook.h"void menu(){ printf("-----------------------------\n"); printf("----欢迎使用通讯录----\n"); printf("-----------------------------\n"); printf("----- 1.增添|2.删减-----\n"); printf("----- 3.查找|4.修改-----\n"); printf("----- 5.排序|6.全览-----\n"); printf("-----0.退出-----\n"); printf("-----------------------------\n"); }int main(){ int input; book con; start(&con); do { menu(); printf("请选择:\n"); scanf("%d", &input); switch (input){case 增添:add(&con); break; case 删减:delete(&con); break; case 查找:find(&con); break; case 修改:fix(&con); break; case 排序:sort(&con); break; case 全览:show(&con); break; case 退出:break; default:printf("錯誤输入!\n"); return 0; } } while (input); return 0; }
phonebook.h
#pragma once# define _CRT_SECURE_NO_WARNINGS # include#include#include#include#include#define max 1000#define x 30#define DEFAULT 50#define z 20typedef struct num{ char name[x]; int age; char sex[x]; char addr[x]; char num[z]; }num; typedef struct book{ num* data; int count; int capacity; }book; enum conmenu{ 退出, 增添, 删减, 查找, 修改, 排序, 全览,}; void start(book* p); void add(book* p); void show(const book* p); void delete(book* p); int search(book* p,char name[]); void find(book* p); void fix(book* p); void sort(book* p); void capa_city(book* p);
phonebook.c
# define _CRT_SECURE_NO_WARNINGS #include"phonebook.h"void capa_city(book* p){ num* container = (num*)realloc(p->data, sizeof(book) * (p->capacity + 2)); if (container != NULL) {p->data = https://www.it610.com/article/container; p->capacity += 2 ; printf("增容成功!\n"); } else {printf("%s\n", strerror(errno)); return; }}void start(book* p){ assert(p); num* container = (num*)malloc(DEFAULT * sizeof(num)); if (container != NULL) {p->data = https://www.it610.com/article/container; p->count = 0; p->capacity = DEFAULT; } else { printf("%s\n", strerror(errno)); return; }}void add(book* p){ if (p->capacity == p->count) {capa_city(p); } assert(p); if (p->count == max) {printf("已满,请先进行删除\n"); return; } else {printf("请输入姓名:"); scanf("%s", p->data[p->count].name); printf("请输入年龄:"); scanf("%d", &(p->data[p->count].age)); printf("请输入性别(F\\M):"); scanf("%s", p->data[p->count].sex); printf("请输入地址:"); scanf("%s", p->data[p->count].addr); printf("请输入电话:"); scanf("%s", p->data[p->count].num); p->count++; printf("\n增添成功!\n"); }}void show(book* p){ assert(p); if (p->capacity == p->count) {capa_city(p); } int i = 0; printf("%10s %5s %5s %10s %13s\n","姓名","年龄","性别","地址","电话"); for (i = 0; i < p->count; i++) {printf("%10s %5d %5s %10s %13s\n", p->data[i].name, p->data[i].age, p->data[i].sex, p->data[i].addr, p->data[i].num); }}int search(book* p, char name[]){ for (int i = 0; i < p->count; i++) {if (strcmp(name , p->data[i].name)==0){return i; }else{return -1; } }}void delete(book* p){ assert(p); if (p->count == 0) {printf("\n为空,无法删除!\n"); return; } else {printf("请输入删除对象:\n"); char name[max] = {0}; scanf("%s", &name); int f = search(p,name); if (f == -1){printf("该对象不存在!\n"); }else{for (int j = f; j < p->count-1; j++){p->data[j] = p->data[j + 1]; }p->count--; printf("\n删除成功!\n"); } }}void find(book* p){ assert(p); if (p->count == 0)printf("\n目录为空!\n"); else {char name[max] = { 0 }; printf("请输入查找对象:\n"); scanf("%s", &name); int i = search(p, name); if (i != -1){printf("联系人存在,在第%d位\n", i + 1); }else{printf("联系人不存在!\n"); } }}void fix(book* p){ assert(p); if (p->count == 0) {printf("为空,无法删除!\n"); return; } else {printf("请输入对象姓名:\n"); char name[max] = { 0 }; scanf("%s", &name); int i = search(p,name); if(i!=-1){printf("该对象存在\n"); printf("请输入修改内容:\n"); printf("请输入姓名:\n"); scanf("%s", p->data[i].name); printf("请输入年龄:\n"); scanf("%d", &(p->data[p->count].age)); printf("请输入性别(F\M):\n"); scanf("%c", &(p->data[p->count].sex)); printf("请输入地址:\n"); scanf("%s", p->data[p->count].addr); printf("请输入电话:\n"); scanf("%s", p->data[p->count].num); printf("\n修改成功!\n"); }else{printf("该对象不存在!\n"); return 0; } }}int compare(const void* a, const void* b){ return strcmp(((book*)a)->data->name , ((book*)b)->data->name); }int compare2(const void* a, const void* b){ return strcmp(((book*)b)->data->name, ((book*)a)->data->name); }void sort(book* p){ printf("请选择:\n"); printf("-----------------------------\n"); printf("----- 1.顺序|2.逆序-----\n"); printf("-----------------------------\n"); int in; scanf("%d", &in); switch (in) { case 1:qsort(p->data, p->count, sizeof(p->data[0]), compare); case 2:qsort(p->data, p->count, sizeof(p->data[0]), compare2); } printf("\n 排序完成!\n"); }
今天就到这里吧,摸了家人们。
以上就是C语言静态动态两版本通讯录实战源码的详细内容,更多关于C语言静态动态通讯录的资料请关注脚本之家其它相关文章!
推荐阅读
- 【生信技能树】R语言练习题|【生信技能树】R语言练习题 - 中级
- 一起来学习C语言的字符串转换函数
- C语言字符函数中的isalnum()和iscntrl()你都知道吗
- C语言浮点函数中的modf和fmod详解
- C语言中的时间函数clock()和time()你都了解吗
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- C语言解方程的根和判断是否是闰年
- 动态组件与v-once指令
- C语言的版本比较
- 【C】题目|【C语言】题集 of ⑥