前言
通讯录对于C语言学习有着重大的意义,是一次非常综合性质的练习,囊括了C语言大多数知识,并且可以根据自身能力写出不同难度的通讯录。
代码解析
Contact.h
#pragma once
#include<stdio.h>
#include<stdlib.h>//动态内存的函数的头问题
#include<assert.h>//断言头文件
#include<string.h>//字符操作的头文件
#define Init 3 //设定一个通讯录容量的初始值
#define Bigger 2 //每次扩容扩大的值
#define MAX_NAME 20//名字的最大容量
#define MAX_SEX 10//性别的最大容量
#define MAX_TEL 15//电话的最大容量
#define MAX_ADDR 30//地址的最大容量
typedef struct PeoInfo //人的信息
{
char name[MAX_NAME];
char sex[MAX_SEX];
int age;
char tel[MAX_TEL];
char addr[MAX_ADDR];
}PeoInfo;
typedef struct Contact //通讯录整体的结构体
{
PeoInfo* data;
int capacity;//最大容量
int size;//实际存储的人数
}Contact;
void menu();//目录
void ContactInit(Contact* peo);//初始化
void ContactDestroy(Contact* peo);//销毁
void ContactAdd(Contact* con);//添加联系人信息
void check_capacity(Contact* con);//检查容量
void ContactDel(Contact* con);//删除指定联系人
void ContactSearch(Contact* con);//查找指定联系人信息
void ContactModify(Contact* con);//修改指定联系人信息
void ContactShow(Contact* con);//显示所有联系人信息
void ContactClear(Contact* con);//清空所有联系人
void ContactSort(Contact* con);//以名字排序所有联系人
void ContactSave(Contact* con);//保存信息
void ContactLoad(Contact* con);//导入信息
main.c
main.c中存储了整体的大框架,基本都是一些外部逻辑,以及函数调用
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
int main()
{
int input = 0;
Contact con;
ContactInit(&con);
do
{
menu();
printf("请进行你的选择>>>");
scanf("%d", &input);
switch (input)
{
case 1:
ContactAdd(&con);
break;
case 2:
ContactDel(&con);
break;
case 3:
ContactSearch(&con);
break;
case 4:
ContactModify(&con);
break;
case 5:
ContactShow(&con);
break;
case 6:
ContactClear(&con);
break;
case 7:
ContactSort(&con);
break;
case 8:
ContactSave(&con);
break;
case 0:
ContactSave(&con);
ContactDestroy(&con);
printf("通讯录已保存,退出成功!\n");
break;
default:
printf("输入错误,请重新输入>>>\n");
continue;
}
} while (input);
return 0;
}
Contact.c
这一部分是每个函数的具体实现,是通讯录的核心
#define _CRT_SECURE_NO_WARNINGS 1
#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");
}
void ContactLoad(Contact* con)//导入信息
{
assert(con);
FILE* pf = fopen("Contact.txt", "rb");
if (pf == NULL)//防止fopen失败
{
perror("ContactLoad::fopen");//perror是打印错误信息
return;//如果fopen失败,就直接退出函数
}
int i = 0;
PeoInfo tmp = { 0 };
while (fread(&tmp, sizeof(PeoInfo), 1, pf))//fread如果读不到数据,返回0
{
check_capacity(con);//每次读取数据后,都需要检查容量
con->data[i] = tmp;//检查容量后,将tmp赋给通讯录
con->size++;//赋给通讯录后,实际存储量就con->size++
i++;
}
fclose(pf);
pf = NULL;
}
void ContactInit(Contact* con)//初始化
{
assert(con);
con->capacity = Init;
con->size = 0;
PeoInfo* ptr = (PeoInfo*)calloc(Init, sizeof(PeoInfo));//动态开辟内存
if (ptr == NULL)
{
perror("InitContact::calloc");
return;
}
con->data = ptr;
//导入之前通讯录的信息
ContactLoad(con);
}
void check_capacity(Contact* con)//检查容量
{
assert(con);
/如果容量不足,增容,如果容量充足,什么也不做
if (con->capacity == con->size)
{
//增容,先用new作为指针变量接收,这是为了防止增容失败
PeoInfo* new = (PeoInfo*)realloc(con->data, (con->capacity + Bigger) * sizeof(PeoInfo));
if (new == NULL)
{
perror("check_capacity::realloc");
return;
}
con->data = new;
con->capacity += Bigger;//增容后,需要将new赋值,最大容量+Bigger
printf("增容成功\n");
}
}
void ContactAdd(Contact* con)//添加联系人信息
{
assert(con);
check_capacity(con);//添加之前需要检查容量
printf("请输入姓名>>");
scanf("%s", con->data[con->size].name);
printf("请输入性别>>");
scanf("%s", con->data[con->size].sex);
printf("请输入年龄>>");
scanf("%d", &(con->data[con->size].age));
printf("请输入电话>>");
scanf("%s", con->data[con->size].tel);
printf("请输入住址>>");
scanf("%s", con->data[con->size].addr);
con->size++;
printf("添加成功!\n");
}
void ContactDel(Contact* con)//删除指定联系人
{
assert(con);
if (!con->size)
{
printf("通讯录为空,无法删除\n");
return;
}
printf("请输入指定联系人的姓名>>");
char Delname[MAX_NAME] = { 0 };
scanf("%s", Delname);
int i = 0;
while(i < con->size)
{
if (!strcmp(Delname, con->data[i].name))
{
//删除信息
//这里可以用覆盖的方式con->data[i] = con->data[i + 1];把data[i+1]中的数据整体赋值给data[i]
memmove(&(con->data[i]), &(con->data[i + 1]), (con->size - i - 1) * sizeof(PeoInfo));
con->size--;
printf("删除成功!\n");
return;
}
else
{
//查找下一个人
i++;
}
}
printf("此人不存在,无法删除\n");
}
void ContactSearch(Contact* con)//查找指定联系人信息
{
assert(con);
printf("请输入查找指定联系人的姓名>>");
char Checkname[MAX_NAME] = {0};
scanf("%s", Checkname);
int i = 0;
while (i < con->size)
{
if (!strcmp(Checkname, con->data[i].name))
{
printf("姓名:%-10s 性别:%-4s 年龄:%-4d 电话:%-15s 住址:%-20s\n", con->data[i].name, con->data[i].sex, con->data[i].age, con->data[i].tel, con->data[i].addr);
return;
}
else
{
i++;
}
}
printf("查无此人!\n");
}
void ContactModify(Contact* con)//修改指定联系人信息
{
assert(con);
printf("您想要修改的联系人>>");
char Modifyname[MAX_NAME] = { 0 };
scanf("%s", Modifyname);
int i = 0;
while (i < con->size)
{
if (!strcmp(Modifyname, con->data[i].name))
{
printf("请输入新的姓名>>");
scanf("%s", con->data[i].name);
printf("请输入新的性别>>");
scanf("%s", con->data[i].sex);
printf("请输入新的年龄>>");
scanf("%d", &(con->data[i].age));
printf("请输入新的电话>>");
scanf("%s", con->data[i].tel);
printf("请输入新的住址>>");
scanf("%s", con->data[i].addr);
printf("修改成功\n");
return;
}
else
{
i++;
}
}
printf("查无此人!\n");
}
void ContactShow(Contact* con)//显示所有联系人信息
{
assert(con);
if (!con->size)
{
printf("通讯录内无联系人\n");
return;
}
int i = 0;
for (i = 0; i < con->size; i++)
{
printf("姓名:%-10s 性别:%-4s 年龄:%-4d 电话:%-15s 住址:%-20s\n", con->data[i].name, con->data[i].sex, con->data[i].age, con->data[i].tel, con->data[i].addr);
}
}
void ContactClear(Contact* con)//清空所有联系人
{
assert(con);
int i = 0;
for (i = 0; i < con->size; i++)
{
memset(con->data[i].name, 0, MAX_NAME);
memset(con->data[i].sex, 0, MAX_SEX);
memset(&(con->data[i].age), 0, 4);
memset(con->data[i].tel, 0, MAX_TEL);
memset(con->data[i].addr, 0, MAX_ADDR);
}
con->capacity = Init;
con->size = 0;
printf("清空成功!\n");
}
int Com_name(const void* e1, const void* e2)
{
assert(e1 && e2);
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void ContactSort(Contact* con)//以名字排序所有联系人
{
assert(con);
if (!con->size)
{
printf("通讯录内无联系人\n");
return;
}
qsort(con->data, con->size, sizeof(PeoInfo), Com_name);
printf("排序成功!\n");
}
void ContactSave(Contact* con)//保存信息
{
assert(con);
FILE* pf = fopen("Contact.txt", "wb");
if (NULL == pf)
{
perror("ContactSave::fopen");
return;
}
int i = 0;
for (i = 0; i < con->size; i++)
{
fwrite(&con->data[i], sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
printf("保存成功\n");
}
void ContactDestroy(Contact* peo)//销毁
{
assert(peo);
peo->capacity = 0;
peo->size = 0;
free(peo->data);
peo->data = NULL;
peo = NULL;
}
代码链接
这里附上我的Gitee上的完整代码,以供大家使用
https://gitee.com/grass-without-dream/learning_-c/tree/master/Contact