C语言实现初阶通讯录
本篇主要介绍C语言实现初阶通讯录
文章目录
前言
本篇主要介绍C语言实现通讯录。通讯录涵盖初阶包括进阶C语言的许多知识点,包括但不限于指针,动态内存分配,文件操作,结构体的运用。
这篇博客是初阶通讯录,即不涉及动态内存以及文件操作。完整版我会在后续发布,在这个版本的基础上进行一定的修改。
下面开始
一、功能介绍
1,增加成员信息
2,删除成员信息
3,搜索成员信息
4,修改成员信息
5,排序成员信息
6,打印成员信息
二、模板构建
通讯录模板 的构建是通过结构体来实现的。
这里需要两个结构体,一个是struct PeoInfo,用来创建用户信息类型,包括姓名,年龄,电话,性别,住址。另一个是struct Contact,用来创建通讯录类型,该类型包含了两个元素,其中一个是数组:struct PeoInfo data[1000],即该通讯录可容纳1000人,另一个是size,即你要存的是第几个人(相当于把这个人存入数组的哪个位置)
typedef struct PeoInfo
{
char name[5];
char sex[5];
int age;
char address[20];
char tel[12];
}PeoInfo;
typedef struct Contact
{
PeoInfo data[1000];
int size;
}Contact;
因此,我们便可以创建一个变量,其类型为Contact,其名称我们称之为con
Contact con;
这是它内部的成员
data是一个数组,上面提到过,该数组的每一个元素都是一个结构体类型
三、通讯录界面
菜单可以实现与用户的良好交互,因此有必要实现一个菜单打印函数。
```c
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 input;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
add();//增加功能
break;
case 2:
del();//删除功能
break;
case 3:
search();//查找功能
break;
case 4:
modify();//更改功能
break;
case 5:
show();//展示
break;
case 6:
sort();//排序
break;
case 0:
break;
default:
printf("你的输入有误,请重新输入\n");
break;
}
} while (input);
当input输入为0时,while(input)判定为假,跳出循环。当用户输入0-6之外的数字,会给出“你的输入有误,请重新输入”的提示。
以上就是通讯录的界面部分
四、 通讯录的初始化
由于一开始,我们的通讯录内部是没有任何成员的,且size应置为0,即将第一个成员放入数组的第0个位置。因此,我们需要对通讯录进行初始化。
初始化前:
初始化方法:创建一个Init函数进行实现
void Init(Contact* ps)
{
memset(ps->data, 0, sizeof(ps->data));
ps->size = 0;
}
这里借助内存设置函数memset将data这块空间的内存全部设为0。注意,由于我们要改变的是con的值,因此我们选择传址调用函数。
初始化后:
五、功能实现
一、增加
增加函数,因为要改变通讯录的内部,因此依然选择传址调用
void add(Contact* con)
我们要做的依次输入成员信息,并将该信息存入data数组的相应位置。因此,每执行一次该函数,size就应该++一次。那么,如何访问到该数组呢?con->data可访问该数组,那么如何访问该数组的第size个元素呢? 可以使用 (con->data)[con->size]
那么如何访问第size个元素的某个变量,比如年龄呢?我们可以借助"."运算符来实现。 (con->data)[con->size].age接着我们借助scanf实现数据的输入
void add(Contact* con)
{
printf("请输入住址\n");
scanf("%s", &((con->data)[con->size].address));
printf("请输入姓名\n");
scanf("%s", &((con->data)[con->size].name));
printf("请输入性别\n");
scanf("%s", &((con->data)[con->size].sex));
printf("请输入电话\n");
scanf("%s", &((con->data)[con->size].tel));
printf("请输入年龄\n");
scanf("%d", &((con->data)[con->size].age));
(con->size)++;
printf("添加完成\n");
}
增加的实现效果如下
依次输入后,通过监视窗口可以看到data[0]已经发生了改变。
二、展示
展示窗口可以展示你目前的通讯录的内容,实现完该函数后对后续功能的检查会变得十分方便,因此我们先来实现 展示 这个功能。
void show(Contact* con)
{
for (int i = 0; i < con->size; i++)
{
printf("-----------------------------\n");
printf(" 成员编号:【%d】\n", i);
printf("姓名:%s\n", (con->data)[i].name);
printf("年龄:%d\n", (con->data)[i].age);
printf("电话:%s\n", (con->data)[i].tel);
printf("住址:%s\n", (con->data)[i].address);
printf("性别:%s\n", (con->data)[i].sex);
}
}
这段代码的逻辑十分简单,通过一个for循环来确定打印的名单数目,即如果size为1,就只打印一个名单(因为此时只有一个成员)效果如下
可以看到,当我选择了’‘show’'时,其展示了我存入的两个成员的信息。
三、删除
删除功能,即删除某个成员的信息
这个功能就有些复杂了,第一,你要找到你所删除的元素的位置,比如我要删掉5号,那么我们就要找到对应数组的下标,并将其删除。第二,删除之后通讯录的状态如何把控。假设我们现在有八个成员,而我们要删掉第4个成员的信息,我们其实有两种删除方法
1、删掉四,随后五、六、七、八依次往前覆盖,并进行size–(因为现在只剩下七个元素了)
2、直接将八移动到四的位置。但这样会打乱通讯录成员的顺序。
我们在这里选择1进行实现。
首先,我们使用for循环找到要删除的元素的位置,如果循环到最后依然没有找到,就打印要找的人不存在并return.
```c
for ( i = 0; i < con->size; ++i)
{
if (strcmp((con->data)[i].name, del_name) == 0)
break;
}
if (i == con->size)
{
printf("要删除的人不存在");
return;
}
接着,我们再次借助for循环,挨个进行元素替换,最后,我们进行con->size–并在屏幕上打印删除成功
else
{
for (int m = i; m < con->size-1; m++)
{
(con->data)[i] = (con->data)[i + 1];
(con->size)--;
printf("删除成功");
}
}
效果展示:
先存入三个成员
然后输入一个不存在的成员
然后我们删除李四
删除实现成功!
四、查找
写过删除功能后,查找功能就似乎变得十分简单了;
查找功能虽不需要进行通讯录内部的改变,但众所周知,结构体传参传指针的效率远高于直接传入一个结构体,因此我们依然选择传入指针。
那么我们只需实现类似于删除中的查找姓名功能,再进行打印即可。
如果输入了一个不存在的姓名,会给出提示
如果给出了一个存在的成员名字,会打印出该成员的信息
代码逻辑十分简单,如下所示
void search(Contact* con)
{
char search_name[10];
printf("请输入你要查找的成员的名字\n");
scanf("%s", &search_name);
int i;
for (i = 0; i < con->size; ++i)
{
if (strcmp((con->data)[i].name, search_name) == 0)
break;
}
if (i == con->size)
{
printf("要查找的人不存在\n");
}
else
{
printf(" 查找成功,成员信息如下\n ");
printf("-----------------------------\n");
printf(" 成员编号:【%d】\n", i);
printf("姓名:%s\n", (con->data)[i].name);
printf("年龄:%d\n", (con->data)[i].age);
printf("电话:%s\n", (con->data)[i].tel);
printf("住址:%s\n", (con->data)[i].address);
printf("性别:%s\n", (con->data)[i].sex);
}
}
五、修改
修改的逻辑也十分简单,输入需要修改的成员编号,然后重新输入数据即可
效果如下
先增添一名成员
此时面板如下
再修改0号成员
修改完展示如下
可以看到,0号成员的信息已经发生了改变
代码如下
void modify(Contact* con)
{
printf("请输入你要修改的成员的编号\n");
int number;
scanf("%d", &number);
printf("请输入新的住址\n");
scanf("%s", &((con->data)[number].address));
printf("请输入新的姓名\n");
scanf("%s", &((con->data)[number].name));
printf("请输入新的性别\n");
scanf("%s", &((con->data)[number].sex));
printf("请输入新的电话\n");
scanf("%s", &((con->data)[number].tel));
printf("请输入新的年龄\n");
scanf("%d", &((con->data)[number].age));
printf("修改完成\n");
}
六、排序
最后一个功能为排序功能,即输入你要交换的两个成员的编号,然后对他们的信息进行交换。
这个功能我们需要创建一个临时空间用于交换,因此我们在原有的Contact这个结构体类中新增一个成员
typedef struct Contact
{
PeoInfo data2[20];
PeoInfo data[1000];
int size;
}Contact;
即data2,其用于临时储存
随后进行交换即可
交换前
交换后
![在这里插入图片描述](https://www.icode9.com/i/ll/?i=20201220140450491.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MjAxNjc4Mg==,size_16,color_FFFFFF,t_70)
代码
```c
void sort(Contact* con)
{
printf("请输入你要交换的两个成员的编号(二者用空格隔开)\n");
int num1;
int num2;
scanf("%d%d", &num1, &num2);
(con->data2)[0] = (con->data)[num1];
(con->data)[num1] = (con->data)[num2];
(con->data)[num2] = (con->data2)[0];
printf("交换成功\n");
}
六 功能优化
如果仔细观察,你会发现其实每次输一个功能是,这个通讯录的界面十分混乱。那么如何解决这个问题呢,可以在适当的位置加入cls,即清空屏幕来达到简洁的效果。
我选择的是在除去菜单打印函数的每个函数的入口加入cls,这样每次执行一个新的功能,都会把残留的信息清空。
七 完整代码
头文件(用于函数的声明以及结构体的声明):contact.h
#ifndef _CONTACT_H_
#define _CONTACT_H_
#include<stdio.h>
#include<windows.h>
typedef struct PeoInfo
{
char name[10];
char sex[5];
int age;
char address[20];
char tel[12];
}PeoInfo;
typedef struct Contact
{
PeoInfo data2[20];
PeoInfo data[1000];
int size;
}Contact;
void menu();
void Init(Contact*);
void add(Contact*);
void show(Contact*);
void del(Contact*);
void searcg(Contact*);
void modify(Contact*);
void sort(Contact*);
#endif // _CONTACT_H_
源文件1(用于函数的实现):test.c
#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");
}
void Init(Contact* con)
{
system("cls");
memset(con->data, 0, sizeof(con->data));
con->size = 0;
}
void add(Contact* con)
{
system("cls");
printf("请输入住址\n");
scanf("%s", &((con->data)[con->size].address));
printf("请输入姓名\n");
scanf("%s", &((con->data)[con->size].name));
printf("请输入性别\n");
scanf("%s", &((con->data)[con->size].sex));
printf("请输入电话\n");
scanf("%s", &((con->data)[con->size].tel));
printf("请输入年龄\n");
scanf("%d", &((con->data)[con->size].age));
(con->size)++;
printf("添加完成\n");
}
void show(Contact* con)
{
system("cls");
if (con->size == 0)
{
printf("通讯录为空");
}
else
{
for (int i = 0; i < con->size; i++)
{
printf("-----------------------------\n");
printf(" 成员编号:【%d】\n", i);
printf("姓名:%s\n", (con->data)[i].name);
printf("年龄:%d\n", (con->data)[i].age);
printf("电话:%s\n", (con->data)[i].tel);
printf("住址:%s\n", (con->data)[i].address);
printf("性别:%s\n", (con->data)[i].sex);
}
}
}
void del(Contact* con)
{
system("cls");
char del_name[10];
printf("请输入你要删除的成员的名字\n");
scanf("%s", &del_name);
int i;
for ( i = 0; i < con->size; ++i)
{
if (strcmp((con->data)[i].name, del_name) == 0)
break;
}
if (i == con->size)
{
printf("要删除的人不存在\n");
}
else
{
for (int m = i; m < con->size - 1; m++)
{
(con->data)[i] = (con->data)[i + 1];
}
(con->size)--;
printf("删除成功\n");
}
}
void search(Contact* con)
{
system("cls");
char search_name[10];
printf("请输入你要查找的成员的名字\n");
scanf("%s", &search_name);
int i;
for (i = 0; i < con->size; ++i)
{
if (strcmp((con->data)[i].name, search_name) == 0)
break;
}
if (i == con->size)
{
printf("要查找的人不存在\n");
}
else
{
printf(" 查找成功,成员信息如下\n ");
printf("-----------------------------\n");
printf(" 成员编号:【%d】\n", i);
printf("姓名:%s\n", (con->data)[i].name);
printf("年龄:%d\n", (con->data)[i].age);
printf("电话:%s\n", (con->data)[i].tel);
printf("住址:%s\n", (con->data)[i].address);
printf("性别:%s\n", (con->data)[i].sex);
}
}
void modify(Contact* con)
{
system("cls");
printf("请输入你要修改的成员的编号\n");
int number;
scanf("%d", &number);
printf("请输入新的住址\n");
scanf("%s", &((con->data)[number].address));
printf("请输入新的姓名\n");
scanf("%s", &((con->data)[number].name));
printf("请输入新的性别\n");
scanf("%s", &((con->data)[number].sex));
printf("请输入新的电话\n");
scanf("%s", &((con->data)[number].tel));
printf("请输入新的年龄\n");
scanf("%d", &((con->data)[number].age));
printf("修改完成\n");
}
void sort(Contact* con)
{
system("cls");
printf("请输入你要交换的两个成员的编号(二者用空格隔开)\n");
int num1;
int num2;
scanf("%d%d", &num1, &num2);
(con->data2)[0] = (con->data)[num1];
(con->data)[num1] = (con->data)[num2];
(con->data)[num2] = (con->data2)[0];
printf("交换成功\n");
}
源文件2(调用函数):contact.c
#include"contact.h"
void main()
{
Contact con;
Init(&con);
int input;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
add(&con);//增加功能
break;
case 2:
del(&con);//删除功能
break;
case 3:
search(&con);//查找功能
break;
case 4:
modify(&con);//修改功能
break;
case 5:
show(&con);//展示
break;
case 6:
sort(&con);//排序
break;
case 0:
break;
default:
printf("你的输入有误,请重新输入\n");
break;
}
} while (input);
}
总结
不得不说的是,这个通讯录的功能十分简陋,第一,它不允许你根据成员的多少来设置空间,而是固定的1000容量。第二,每当你关闭界面,你的所有成员信息都会被销毁,下次打开时什么也没有。这显然不能称之为一个合格的通讯录。在我的下篇博客我会对这两个问题进行解决,码字不易,希望点赞支持