当前位置: 首页 > news >正文

C语言练习:通讯录

简单版代码讲解:

这个版本不涉及文件操作以及动态内存分配,有助于理解代码。

文件管理

这里我们分了三个文件,.h 文件里给出类型声明和函数声明,contact.c 文件是具体的实现,test.c文件里是游戏的实现逻辑。

test.c

菜单

我们一共给出了 7 种操作,用 0~6 表示,分别有添加、删除、查找、修改、展示、排序以及退出。

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

main函数

我们先定义了一个“选择”的枚举类型,从0到6分别表示各种操作。

enum OPTION
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT//6
};

 这一段实现了菜单中想要实现的内容。

int main()
{int input = 0;Contact con;InitContact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT:Sort_By_Name(&con);break;case EXIT:printf("退出通讯录\n");break;default:printf("选择错误, 请重新选择\n");break;}} while (input);return 0;
}

contact.h

联系人信息

宏定义:

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12//telephone
#define MAX_ADDR 30//address

定义了一个结构体里包含人的姓名、年龄、性别、电话、地址。 

typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;

通讯录信息

定义了一个结构体表示整个通讯录,用数组存储,最大的存储MAX(100)个人的信息,sz表示已经使用的大小。

typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;

contact.c

初始化通讯录

void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}

增加联系人

void AddContact(Contact* pc)
{assert(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].tele));printf("请输入地址:>");scanf("%s", &(pc->data[pc->sz].addr));pc->sz++;printf("成功添加联系人\n");
}

显示所有联系人的信息

void ShowContact(const Contact* pc)
{assert(pc);printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");for (int i = 0; i < pc->sz; i++){printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}
  • - 表示左对齐。如果没有 -,会默认右对齐。
  • 10 表示这个字段的宽度是 10 个字符。如果字符串长度小于 10,会用空格填充。
  • \t 是一个水平制表符,通常用于在输出中添加水平间隔。

删除指定联系人

void DelContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME];printf("请输入要删除的人名字:>");scanf("%s", name);int i = 0;int del = 0;int flag = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){del = i;flag = 1;break;}}if (flag == 0){printf("没找到要删除的人\n");return;}//挪动覆盖删除for (i = del; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人\n");
}

查找指定联系人

FindByName函数的作用是用名字作为关键字查找,找到了返回这个联系人的下标。

int FindByName(const Contact* pc, char* name)
{for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}void SearchContact(const Contact* pc)
{assert(pc);char name[MAX_NAME];printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("没找到要查找的人\n");}else{printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}

修改指定联系人

void ModifyContact(Contact* pc)
{assert(pc);char name[MAX_NAME];printf("请输入要修改人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("没找到要修改的人\n");}else{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].tele);printf("请输入地址:>");scanf("%s", pc->data[pos].addr);printf("修改成功\n");}
}

排序联系人的信息(按照名字的大小)

qsort函数回调函数里有讲,请见->指针

int cmp_con_by_name(const void* p1, const void* p2)
{return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
}void Sort_By_Name(const Contact* pc)
{assert(pc);qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_con_by_name);ShowContact(pc);
}

复杂版代码讲解:

这个版本涉及文件操作以及动态内存分配。

test.c

main函数

相比于之前的只修改了EXIT,因为动态开辟的内存空间需要我们手动释放,否则会造成内存泄漏。并且在退出之前要把数据写入到文件中。

case EXIT:SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");

contact.h

通讯录信息

typedef struct Contact
{PeoInfo* data;//指向存放数据的空间int sz;//有效元素个数int capacity;//最大容量
}Contact;

contact.c

初始化通讯录

宏定义:

#define DEFAULT_SZ 3//默认容量
#define INC_SZ 2//每次增加的容量

一开始为pc指向的data开辟了3个PeoInfo大小的连续空间存放联系人的信息 ,我们使用了文件存储,所以在初始化的时候要把之前的加载进来。

void InitContact(Contact* pc)
{assert(pc);pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact");return;}pc->sz = 0;pc->capacity = DEFAULT_SZ;//文件中保存的信息加载到通讯录中LoadContact(pc);
}

加载通讯录

fread函数的讲解在这里->文件操作,记得要随时检查sz的大小,不够的话要增容。

void LoadContact(Contact* pc)
{FILE* pf = fopen("contact.dat", "rb");if (pf == NULL){perror("loadContact");return;}PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){if (0 == CheckCapacity(pc))return;pc->data[pc->sz] = tmp;pc->sz++;}fclose(pf);pf = NULL;
}

检查容量是否够用

容量够用或者容量不够用但是增容成功了都返回1,不成功返回0。

int CheckCapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ * sizeof(PeoInfo)));if (ptr == NULL){perror("CheckCapacity");return 0;}else{pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");return 1;}}return 1;
}

增加联系人

检查容量是否够用的事情就交给check函数去做。

if (0 == CheckCapacity(pc))
{return;
}

排序联系人的信息

int cmp_con_by_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}void Sort_By_Name(const Contact* pc)
{assert(pc);qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_con_by_name);ShowContact(pc);
}

销毁通讯录

void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}

保存通讯录信息到文件

