一、通讯录的基本功能
实现一个通讯录,用来保存其名字,年龄,性别,电话,住址
1、增加联系人
2、删除指定联系人
3、修改指定联系人
4、查找指定联系人
5、显示当先所存所有联系人的信息
6、对当前联系人按照某个标准进行排序
二、通讯录的实现逻辑及代码(静态版本)
实现方式:
考虑到通讯录要存储联系人的姓名,年龄,性别,电话,所以考虑使用结构体来存储通讯录的数据信息。对于这个实现我们采用多文件的形式来完成,test.c用来实现整个通讯录的测试逻辑,contact.h实现对函数,标识符,结构体等声明,contact.c用来实现整个通讯录的增删查改显示以及排序函数的实现。
静态版本代码如下:
test.c文件实现对整个通讯录的测试,根据不同的菜单进行相应的操作,如选择1进行增加通讯录中的联系人,选择2删除指定的联系人,选择3按照名字查找通讯录中的联系人,选择4可以对联系人的姓名,年龄,性别,电话进行修改,选择5可以将当前通讯录中所存储的信息进行展示,选择6将按照名字的进行排序。代码有相应的注释可供参考
#include"contact.h"
int main()
{
int input = 0;
struct contact con;
//一定要记得对这个con结构体进行初始化,否则可能会出现内存非法访问的问题
init_contact(&con);
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
add_contact(&con);//要对结构体内容进行改变,必须要传址
break;
case 2:
del_contact(&con);//要对结构体内容进行改变,必须要传址
break;
case 3:
search(&con);
break;
case 4:
modify(&con);//要对结构体内容进行改变,必须要传址
break;
case 5:
show_contact(&con);
break;
case 6:
sort(&con);
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
contact,h主要对函数进行声明,定义相应的结构体类型,声明相应的头文件等,其代码如下:
#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define max_num 100
#define max_name 20
#define max_sex 5
#define max_tel 12
//考虑到通讯录要存储联系人的姓名,年龄,性别,电话,所以考虑使用结构体来存储数据
struct People_info
{
char name[max_name];
int age;
char sex[max_sex];
char tel[max_tel];
};
//该contact结构体包含联系人信息结构体(由于要存储多人所以定义一个结构体数组),sz是用来记录通讯录中有多少人
struct contact
{
struct People_info people[max_num];//最大用来存储联系人的结构体数组
int sz;//用来记录当前存了多少联系人了
};
//菜单打印函数
void menu();
//初始化通讯录
void init_contact(struct contact *p);
//增加通讯录联系人
void add_contact(struct contact *p);
//显示通讯录
void show_contact(struct contact*p);
//删除通讯录中的联系人
void del_contact(struct contact* p);
//查找通讯录中的联系人
void search(struct contact* p);
//修改通讯录中的联系人
void modify(struct contact* p);
//根据名字进行升序排序
void sort(struct contact* p);
contact.c主要用来实现增,删,查,改,显示,按照名字进行升序排列,其代码实现方式如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
printf("****** 1.add 2.del *****\n");
printf("****** 3.search 4.modify *****\n");
printf("****** 5.show 6.sort *****\n");
printf("****** 0.exit *****\n");
}
void modify_menu()
{
printf("****** 1.name 2.age *****\n");
printf("****** 3.sex 4.tel *****\n");
printf("****** 0.no modify *****\n");
}
//搜寻查找
int find(char*str,struct contact*p)
{
for (int i = 0; i < p->sz; i++)
{
if (!strcmp(str, p->people[i].name))
{
return i;
}
}
return -1;
}
//对通讯录进行初始化
void init_contact(struct contact* p)
{
p->sz = 0;
char arr[] = "\0";
for (int i = 0; i < max_num; i++)//对联系人进行初始化
{
strcpy(p->people[i].name, arr);
strcpy(p->people[i].sex, arr);
strcpy(p->people[i].tel, arr);
p->people[i].age=0;
}
}
//增加通讯录联系人
void add_contact(struct contact* p)
{
if (p->sz > max_num)
{
printf("容量已满,无法无法增加\n");
return;//容量已经满了直接返回
}
else
{
printf("请输入要添加联系人的姓名:>");
scanf("%s", p->people[p->sz].name);
printf("\n");
printf("请输入要添加联系人的年龄:>");
scanf("%d", &(p->people[p->sz].age));
printf("\n");
printf("请输入要添加联系人的性别:>");
scanf("%s", p->people[p->sz].sex);
printf("\n");
printf("请输入要添加联系人的电话:>");
scanf("%s", p->people[p->sz].tel);
p->sz++;
printf("添加成功\n");
}
}
//通讯录中的显示
void show_contact(struct contact* p)
{
printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");
for (int i = 0; i < p->sz; i++)
{
printf("%-10s\t%-5d\t%-5s\t%-20s\n",
p->people[i].name,
p->people[i].age,
p->people[i].sex,
p->people[i].tel);
}
printf("\n");
}
//删除通讯录中的联系人
void del_contact(struct contact* p)
{
if (!p->sz)
{
printf("通讯录为空,无法进行删除操作\n");
return;
}
printf("请输入要删除的联系人:>");
char str[max_name]="\0";
scanf("%s", str);
int del=find(str,p);
if (del == -1)//通讯录找不到该联系人就返回,提前结束
{
printf("要删除的人不存在\n");
return;
}
//删除联系人
for (int i = del; i < p->sz - 1; i++)
{
p->people[i].age = p->people[i + 1].age;
strcpy(p->people[i].name, p->people[i + 1].name);
strcpy(p->people[i].sex, p->people[i + 1].sex);
strcpy(p->people[i].tel, p->people[i + 1].tel);
}
p->sz--;
printf("删除成功\n");
}
//查找通讯录中的联系人
void search(struct contact* p)
{
printf("强输入想要查找的联系人姓名:>");
char str[max_name] = "\0";
scanf("%s", str);
int ret=find(str, p);
if (ret == -1)
{
printf("在该通讯录中找不到\n");
return;
}
printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");;
printf("%-10s\t%-5d\t%-5s\t%-20s\n",
p->people[ret].name,
p->people[ret].age,
p->people[ret].sex,
p->people[ret].tel);
}
//修改通讯录中的联系人
void modify(struct contact* p)
{
printf("请输入要修改人的名字:>");
char str[max_name] = "\0";
scanf("%s", str);
int ret = find(str, p);
if (ret == -1)
{
printf("要修改的人在通讯录中不存在\n");
}
else
{
int input = 0;
do//该逻辑与test.c文件的逻辑基本一致,选择想要修改的或者不修改退出
{
modify_menu();
printf("请选择想要修改的:>");
scanf("%d", &input);
char tmp[max_name] = "\0";//用max_name比其他的大,所以足够容下其他的修改输入
int tt = 0;
switch (input)
{
case 1:
printf("请输入想要修改联系人的名字:>");
scanf("%s", tmp);
strcpy(p->people[ret].name, tmp);
break;
case 2:
printf("请输入想要修改联系人的年龄:>");
scanf("%d", &tt);
p->people[ret].age = tt;
break;
case 3:
printf("请输入想要修改联系人的性别:>");
scanf("%s", tmp);
strcpy(p->people[ret].sex, tmp);
break;
case 4:
printf("请输入想要修改联系人的电话:>");
scanf("%s", tmp);
strcpy(p->people[ret].tel, tmp);
break;
case 0:
printf("不修改\n");
break;
default :
printf("选择错误请重新选择\n");
break;
}
} while (input);
}
}
//排序,按照名字进行升序排序
int cmp(const void* str1, const void* str2)
{
return strcmp(((struct People_info*)str1)->name, ((struct People_info*)str2)->name);
}
void sort(struct contact* p)
{
int num = p -> sz;
struct contact* ptr = p;
qsort(ptr->people, p->sz, sizeof(p->people[0]), cmp);//调用qsort库函数进行排序
show_contact(p);
}
modify修改函数的实现加入了和test.c基本一致的逻辑结构,通过对应的选择来选择修改相应的部分或不修改。
三、测试结果
增加测试:
通过增加了4个人信息显示如下:
删除之后显示如下:
查找通讯录中不存在的联系人:
查找通讯录中存在的联系人
修改也是类似的
排序之前:
排序之后:
动态版本代码(逻辑与静态版本一致):
实现的方式和静态版本的逻辑是一致的(只是在选择0退出释放开辟的空间以及初始化函数部分,增加联系人函数的进行了一些修改),动态版本使用的是
test.c代码如下:
#include"contact.h"
int main()
{
int input = 0;
struct contact con;
//一定要记得对这个con结构体进行初始化,否则可能会出现内存非法访问的问题
init_contact(&con);
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
add_contact(&con);//要对结构体内容进行改变,必须要传址
break;
case 2:
del_contact(&con);//要对结构体内容进行改变,必须要传址
break;
case 3:
search(&con);
break;
case 4:
modify(&con);
break;
case 5:
show_contact(&con);
break;
case 6:
sort(&con);
break;
case 0:
free(con.people);//退出释放开辟的空间
con.people = NULL;//将指针置为空指针
printf("退出通讯录\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
contact.h文件代码如下:
#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define init_cmp 1//默认最初的容量为1
#define max_name 20
#define max_sex 5
#define max_tel 12
//考虑到通讯录要存储联系人的姓名,年龄,性别,电话,所以考虑使用结构体来存储数据
struct People_info
{
char name[max_name];
int age;
char sex[max_sex];
char tel[max_tel];
};
struct contact
{
struct People_info *people;
int sz;//用来记录当前存了多少联系人了
int cap;//记录当前通讯录最大的空间存储
};
//菜单打印函数
void menu();
//初始化通讯录
void init_contact(struct contact *p);
//增加通讯录联系人
void add_contact(struct contact *p);
//显示通讯录
void show_contact(struct contact*p);
//删除通讯录中的联系人
void del_contact(struct contact* p);
//查找通讯录中的联系人
void search(struct contact* p);
//修改通讯录中的联系人
void modify(struct contact* p);
//根据名字进行升序排序
void sort(struct contact* p);
contact.c文件(主要对增加通讯录联系人的这个函数和初始化通讯录进行修改)代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{
printf("****** 1.add 2.del *****\n");
printf("****** 3.search 4.modify *****\n");
printf("****** 5.show 6.sort *****\n");
printf("****** 0.exit *****\n");
}
void modify_menu()
{
printf("****** 1.name 2.age *****\n");
printf("****** 3.sex 4.tel *****\n");
printf("****** 0.no modify *****\n");
}
//搜寻查找
int find(char*str,struct contact*p)
{
for (int i = 0; i < p->sz; i++)
{
if (!strcmp(str, p->people[i].name))
{
return i;
}
}
return -1;//通讯录中没查到此人就返回-1
}
//对通讯录进行初始化
void init_contact(struct contact* p)
{
p->people = (struct People_info*)malloc(sizeof(struct People_info) * init_cmp);
if (p->people==NULL)
{
perror("malloc:");//申请失败,提醒是malloc开辟空间失败
return;
}
p->sz = 0;
char arr[] = "\0";
for (int i = 0; i < init_cmp; i++)//对联系人进行初始化
{
strcpy(p->people[i].name, arr);
strcpy(p->people[i].sex, arr);
strcpy(p->people[i].tel, arr);
p->people[i].age=0;
}
p->cap = init_cmp;//防止空间浪费,所以初始容量大小为2
}
//增加通讯录联系人
void add_contact(struct contact* p)
{
if ((p->sz) >= (p->cap))
{
p->cap += 2;//每次容量增加2
struct People_info* ptr = (struct People_info*)realloc(p->people, sizeof(struct People_info) * (p->cap));//申请失败,提醒是realloc开辟空间失败
if (ptr == NULL)
{
p->cap -= 2;//没增容成功,就减到原来的容量
printf("增容失败\n");
return;//失败直接返回
}
p->people = ptr;
printf("增容成功\n");
}
printf("请输入要添加联系人的姓名:>");
scanf("%s", p->people[p->sz].name);
printf("\n");
printf("请输入要添加联系人的年龄:>");
scanf("%d", &(p->people[p->sz].age));
printf("\n");
printf("请输入要添加联系人的性别:>");
scanf("%s", p->people[p->sz].sex);
printf("\n");
printf("请输入要添加联系人的电话:>");
scanf("%s", p->people[p->sz].tel);
p->sz++;
printf("添加成功\n");
}
//通讯录中的显示
void show_contact(struct contact* p)
{
printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");
for (int i = 0; i < p->sz; i++)
{
printf("%-10s\t%-5d\t%-5s\t%-20s\n",
p->people[i].name,
p->people[i].age,
p->people[i].sex,
p->people[i].tel);
}
printf("\n");
}
//删除通讯录中的联系人
void del_contact(struct contact* p)
{
if (!p->sz)
{
printf("通讯录为空,无法进行删除操作\n");
return;
}
printf("请输入要删除的联系人:>");
char str[max_name]="\0";
scanf("%s", str);
int del=find(str,p);
if (del == -1)//通讯录找不到该联系人就返回,提前结束
{
printf("要删除的人不存在\n");
return;
}
//删除联系人
for (int i = del; i < p->sz - 1; i++)
{
p->people[i].age = p->people[i + 1].age;
strcpy(p->people[i].name, p->people[i + 1].name);
strcpy(p->people[i].sex, p->people[i + 1].sex);
strcpy(p->people[i].tel, p->people[i + 1].tel);
}
p->sz--;
printf("删除成功\n");
}
//查找通讯录中的联系人
void search(struct contact* p)
{
printf("请输入想要查找的联系人姓名:>");
char str[max_name] = "\0";
scanf("%s", str);
int ret=find(str, p);
if (ret == -1)
{
printf("在该通讯录中找不到\n");
return;
}
printf("%-10s\t%-5s\t%-5s\t%-20s\n", "姓名", "年龄", "性别", "电话");;
printf("%-10s\t%-5d\t%-5s\t%-20s\n",
p->people[ret].name,
p->people[ret].age,
p->people[ret].sex,
p->people[ret].tel);
}
//修改通讯录中的联系人
void modify(struct contact* p)
{
printf("请输入要修改人的名字:>");
char str[max_name] = "\0";
scanf("%s", str);
int ret = find(str, p);
if (ret == -1)
{
printf("要修改的人在通讯录中不存在\n");
}
else
{
int input = 0;
do
{
modify_menu();
printf("请选择想要修改的:>");
scanf("%d", &input);
char tmp[max_name] = "\0";//用max_name比其他的大,所以足够容下其他的修改输入
int tt = 0;
switch (input)
{
case 1:
printf("请输入想要修改联系人的名字:>");
scanf("%s", tmp);
strcpy(p->people[ret].name, tmp);
break;
case 2:
printf("请输入想要修改联系人的年龄:>");
scanf("%d", &tt);
p->people[ret].age = tt;
break;
case 3:
printf("请输入想要修改联系人的性别:>");
scanf("%s", tmp);
strcpy(p->people[ret].sex, tmp);
break;
case 4:
printf("请输入想要修改联系人的电话:>");
scanf("%s", tmp);
strcpy(p->people[ret].tel, tmp);
break;
case 0:
printf("不修改\n");
break;
default :
printf("选择错误请重新选择\n");
break;
}
} while (input);
}
}
//排序,按照名字字符进行排序
int cmp(const void* str1, const void* str2)
{
return strcmp(((struct People_info*)str1)->name, ((struct People_info*)str2)->name);
}
void sort(struct contact* p)
{
int num = p -> sz;
struct contact* ptr = p;
qsort(ptr->people, p->sz, sizeof(p->people[0]), cmp);
show_contact(p);
}
最小的容量设置的为1,当存第二个联系人将会重新申请空间增加容量,每次增加2个存放联系人信息的空间。
总结:该通讯录主要使用了结构体,结构体数组,结构体嵌套结构体,在使用结构体首选传址而不是传值,需要注意的,要对结构体中的信息进行修改要传相应的结构体地址。