//动态开辟空间//存储文件//读取数据//排列
文章目录
目录
前言
对于初学者来说,如何用c语言来实现一个简易版的通讯录呢?下面将简单的介绍。
一、通讯录设计思路
1:首先要明白通讯录所存储的信息,如(姓名、性别、年龄、家庭住址、联系方式等)这里我们简单的写上五种,后续如果有需要可以继续添加。
2:创建好信息结构体后我们想接下来该怎么做?提供给用户选择的操作菜单,菜单的功能要有:
- 添加联系人信息。
- 删除联系人信息。
- 查找联系人信息。
- 修改通讯录信息
- 展示通讯录信息。
- 将通讯录信息进行排序(提供多种排序方法供用户选择)。
- 保存通讯录。
- 退出通讯录。
3:实现函数功能。
4.通讯录主函数展示
//主函数的架构
int main()
{
int input = 0;
Contact con;//创建一个通讯录。
InitContact(&con);//对通讯录进行初始化。
printf("请选择你要进行的操作。\n");
do
{
menu();//打印菜单。
scanf("%d", &input);
switch (input)
{
case add: AddContact(&con);//增加联系人信息的函数。
break;
case del:DelContact(&con);//删除联系人信息的函数。
break;
case search: SearchContact(&con);//查找联系人的函数。
break;
case my: ModifyContact(&con);//修改联系人信息的函数。
break;
case show: ShowContact(&con);//展示联系人信息的函数。
break;
case sort :SortContact(&con);//排列联系人信息的函数。
break;
case exit_: SaveContact(&con);//保存通讯录的内容。
DesplayInf(&con);//展示目前通讯录的信息。
DestoryContact(&con);//摧毁通讯录信息。
printf("退出。\n");
break;
case save: SaveContact(&con);//保存
break;
default :
printf("选择错误请重新选择。\n");
break;
}
} while (input);
return 0;
}
5:头文件的展示。
#ifndef CONTACT_H_INCLUDED
#define CONTACT_H_INCLUDED
#endif // CONTACT_H_INCLUDED
#include<stdio.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS l
#define Initial_capacity 3//初始容量。
#define Quantity_Increase 2//每次扩容增加的数量。
#define Max_name 20 //名字的长度。
#define Max_sex 5
#define Max_address 20
#define Max_numbers 20
typedef struct PeoInfo //建立一个人信息的结构体。
{
//姓名,性别,年龄,地址,电话号码。
char name[Max_name];
char sex[Max_sex];
int age;
char address[Max_address];
char numbers[Max_numbers];
}PeoInfo;
typedef struct Contact //结构体的结构体
{
PeoInfo* date;
int size;
int Capacity;
}Contact;
enum Option//枚举,增加数据的可读性。
{
exit_,add,del,search,my,show,sort,save//0 1 2 3 4 5 6 7
};
void SortContact(struct Contact *ps);//排序通讯录的内容。
void menu();//打印菜单。
void InitContact(Contact* pc);//动态通讯录初始化。
void CheckCapacity(Contact* pc);//检测通讯录目前容量。
void AddContact(Contact* pc);//增加联系人。
void DelContact(Contact* pc);//删除联系人。
void SearchContact(Contact* pc);//查找联系人。
void ModifyContact(Contact* pc);//修改联系人信息。
void Modify_menu();//修改选项。
void DestoryContact(Contact* pc);//摧毁通讯录。
void SaveContact(Contact* pc);//保存数据。
void LoadingContact(Contact* pc);//从txt文件读取数据。
void ShowContact( Contact* pc);//展示通讯录的信息。
void DesplayInf(Contact* pc);//通讯录目前情况;
//排序函数
void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void* e2));
void swap(char* e1, char* e2, int width);
int cmp_age( void* e1, void* e2);
int cmp_name(void* e1, void* e2);
int cmp_address(void* e1, void* e2);
int cmp_numbers(void* e1, void* e2);
int cmp_sex(void* e1, void* e2);
二、主要步骤
1.宏定义通讯录信息,便于修改
#define Initial_capacity 3//初始容量
#define Quantity_Increase 2//每次扩容增加的数量
#define Max_name 20 //名字的长度。
#define Max_sex 5 //性别长度
#define Max_address 20 //地址长度
#define Max_numbers 20 //电话长度
2.创建通讯录信息结构体
通讯录结构体代码如下:
typedef struct PeoInfo //建立一个人信息的结构体。
{
//姓名,性别,年龄,地址,电话号码。
char name[Max_name];
char sex[Max_sex];
int age;
char address[Max_address];
char numbers[Max_numbers];
}PeoInfo;
typedef struct Contact //结构体的结构体
{
PeoInfo* date; //创建一个PeoInfo*的指针,指向信息结构体。
int size; //记录目前通讯录所存储的数量。
int Capacity; //通讯录总容量。
}Contact;
3.菜单的简单设置
//定义一个菜单函数,在主函数打印。
void menu()
{
printf("*******************************\n");
printf("***1->添加 2->删除*********\n");
printf("***3->查找 4->修改*********\n");
printf("***5->展示 6->排序*********\n");
printf("***7->保存 0->退出*********\n");
}
4.初始化函数的实现
在主函数中我们已经进行了传参:InitContact(&con);//对通讯录进行初始化。
我们用Contact*类型的指针进行接收;
pc->date指向malloc函数动态开辟一段空间。
if (pc->date == NULL)
{
perror("InitContact");//打印错误消息。
return ;
}.判断是否开辟成功;没开辟成功会让他指向NULL.
让通讯录内容和容量都为0.
void InitContact(Contact* pc)//初始化通讯录。
{
pc->date = (PeoInfo*)malloc(Initial_capacity * sizeof(PeoInfo));//动态开辟一段空间
if (pc->date == NULL)
{
perror("InitContact");//打印错误消息。
return ;
}
pc->size = 0;//让通讯录的信息清零;
pc->Capacity = Initial_capacity;//容量
printf("通讯录初始化成功。\n");
LoadingContact(pc);//加载文件信息。
//这个函数后面会出现。
}
5.增加通讯录的信息
- 增加之前我们是不是要考虑通讯录的容量需不需要扩容的问题。因此我们增加一个函数进行判断是否需要进行扩容。
void CheckCapacity(Contact* pc)//检测通讯录容量是否满;
{
PeoInfo* _ = NULL;//创建一个人物信息的结构体指针。
if (pc->size == pc->Capacity)//目前存储人数和总人数进行比较;
{
_ = (PeoInfo*)realloc(pc->date, (pc->Capacity + Quantity_Increase) * sizeof(PeoInfo));
//realloc对原来malloc开辟的空间将进行扩容。
//
}
if (_ != NULL)
{
pc->date = _;//将新开辟的空间交给数据信息指针date
pc->Capacity += Quantity_Increase;//增加容量
printf("扩容成功。\n");
}
else
{
perror("AddContact");
return;
}
}
现在进行增加联系人的函数。
void AddContact(Contact* pc)//添加人物信息
{
CheckCapacity(pc);//检测容量问题
printf("请输入姓名->");
scanf("%s", (pc->date[pc->size].name));
printf("请输入年龄->");
scanf("%d", &(pc->date[pc->size].age));
printf("请输入地址->");
scanf("%s", (pc->date[pc->size].address));
printf("请输入性别->");
scanf("%s", (pc->date[pc->size].sex));
printf("请输入电话号码->");
scanf("%s", (pc->date[pc->size].numbers));
pc->size++;
printf("添加成功。\n");
}
6.精确查找联系人
后面的函数实现都要需要对联系人进行精确查找,因此我们写一个函数进行查找。
创立一个静态函数,只在这个项目中使用。
static int FindByName(Contact* pc, char name[])//创建一个静态函数用来查询人物姓名; { int i = 0; for (i = 0; i < pc->size; i++) { if (strcmp(pc->date[i].name ,name)==0)//比较通讯录中人的名字和你所要查找人的名字是否相同 return i;//返回这个人在数组中的位置。 } return -1;//表示错误,该通讯录中没有这个人。 }
7.删除联系人信息
void DelContact(Contact* pc)//动态删除。
{
char name[Max_name] = { 0 };
if (pc->size == 0)
{
printf("通讯录为空,不用删除。\n");
return;
}
printf("请输入你要删除联系人的姓名: ");
fscanf(stdin, "%s", name);
int pos=FindByName(pc, name);//用pos接受FindByName的返回值;
if (pos == -1)
{
printf("通讯录查无此人。\n");
return;
}
int i = 0;
for (i = pos; i < pc->size - 1; i++)//将要删除的元素用后一个元素覆盖,以此类推
{
pc->date[i] = pc->date[i + 1];//实现覆盖信息
}
pc->size--;//每进行一次将通讯录的目前存储信息减1
printf("删除成功。\n");
}
8.查找联系人
void SearchContact(Contact* pc)//查找联系人
{
char name[Max_name] = { 0 };
if (pc->size == 0)
{
printf("通讯录为空,无法查找。\n");
return;
}
printf("请输入你要查找联系人的姓名: ");
fscanf(stdin, "%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("通讯录查无此人。\n");
return;
}
else
{
printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20s\t\n", "姓名", "年龄", "地址", "性别", "电话号码");
printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20s\t\n",
pc->date[pos].name,
pc->date[pos].age,
pc->date[pos].address,
pc->date[pos].sex,
pc->date[pos].numbers);
}
}
9.修改联系人信息
精确修改人物信息
void ModifyContact(Contact* pc)//修改信息
{
char name[Max_name] = { 0 };
if (pc->size == 0)
{
fprintf(stdout, "通讯录为空。\n");
}
fprintf(stdout, "%s\n", "请输入要修改人的姓名。");
fscanf(stdin, "%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
fprintf(stdout, "该人没在通讯录中,无法进行修改。\n");
}
else
{
fprintf(stdout, "请选择你要修改的的内容。\n");
Modify_menu();
int input_number = 0;
fscanf(stdin, "%d", &input_number);
static enum Choice_Modify
{
exit, name, age, address, sex, contact_way
};
switch (input_number)
{
case name:
{
char name[Max_name] = { 0 };
fprintf(stdout, "你想修改为->");
fscanf(stdin, "%s", name);
strcpy(pc->date[pos].name, name);
}break;
case age:
{
int age = 0;
fprintf(stdout, "你想修改为->");
fscanf(stdin, "%d", &age);
pc->date[pos].age = age;
}break;
case address:
{
char address[Max_address] = { 0 };
fprintf(stdout, "你想修改为->");
fscanf(stdin, "%s", address);
strcpy(pc->date[pos].address, address);
}break;
case sex:
{
char sex[Max_sex] = { 0 };
fprintf(stdout, "你想修改为->");
fscanf(stdin, "%s", sex);
strcpy(pc->date[pos].sex, sex);
}break;
case contact_way:
{
char contact_way[Max_numbers] = { 0 };
fprintf(stdout, "你想修改为->");
fscanf(stdin, "%s", contact_way);
strcpy(pc->date[pos].numbers, contact_way);
}break;
case exit:
{
fprintf(stdout, "退出。\n");
}break;
default:
fprintf(stdout, "选择错误,请重新选择。\n");
break;
}
}
}
10.展示通讯录内容
void ShowContact( Contact* pc)//展示通讯录的内容;
{
if (pc->size == 0)
printf("通讯录为空。\n");
else
{
int i = 0;
printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20s\t\n", "姓名", "年龄", "地址", "性别", "电话号码");
for (i = 0; i < pc->size; i++)
printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20s\t\n",
pc->date[i].name,
pc->date[i].age,
pc->date[i].address,
pc->date[i].sex,
pc->date[i].numbers);
}
}
11排序函数
这个得自己慢慢体会
void SortContact( Contact* ps)//按名称对通讯的信息进行排序
{
fprintf(stdout, "请选择排列方式\n ");
printf("0->按年龄 "); printf("1->姓名 "); printf("2->按年龄 "); printf("3->按地址 "); printf("4->按电话 "); printf("5->按性别\n");
int N = 0;
fscanf(stdin, "%d", &N);
qsort(ps->date, ps->size, sizeof(PeoInfo), CMPMAIN[N]);
}
int cmp_age(void* e1, void* e2) { return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age; } int cmp_name(void* e1, void* e2) { return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } int cmp_address(void* e1, void* e2) { return strcmp(((PeoInfo*)e1)->address, ((PeoInfo*)e2)->address); } int cmp_numbers(void* e1, void* e2) { return strcmp(((PeoInfo*)e1)->numbers, ((PeoInfo*)e2)->numbers); } int cmp_sex(void* e1, void* e2) { return strcmp(((PeoInfo*)e1)->sex, ((PeoInfo*)e2)->sex); }
存放函数地址的数组;
int(*CMPMAIN[5])(void* e1, void* e2) ={&cmp_age,&cmp_name,&cmp_address,&cmp_address,&cmp_sex };
三 将数据写入文件中去
1.save函数
wb已二进制的形式进行写入。
void SaveContact(Contact* pc)//保存文件。
{
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("SaveContact");
return;
}
int i = 0;
for (i = 0; i < pc->size; i++)
{
fwrite(pc->date+i, sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf = NULL;
fprintf(stdout, "文件保存成功。\n");
}
2.read函数
这里我们创建了临时的人物结构体信息用来存储缓存空间。
void LoadingContact(Contact* pc)//加载文件
{
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("LoadingContact");
return;
}
PeoInfo tmp = { 0 };//建立一个临时的人物信息进行交换;
while (fread(&tmp, sizeof(PeoInfo), 1, pf))//详细参考fread函数的返回值
{
CheckCapacity(pc);
pc->date[pc->size] = tmp;
pc->size++;
}
fclose(pf);
pf = NULL;
fprintf(stdout, "数据加载成功。\n");
}
3.摧毁函数
void DestoryContact(Contact* pc)//摧毁通讯录。
{
free(pc->date);//释放通讯录开辟的内存空间;
pc->date = NULL;//指针指向空指针;
pc->size = 0;//数据归0;
pc->Capacity = 0;//容量归0;
}
四 运行结果展示
二进制文件
总结
- 首先得有一个很好的框架体系,先进行构思,之后进行写入。
- 排序函数需要进行深入的了解,研究。
- 为了增加代码的可读性,可以考虑用枚举法列举。
- 完整代码https://pan.baidu.com/s/1SjE66bzH0svayI53s9xP9g 提取码shdy