void SaveContact(Contact* pc)
{FILE* pf = fopen("contact.dat", "wb");if (pf == NULL){perror("SaveContact");return;}for (int i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf); pf = NULL;
}

完整代码

contact.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12//telephone
#define MAX_ADDR 30//address#define DEFAULT_SZ 3//默认容量
#define INC_SZ 2//每次增加的容量enum OPTION
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT
};//类型声明
typedef struct PeoInfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
}PeoInfo;//动态版本
typedef struct Contact
{PeoInfo* data;//指向存放数据的空间int sz;//有效元素个数int capacity;//最大容量
}Contact;//函数声明
//初始化通讯录
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//显示所有联系人的信息
void ShowContact(const Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
//查找指定联系人
void SearchContact(const Contact* pc);
//修改指定联系人
void ModifyContact(Contact* pc);
//排序通讯录
void Sort_By_Name(const Contact* pc);
//销毁通讯录
void DestroyContact(Contact* pc);
//保存通讯录信息到文件
void SaveContact(Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"int CheckCapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ * sizeof(PeoInfo)));if (ptr == NULL){perror("CheckCapacity");return 0;}else{pc->data = ptr;pc->capacity += INC_SZ;printf("增容成功\n");return 1;}}return 1;
}void LoadContact(Contact* pc)
{FILE* pf = fopen("contact.dat", "rb");if (pf == NULL){perror("loadContact");return;}PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){if (0 == CheckCapacity(pc))return;pc->data[pc->sz] = tmp;pc->sz++;}fclose(pf);pf = NULL;
}void InitContact(Contact* pc)
{assert(pc);pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact");return;}pc->sz = 0;pc->capacity = DEFAULT_SZ;//文件中保存的信息加载到通讯录中LoadContact(pc);
}void AddContact(Contact* pc)
{assert(pc);if (0 == CheckCapacity(pc)){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].tele));printf("请输入地址:>");scanf("%s", &(pc->data[pc->sz].addr));pc->sz++;printf("成功添加联系人\n");
}void ShowContact(const Contact* pc)
{assert(pc);printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");for (int i = 0; i < pc->sz; i++){printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}int FindByName(const Contact* pc, char* name)
{for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}void DelContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}char name[MAX_NAME];printf("请输入要删除的人名字:>");scanf("%s", name);int del = FindByName(pc, name);if (del == -1){printf("要删除的人不存在\n");return;}//挪动覆盖删除for (int 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[MAX_NAME];printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("没找到要查找的人\n");}else{printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}
}void ModifyContact(Contact* pc)
{assert(pc);char name[MAX_NAME];printf("请输入要修改人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (pos == -1){printf("没找到要修改的人\n");}else{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].tele);printf("请输入地址:>");scanf("%s", pc->data[pos].addr);printf("修改成功\n");}
}int cmp_con_by_name(const void* p1, const void* p2)
{return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}void Sort_By_Name(const Contact* pc)
{assert(pc);qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_con_by_name);ShowContact(pc);
}void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}void SaveContact(Contact* pc)
{FILE* pf = fopen("contact.dat", "wb");if (pf == NULL){perror("SaveContact");return;}for (int i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf); pf = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"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 = 0;Contact con;InitContact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT:Sort_By_Name(&con);break;case EXIT:SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误, 请重新选择\n");break;}} while (input);return 0;
}

http://www.mrgr.cn/news/35301.html

相关文章:

  • 使用 Grafana api 查询 Datasource 数据
  • 纽约大学:指导LLM提出澄清性问题
  • 使用OpenCV(C++)通过鼠标点击操作获取图像的像素坐标和像素值
  • 如何快速定位并解决 Linux 系统性能瓶颈:终极全攻略
  • Qt 正则表达式提取文件中的 USB 设备 ID
  • Redhat7.9 安装 KingbaseES 金仓数据库 V9单机版(静默安装)
  • 电脑共享同屏的几种方法分享
  • windows桌面管理软件推荐:一键整理桌面!美化电脑桌面小助手!
  • 【MySQL】regexp_replace在MySQL以及regexp extract all在MySQL的用法
  • 如何修改音频的音量增益
  • 力扣 中等 92.反转链表 II
  • std::make_unique小结
  • 【Qt】背景介绍
  • 【代码笔记】
  • Java解决同构字符串问题
  • file zilla server安装以后,client连接,账号登录成功,但是读取目录失败的处理
  • 建筑工程系列专业职称评审条件大全
  • 误删系统引导如何恢复?如何创建系统引导?
  • C++: unordered系列关联式容器
  • MQ的简单梳理
  • 【动态规划】(五)动态规划——子序列问题
  • 前端报错401 【已解决】
  • 快速排序(plus)与单调栈道,力扣912.排序数组​​​​​​​力扣215.数组中的第k大个元素力扣17.14最小的k个数单调栈力扣.柱状图中最大的矩形
  • 美业门店怎么提升业绩?连锁美业门店管理系统收银系统拓客系统源码
  • 【5米光学卫星(资源一号02D/02E卫星)】
  • 鸿蒙OpenHarmony【小型系统内核(用户态启动)】子系统开发