前言
我们用手机打电话,发信息时候总是会用到通讯录那么通讯录是干什么的呢?
显而易见,用于存储一个人的信息(姓名,电话,地址)等等.我们可以进行查询,删除,增加等相关信息.
而博主写这篇博客的目的就是 把我们最近学习的C语言知识用来制作简易版本的 通讯录.
①明确项目目的
此前看过博主的博客小伙伴可能知道博主的博客风格.博主写任何一个小项目之前都是先去梳理 目的,然后去搭建逻辑结构,再去分别实现模块化.此次仍然不例外.
目的:
- 可以存储个人信息(姓名,性别,年龄,电话,地址), 说明少不了结构体.
- 存储人数不限. (说明需要动态内存)
- 有提醒菜单提示相关命令.
- 命令有(0退出,1添加信息,2删除信息,3查询信息,4修改信息,5显示所有信息,6排序信息)
②项目结构搭建
明确目的后就可以搭建逻辑结构了,我们知道人的信息要用结构体存.并且按相关命令就进入相关模块,那么
一定少不了do-while
和switch-case
#include <stdio.h>
struct information //个人信息表
{
char name[20];//姓名
char sex[10]; //性别
int age;//年龄
char tele[15];//电话
char address[40];//地址
};
struct contact //通讯录
{
struct information* info; //因为不限人数量,所以开辟动态空间,存储多个信息表.
long long size; //真实信息人数数量
long long capacity; //通讯录容量
};
int main()
{
struct contact con = {}; //创建通讯录
Initcon(&con); //初始化通讯录
int input = 0;
printf("请输入你想要操作的命令:\n");
do
{
remind(); //菜单提示
scanf("%d", &input);
switch (input)
{
case Exit:
save_con(&con); //把通讯录保存到文件夹
free_con(&con); //一定要记得释放动态空间.
printf("已经成功退出系统!\n");
break;
case add:
add_con(&con);
printf("信息存储完毕!\n等待您的下一步命令:\n");
break;
case del:
del_con(&con);
printf("该人信息删除完毕!\n等待您的下一步命令:\n");
break;
case search:
search_con(&con);
printf("查找成功,等待您的下一步命令:\n");
break;
case modify:
modify_con(&con);
printf("修改完毕\n等待您的下一步命令:\n");
break;
case show:
printf("所有人的详细信息如下,请查看:\n");
show_con(&con);
printf("展示完毕,等待您的下一步命令:\n");
break;
case sort:
sort_con(&con);
printf("排序成功\n等待您的下一步命令:\n");
break;
default:
printf("你的命令不在菜单栏中,请重新选择:\n");
break;
}
} while (input);
return 0;
}
在这,逻辑结构就已经搭建好了,但是能不能再修改下呢?比如
switch-case
语句中的0-6
,我们可不可以用更加表明意思的句子代替?怎么弄呢?这就是
枚举
的好处
修改的内容如下:
#include <stdio.h>
struct information //个人信息表
{
char name[20];//姓名
char sex[10]; //性别
int age;//年龄
char tele[15];//电话
char address[40];//地址
};
struct contact //通讯录
{
struct information* info; //因为不限人数量,所以开辟动态空间,存储多个信息表.
long long size; //真实信息人数数量
long long capacity; //通讯录容量
};
enum command //增加了枚举常量
{
Exit,
add,
del,
search,
modify,
show,
sort
};
int main()
{
struct contact con = {}; //创建通讯录
Initcon(&con); //初始化通讯录
int input = 0;
printf("请输入你想要操作的命令:\n");
do
{
remind(); //菜单提示
scanf("%d",&input);
switch(input)
{
case Exit:
save_con(&con); //把通讯录保存到文件夹
free_con(&con); //一定要记得释放动态空间.
printf("已经成功退出系统!\n");
break;
case add:
add_con(&con);
printf("信息存储完毕!\n等待您的下一步命令:\n");
break;
case del:
del_con(&con);
printf("该人信息删除完毕!\n等待您的下一步命令:\n");
break;
case search:
search_con(&con);
printf("查找成功,等待您的下一步命令:\n");
break;
case modify:
modify_con(&con);
printf("修改完毕\n等待您的下一步命令:\n");
break;
case show:
printf("所有人的详细信息如下,请查看:\n");
show_con(&con);
printf("展示完毕,等待您的下一步命令:\n");
break;
case sort:
sort_con(&con);
printf("排序成功\n等待您的下一步命令:\n");
break;
default:
printf("你的命令不在菜单栏中,请重新选择:\n");
break;
}
}while(input);
return 0;
}
③各模块的具体实现
1.Initcon初始化通讯录实现
在搭建结构时候,我们只创建了通讯录,但是通讯录实际是没有任何东西的.我们需要给它赋上初值.
#include <stdlib.h>
void Initcon(struct contact* con)
{
con->info = (struct information*)malloc(sizeof(struct information) * 4); //开辟个人信息空间
if (con->info == NULL)
{
printf("系统容量不足,无法增加通讯录容量\n");
return;
}
con->size = 0; //当前有0个存储信息
con->capacity = 4; //当前通讯录剩余4个存储空间
}
2.remind菜单制作
菜单制作其实就是把相关的信息打印出来就行.
void remind()
{
printf(
"******************************************************************\n"
"******************************************************************\n"
"********************* 0 退出通讯录 ***********************\n"
"********************* 1 存储相关信息 ***********************\n"
"********************* 2 删除相关信息 ***********************\n"
"********************* 3 查找某人信息 ***********************\n"
"********************* 4 修改某人信息 ***********************\n"
"********************* 5 显示通讯录 ***********************\n"
"********************* 6 信息排序 ***********************\n"
"******************************************************************\n"
"******************************************************************\n"
);
}
3.add_con存储信息的实现
存储信息就是把一个人的 姓名,性别,年龄,电话,地址
写进去,也就是说我们需要更新结构体 struct information
.
同时我们知道,一旦增加了一个信息,那么通讯录struct contact
中的实际容量size
就会增加1.剩余容量capacity
就会减去1.
最重要的是, 在我们存储信息之前一定不能忘记检查size
是否已经等于capacity
了,如果等于我们就需要增容.
void add_con(struct contact* con)
{
check_capacity(con); //这一步必不可少
printf("请输入所需存储姓名:\n");
scanf("%s", con->info[con->size].name);
printf("请输入其性别:\n");
scanf("%s", con->info[con->size].sex);
printf("请输入其年龄:\n");
scanf("%s", con->info[con->size].age);
printf("请输入其电话:\n");
scanf("%s", con->info[con->size].tele);
printf("请输入其居住地址:\n");
scanf("%s",con->info[con->size].address);
con->size++; //存储人数加1
}
1.check_capacity增容函数的实现
我们在存储信息时候,需要检查是否必要扩容,check_capacity
的作用就是这个.
void check_capacity(struct contact* con)
{
if (con->size == con->capacity)
{
struct information* p = (struct information*)realloc(con->info, sizeof(struct information) * (con->capacity + 4));
//每次多开辟4个容量.
if (p == NULL)
{
printf("系统容量不足以支撑继续存储信息\n");
return;
}
con->info = p;
con->capacity += 4;
}
}
4.del_con删除信息的实现
要删除一个人的信息,很简单,只要知道那个人的名字就行.但是我们用代码怎么来实现删除呢?
因为我们采用的动态内存数组.删除一个人信息后,就会空缺一个位置,而那个位置大概率是在中间.
那删除以后把后面的数据依次往前挪动吗? 可行,但是比较麻烦.
那怎么办? 采取覆盖方法,直接依次往前挪动数据,然后size
减去1就行.这样最后面那个即使还存在,但是我们后面
即使增加它也会被覆盖.
void del_con(struct contact* con)
{
printf("你想要删除的人名字是:\n");
char na[20] = "";
int index = 0,i = 0;
scanf("%s", na);
for (i = 0; i < con->size - 1; i++) //找此人的位置在哪,如果就在最后面,就只需要size - 1
{
if (!strcmp(con->info[i].name, na))
{
index = i;
break;
}
}
if ((i == con->size) && (strcmp(con->info[con->size - 1].name, na) != 0))
{
printf("此人不存在!\n");
return;
}
for (i = index; i < con->size-1; i++) //依次覆盖
{
con->info[i] = con->info[i + 1];
}
con->size -= 1; //不要忘记减1哦~~
}
5.search查询模块
查询,即根据名字去查询就行.需要的代码和del_con
中部分相似.
void search_con(struct contact* con)
{
printf("你想要查找的人的姓名是:\n");
char na[20] = "";
scanf("%s",na);
int i = 0;
for(i = 0;i<con->size;i++)
{
if (!strcmp(con->info[i].name, na))
{
printf("信息如下:\n"
"%4s\t%4s\t%4s\t%4s\t%4s\n ",
"姓名","性别","年龄","电话","地址");
printf("%s\t%s\t%s\t%s\t%s\n",
con->info[i].name,con->info[i].sex,con->info[i].age,con->info[i].tele, con->info[i].address);
break;
}
}
if (i == con->size)
{
printf("此人不存在\n");
}
}
6.modify_con信息修改实现
信息修改,顾名思义就是去修改某一项信息.直接搜索名字,然后修改相关信息.
void modify_con(struct contact* con)
{
printf("你想要修改谁的信息:\n");
char na[20] = "";
scanf("%s", na);
for (int i = 0; i < con->size; i++)
{
if (!strcmp(con->info[i].name, na))
{
printf("名字需要修改为: ");
scanf("%s",con->info[i].name);
printf("\n性别修改为:");
scanf("%s", con->info[i].sex);
printf("\n年龄修改为:");
scanf("%s", con->info[i].age);
printf("\n电话修改为:");
scanf("%s", con->info[i].tele);
printf("\n地址修改为:");
scanf("%s", con->info[i].address);
printf("\n");
break;
}
}
}
7.show 展示所有人信息
void show_con(struct contact* con)
{
printf("信息如下:\n"
"%4s\t%4s\t%4s\t%4s\t%4s\n",
"姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < con->size; i++)
{
printf("%s\t%s\t%s\t%s\t%s\n",
con->info[i].name, con->info[i].sex, con->info[i].age, con->info[i].tele, con->info[i].address);
}
}
8.sort_con信息排序
这里留下一个小思考,不准调研排序库函数,大家可以怎么排序?
博主用的选择排序:
void swap(struct information* a, struct information* b)
{
struct information p = {0};
p = *a;
*a = *b;
*b = p;
}
void sort_con(struct contact* con)
{
printf("你想要按照什么排序:\n"
"姓名 性别 年龄 电话 地址?\n:");
char na[20] = "";
scanf("%s", na);
int i = 0, j = 0;
for (i = 0; i < con->size - 1; i++)
{
int dex = i;
if (!strcmp(na, "姓名"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].name, con->info[j].name) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na, "性别"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].sex, con->info[j].sex) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na, "年龄"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].age, con->info[j].age) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na,"电话"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].tele, con->info[j].tele) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na, "地址"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].address, con->info[j].address) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
}
}
9.save_con保存通讯录信息.
void save_con(struct contact* con)
{
FILE* write = fopen("pp.txt","wb");
if (!write)
{
printf("系统容量不足,无法保存\n");
return;
}
fwrite(con->info,sizeof(struct information),con->size,write);
fclose(write);
write = NULL;
}
10.free_con释放内存
void free_con(struct contact* con)
{
free(con->info);
con->info = NULL;
}
告终
到此,整个通讯录就写完毕了.
???
真的完毕了吗???大家仔细想想,还有哪一步出问题了.
没错那就是 我们虽然保存了文件,但是下次运行程序时候,我们上次的保存内容读取出来了吗?并没有…
所以我们在初始化出了问题,初始化的时候忘记 读取文件内容
修改:
void save_con(struct contact* con)
{
FILE* write = fopen("pp.txt","wb");
if (!write)
{
printf("系统容量不足,无法保存\n");
return;
}
fwrite(con->info,sizeof(struct information),con->size,write);
fclose(write);
write = NULL;
}
void Initcon(struct contact* con)
{
con->info = (struct information*)malloc(sizeof(struct information) * 4);
if (con->info == NULL)
{
printf("系统容量不足,无法增加通讯录容量\n");
return;
}
con->size = 0; //当前有0个存储信息
con->capacity = 4; //当前通讯录剩余4个存储空间
read_con(con);
}
完结
完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct information //个人信息表
{
char name[20];//姓名
char sex[10]; //性别
char age[10];//年龄
char tele[15];//电话
char address[40];//地址
};
struct contact //通讯录
{
struct information* info; //因为不限人数量,所以开辟动态空间,存储多个信息表.
long long size; //真实信息人数数量
long long capacity; //通讯录剩余容量
};
enum command //增加了枚举常量
{
Exit,
add,
del,
search,
modify,
show,
sort
};
void save_con(struct contact* con)
{
FILE* write = fopen("pp.txt","wb");
if (!write)
{
printf("系统容量不足,无法保存\n");
return;
}
fwrite(con->info,sizeof(struct information),con->size,write);
fclose(write);
write = NULL;
}
void free_con(struct contact* con)
{
free(con->info);
con->info = NULL;
}
void check_capacity(struct contact* con)
{
if (con->size == con->capacity)
{
struct information* p = (struct information*)realloc(con->info, sizeof(struct information) * (con->capacity + 4));
//每次多开辟4个容量.
if (p == NULL)
{
printf("系统容量不足以支撑继续存储信息\n");
return;
}
con->info = p;
con->capacity += 4;
}
}
void read_con(struct contact* con)
{
FILE* read = fopen("pp.txt","rb");
if (read == NULL)
{
return;
}
int i = 0;
while (fread(&(con->info[i++]), sizeof(struct information), 1, read))
{
check_capacity(con); //一定不要忘记检查增容.
con->size++;
}
}
void Initcon(struct contact* con)
{
con->info = (struct information*)malloc(sizeof(struct information) * 4);
if (con->info == NULL)
{
printf("系统容量不足,无法增加通讯录容量\n");
return;
}
con->size = 0; //当前有0个存储信息
con->capacity = 4; //当前通讯录剩余4个存储空间
read_con(con);
}
void remind()
{
printf(
"******************************************************************\n"
"******************************************************************\n"
"********************* 0 退出通讯录 ***********************\n"
"********************* 1 存储相关信息 ***********************\n"
"********************* 2 删除相关信息 ***********************\n"
"********************* 3 查找某人信息 ***********************\n"
"********************* 4 修改某人信息 ***********************\n"
"********************* 5 显示通讯录 ***********************\n"
"********************* 6 信息排序 ***********************\n"
"******************************************************************\n"
"******************************************************************\n"
);
}
void add_con(struct contact* con)
{
check_capacity(con); //这一步必不可少
printf("请输入所需存储姓名:\n");
scanf("%s", con->info[con->size].name);
printf("请输入其性别:\n");
scanf("%s", con->info[con->size].sex);
printf("请输入其年龄:\n");
scanf("%s", con->info[con->size].age);
printf("请输入其电话:\n");
scanf("%s", con->info[con->size].tele);
printf("请输入其居住地址:\n");
scanf("%s",con->info[con->size].address);
con->size++; //存储人数加1
}
void del_con(struct contact* con)
{
printf("你想要删除的人名字是:\n");
char na[20] = "";
int index = 0,i = 0;
scanf("%s", na);
for (i = 0; i < con->size - 1; i++) //找此人的位置在哪,如果就在最后面,就只需要size - 1
{
if (!strcmp(con->info[i].name, na))
{
index = i;
break;
}
}
if ((i == con->size) && (strcmp(con->info[con->size - 1].name, na) != 0))
{
printf("此人不存在!\n");
return;
}
for (i = index; i < con->size-1; i++) //依次覆盖
{
con->info[i] = con->info[i + 1];
}
con->size -= 1; //不要忘记减1哦~~
}
void search_con(struct contact* con)
{
printf("你想要查找的人的姓名是:\n");
char na[20] = "";
scanf("%s",na);
int i = 0;
for(i = 0;i<con->size;i++)
{
if (!strcmp(con->info[i].name, na))
{
printf("信息如下:\n"
"%4s\t%4s\t%4s\t%4s\t%4s\n ",
"姓名","性别","年龄","电话","地址");
printf("%s\t%s\t%s\t%s\t%s\n",
con->info[i].name,con->info[i].sex,con->info[i].age,con->info[i].tele, con->info[i].address);
break;
}
}
if (i == con->size)
{
printf("此人不存在\n");
}
}
void modify_con(struct contact* con)
{
printf("你想要修改谁的信息:\n");
char na[20] = "";
scanf("%s", na);
for (int i = 0; i < con->size; i++)
{
if (!strcmp(con->info[i].name, na))
{
printf("名字需要修改为: ");
scanf("%s",con->info[i].name);
printf("\n性别修改为:");
scanf("%s", con->info[i].sex);
printf("\n年龄修改为:");
scanf("%s", con->info[i].age);
printf("\n电话修改为:");
scanf("%s", con->info[i].tele);
printf("\n地址修改为:");
scanf("%s", con->info[i].address);
printf("\n");
break;
}
}
}
void show_con(struct contact* con)
{
printf("信息如下:\n"
"%4s\t%4s\t%4s\t%4s\t%4s\n",
"姓名", "性别", "年龄", "电话", "地址");
for (int i = 0; i < con->size; i++)
{
printf("%s\t%s\t%s\t%s\t%s\n",
con->info[i].name, con->info[i].sex, con->info[i].age, con->info[i].tele, con->info[i].address);
}
}
void swap(struct information* a, struct information* b)
{
struct information p = {0};
p = *a;
*a = *b;
*b = p;
}
void sort_con(struct contact* con)
{
printf("你想要按照什么排序:\n"
"姓名 性别 年龄 电话 地址?\n:");
char na[20] = "";
scanf("%s", na);
int i = 0, j = 0;
for (i = 0; i < con->size - 1; i++)
{
int dex = i;
if (!strcmp(na, "姓名"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].name, con->info[j].name) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na, "性别"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].sex, con->info[j].sex) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na, "年龄"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].age, con->info[j].age) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na,"电话"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].tele, con->info[j].tele) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
else if (!strcmp(na, "地址"))
{
for (j = i + 1; j < con->size; j++)
{
if (strcmp(con->info[dex].address, con->info[j].address) > 0)
{
dex = j;
}
}
swap(&con->info[dex], &con->info[i]);
}
}
}
int main()
{
struct contact con = {0}; //创建通讯录
Initcon(&con); //初始化通讯录
int input = 0;
printf("请输入你想要操作的命令:\n");
do
{
remind(); //菜单提示
scanf("%d", &input);
switch (input)
{
case Exit:
save_con(&con); //把通讯录保存到文件夹
free_con(&con); //一定要记得释放动态空间.
printf("已经成功退出系统!\n");
break;
case add:
add_con(&con);
printf("信息存储完毕!\n等待您的下一步命令:\n");
break;
case del:
del_con(&con);
printf("该人信息删除完毕!\n等待您的下一步命令:\n");
break;
case search:
printf("此人信息如下:\n");
search_con(&con);
printf("查找成功,等待您的下一步命令:\n");
break;
case modify:
modify_con(&con);
printf("修改完毕\n等待您的下一步命令:\n");
break;
case show:
printf("所存储人的详细信息如下,请查看:\n");
show_con(&con);
printf("展示完毕,等待您的下一步命令:\n");
break;
case sort:
sort_con(&con);
printf("排序成功\n等待您的下一步命令:\n");
break;
default:
printf("你的命令不在菜单栏中,请重新选择:\n");
break;
}
} while (input);
return 0;
}