c语言 通讯录系统 增删改查 排序 动态内存开辟及文件保存与读取
Posted 程序猿是小贺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言 通讯录系统 增删改查 排序 动态内存开辟及文件保存与读取相关的知识,希望对你有一定的参考价值。
c语言 通讯录系统 动态内存开辟及文件的保存与读取
一个最基本的通讯录系统,我们要实现的基本功能包括增删改查,并要在此基础上然后在对其进行各种扩充,比如排序,以及动态开辟内存进行存储,还有实现通讯录的文件保存和从文件中将已存的联系人加载并展示出来等等。
对其进行分析,我们需要以下三个不同文件
Contact.h 声明函数
#define _CRT_SECURE_NO_WARNINGS 1
#define DEFAULT_SZ 5 //初始动态开辟五个数据的空间
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_PHONE 16
#define MAX_ADDR 30
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
#include<errno.h>
enum OP_ENUM //避免魔鬼数字的出现
{
QUIT, //停止
ADD, //增加
DEL, //删除
SEEK, //查找
ALTER, //修改
SHOW, //显示
DELALL, //删除所有联系人
SORT, //排序
SAVE, //保存文件
};
typedef struct Info
{
char name[MAX_NAME];
char sex[MAX_SEX];
int age;
char phone[MAX_PHONE];
char addr[MAX_ADDR];
}Info;
//通讯录类型
typedef struct Contact
{
struct Info *data; //存放信息
int size; //记录当前已经有的元素个数
int capacity; //当前通讯录的最大容量
}Contact;
//声明函数
void InitContact(Contact *ps);//初始化通讯录
void addpeo(Contact *ps);//增加一个联系人信息
void showpeo(const Contact *ps);//打印所有联系人信息
//int findname(struct Contact *ps, char name[MAX_NAME]);//查找函数,根据姓名查找
void delpeo(Contact *ps);//调用查找函数删除指定联系人信息
void seekpeo(Contact *ps); //调用查找函数查找指定联系人信息
void alterpeo(Contact *ps); ///调用查找函数修改指定联系人信息
void sortpeo(Contact *ps); //排序通讯录联系人信息
void delall(Contact *ps); //删除所有联系人
void sortpeo(Contact *ps); //对联系人信息进行排序
void savepeo(Contact *ps); //保存数据到文件中
void LoadContact(Contact *ps); //加载文件中的信息至通讯录
Contact.c 实现函数的具体功能
这里要实现我们具体函数的功能,所以我们来定义一个Contact.c文件
Contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<assert.h>
#include"contact.h"
void LoadContact(Contact *ps);
// 1.查找联系人的位置, static 表示只能在本程序内部使用
static int findname(const Contact *ps, char name[MAX_NAME])
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (0 == strcmp(ps->data[i].name, name))
{
return i;
}
}
return -1;//找不到返回-1
}
void InitContact(Contact *ps)
{
ps->data = (struct Info*)malloc(DEFAULT_SZ * sizeof(Info));
if (ps->data == NULL)
{
return;
}
ps->size = 0;
ps->capacity = DEFAULT_SZ;
//把文件中已经存放的数据读取至通讯录中
LoadContact(ps);
}
void CheckCapacity(Contact *ps)
{
assert(ps != NULL);
if (ps->size == ps->capacity)
{
//增容
struct Info* ptr = realloc(ps->data, (ps->capacity + 5)*sizeof(Info));
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += 5;
printf("增容成功!\\n");
}
else
{
printf("增容失败!\\n");
}
}
}
void LoadContact(Contact *ps)
{
Info tmp = { 0 }; //定义一个临时的空间来存放文件中读取的数据
FILE* pfread = fopen("contact.txt", "rb");
if (pfread == NULL)
{
printf("%s\\n", strerror(errno));
return;
}
//读取文件至通讯录中
while ((fread(&tmp, sizeof(Info), 1, pfread)) == 1)
{
CheckCapacity(ps);
ps->data[ps->size] = tmp;
ps->size++;
}
fclose(pfread);
pfread = NULL;
}
void addpeo(Contact *ps)
{
assert(ps != NULL);
//检测当前通讯录容量
//容量已满就增容,反之则不用理会
CheckCapacity(ps);
//增加数据
printf("请输入联系人姓名:");
scanf("%s", ps->data[ps->size].name);
printf("请输入联系人性别:");
scanf("%s", ps->data[ps->size].sex);
printf("请输入联系人年龄:");
scanf("%d", &(ps->data[ps->size].age));
printf("请输入联系人电话:");
scanf("%s", ps->data[ps->size].phone);
printf("请输入联系人地址:");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("添加成功\\n");
}
void showpeo(const Contact *ps)
{
if (ps->size == 0)
{
printf("通讯录为空\\n");
}
else
{
//打印标题
printf("%-20s\\t%-5s\\t%-3s\\t%-16s\\t%-30s\\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < ps->size; i++)
{
//打印数据
printf("%-20s\\t%-5s\\t%-3d\\t%-16s\\t%-30s\\n",
ps->data[i].name,
ps->data[i].sex,
ps->data[i].age,
ps->data[i].phone,
ps->data[i].addr);
}
}
}
void delpeo(Contact *ps)
{
printf("请输入要删除的联系人姓名:");
char name[MAX_NAME];
scanf("%s", name);
//找到返回姓名所在元素下标, 找不到返回-1
int pos = findname(ps, name);
//2.删除
if (pos == -1)
{
printf("要删除的人不存在.\\n");
}
else
{
//删除数据
int j = 0;
for (j = pos; j <ps->size - 1; j++)
{
ps->data[j] = ps->data[j + 1];
}
ps->size--;
printf("删除成功\\n");
}
}
void seekpeo(Contact *ps)
{
char name[MAX_NAME];
printf("请输入要查找人的姓名:");
scanf("%s", name);
int pos = findname(ps, name);
if (pos == -1)
{
printf("查无此人.\\n");
}
else
{
printf("%-20s\\t%-5s\\t%-3s\\t%-16s\\t%-30s\\n", "姓名", "性别", "年龄", "电话", "地址");
//打印数据
printf("%-20s\\t%-5s\\t%-3d\\t%-16s\\t%-30s\\n",
ps->data[pos].name,
ps->data[pos].sex,
ps->data[pos].age,
ps->data[pos].phone,
ps->data[pos].addr);
}
}
void alterpeo(Contact *ps)
{
char name[MAX_NAME];
printf("请输入要修改人的姓名:");
scanf("%s", name);
int pos = findname(ps, name);
if (pos == -1)
{
printf("要修改的人不存在.\\n");
}
else
{
printf("请输入联系人姓名:");
scanf("%s", ps->data[pos].name);
printf("请输入联系人性别:");
scanf("%s", ps->data[pos].sex);
printf("请输入联系人年龄:");
scanf("%d", &(ps->data[pos].age));
printf("请输入联系人电话:");
scanf("%s", ps->data[pos].phone);
printf("请输入联系人地址:");
scanf("%s", ps->data[pos].addr);
printf("修改完成\\n");
}
}
void delall(Contact *ps)
{
free(ps->data); //删除所有人的的性质等同于释放data空间
ps->data = NULL;
}
void sortpeo(Contact *ps)
{
//此处使用冒泡排序,也可以使用快排
//这里也只是对其进行了简单排序,如果名字相同也可以对比年龄性别等进行二次排序,具体实现方案我也就不一一列举了
for (int i = 0; i < ps->size -1; i++)
{
for (int j = 0; j < ps->size - 1 - i; j++)
{
if (strcmp(ps->data[j].name, ps->data[j + 1].name) > 0)
{
Info temp = ps->data[j];
ps->data[j] = ps->data[j + 1];
ps->data[j + 1] = temp;
}
}
}
printf("%-20s\\t%-5s\\t%-3s\\t%-16s\\t%-30s\\n", "姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < ps->size; i++)
{
//打印数据
printf("%-20s\\t%-5s\\t%-3d\\t%-16s\\t%-30s\\n",
ps->data[i].name,
ps->data[i].sex,
ps->data[i].age,
ps->data[i].phone,
ps->data[i].addr);
}
}
void savepeo(Contact *ps)
{
FILE* pfwrite = fopen("contact.txt", "wb");
if (pfwrite == NULL)
{
printf("%s\\n", strerror(errno));
return;
}
//将通讯录中的数据写入文件
for (int i = 0; i < ps->size; i++)
{
fwrite(&(ps->data[i]), sizeof(Info), 1, pfwrite);
}
fclose(pfwrite);
pfwrite = NULL;
}
test.c 进行测试
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <Windows.h>
#include<assert.h>
#include"contact.h"
void menu() //菜单
{
printf("***************************\\n");
printf(" * 1.增加联系人 \\n");
printf(" * 2.删除指定联系人 \\n");
printf(" * 3.查询联系人 \\n");
printf(" * 4.修改联系人 \\n");
printf(" * 5.显示所有联系人 \\n");
printf(" * 6.清空所有联系人 \\n");
printf(" * 7.按名字进行排序 \\n");
printf(" * 8.保存信息到文件 \\n");
printf(" * 0.退出 \\n");
printf("***************************\\n");
}
//
//1.此处由于showpeo()函数的形参与其他函数参数类型有所不同,所以在此使用转移表会出现warning警告
//2.其内部函数类型为void,但此处定义为void*与其不兼容也会出现warning警告
//void *(*Contact_table[])(Contact *) = { NULL, addpeo, delpeo, seekpeo, alterpeo, showpeo, delall, sortpeo, savepeo };//转移表
//
int main()
{
int select = 1;
Contact con; //con就是通讯录,里面包含n(不确定要录入多少个,所以用n代替) 个元素的数据和size和capacity
//初始化通讯录,
InitContact(&con);//结构体传参,传址调用
while (select)
{
menu();
printf("请选择:");
scanf("%d", &select);
//void *tmp = Contact_table[select](&con);
switch (select)
{
case ADD:
addpeo(&con);
break;
case DEL:
delpeo(&con);
break;
case SEEK:
seekpeo(&con);
break;
case ALTER:
alterpeo(&con);
break;
case SHOW:
showpeo(&con);
break;
case DELALL:
delall(&con);//销毁通讯录——释放动态开辟的内存
break;
case SORT:
sortpeo(&con);
break;
case SAVE:
savepeo(&con);
break;
case QUIT:
savepeo(&con);//退出之前也可以先执行savepeo函数保存数据,避免忘记保存而出现差错
printf("谢谢使用!\\n");
break;
default:
printf("选择错误!\\n");
break;
}
}
system("pause");
return 0;
}
码完这么多字已经到了凌晨一点多了,期间我回顾了很多小的知识点,不过运用的程度连熟悉可能都算不上,最多可能也只是了解,可现在是并不代表以后也是,我还是会好好努力,加油,奥里给。
努力活成别人的信仰,共勉!
以上是关于c语言 通讯录系统 增删改查 排序 动态内存开辟及文件保存与读取的主要内容,如果未能解决你的问题,请参考以下文章