——————————————我们先来看看通讯录大致结构————————————————
由此可知,我们实现通讯录得先保存个人信息,包括姓名、年龄、电话等,将其添加保存后可以进行增、删、查、改等功能——
目录
目录
一、实现个人信息添加:
二、信息的储存
三、通讯录的初始化
1.目录的初始化:
2.个人信息的初始化:
四、各项功能实现:
1.增加联系人:
2.删除 *** 作:
3.查找联系人:
4.打印联系人:
5.修改联系人:
6.联系人排序:
—————————————优化————————————————
一、实现个人信息添加:
我们可以用结构体进行个人信息的存储——
#define name_max 20
#define sex_max 6
#define number_max 11
#define addr_max 30
typedef struct PeoInfo
{
char name[name_max];//名字
char sex[sex_max];//性别
int age;//年龄
int number[number_max];//电话
char addr[addr_max];//住址
}Peo;
这里结构体名称太长,我们可以用名字替换来缩短其命名,用define定义常量方便后期更改。
二、信息的储存
创建一个结构体,在结构体中创建数组进行数据存储——
#define Max 1000
typedef struct Contact
{
Peo data[Max];
int sum;//用来记录现存联系人大小及方便找到联系人位置
}Cont;
三、通讯录的初始化 1.目录的初始化:
enum Option
{
Exit,
Add,
Delete,
Search,
Alter,
Sort,
Print
};
void menu()
{
printf("************************************\n");
printf("****** 1.Add 2.Delete ********\n");
printf("****** 3.Search 4.Alter ********\n");
printf("****** 5.Sort 6.Print ********\n");
printf("****** 0.Exit ********\n");
printf("************************************\n");
}
void test()
{
int input = 0;
Cont con;
InitContact(&con);
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case Add:
add_contact(&con);
break;
case Delete:
DelContact(&con);
break;
case Search:
SearchContact(&con);
break;
case Alter:
AlterContact(&con);
break;
case Sort:
SortContact(&con);
break;
case Print:
PrintContact(&con);
break;
case Exit:
system("cls");
printf("退出程序\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
这里我们可以将目录分装成一个函数,运用枚举类型进行选择。
将主函数放置在一个测试文件中,再将通讯录分装成头文件(用来放置函数声明及头文件),再将实现的功能分装成一系列函数进行实现,方便后期调用及修改。
在创建了结构体后,内容需要进行初始化再进行赋值 *** 作——
void InitContact(struct Contact* pc)
{
assert(pc);
pc->sum = 0;
memset(pc, 0, sizeof(pc->data));
}
在开启通讯录前先进行置为“0” *** 作。
四、各项功能实现: 1.增加联系人:
将结构体地址传入函数,通过地址找到其内容。
进行之前先用“assert”进行断言。
如果计数器——“sum”小于我们限制的最大存储值,则此结构体还可继续添加。
每次添加完成后可进行清屏保持屏幕整洁。
void add_contact(Cont* pc)
{
assert(pc);
if (pc->sum == Max)
{
printf("存储已满\n");
return;
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->sum].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sum].sex);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->sum].age));
printf("请输入电话:>");
scanf("%s", pc->data[pc->sum].number);
printf("请输入住处:>");
scanf("%s", pc->data[pc->sum].addr);
pc->sum++;
system("cls");
printf("添加完成.\n");
}
2.删除 *** 作:
在我们添加联系人后如果此人之后不再联系,则可进入删除 *** 作——要进行删除 *** 作,则以人名为查找方式,先在所有结构体成员中查找到此人才可进行删除。
而查找此联系人的方式最简单暴力的方法无非就是遍历了(后期进行排序后也可以排序后的结构体进行遍历,效率会提高)——找到此人在总和的位置后,返回此人位置,即可对此人进行删除(将后一个结构体内容向前进行覆盖)。
int FindCont(Cont* pc, const char* s1)
{
assert(pc);
int i = 0;
while (i <= pc->sum)
{
int ret = strcmp(pc->data[i].name, s1);
if (ret == 0)
{
return i;
}
i++;
}
return -1;
}
void DelContact(Cont* pc)
{
assert(pc);
if (pc->sum == 0)
{
printf("无可修改联系人\n");
return;
}
char arr[name_max] = { 0 };
printf("请输入需要查找的联系人:>");
gets(arr);
int ret = FindCont(pc, arr);
if (ret != -1)
{
int j = 0;
for (j = ret; j < pc->sum - 1; j++)
{
pc->data[j] = pc->data[j + 1];
}
pc->sum--;
printf("删除成功\n");
}
else
{
printf("无此联系人,请重新输入\n");
}
}
3.查找联系人:
此时我们可以借用前面删除 *** 作中的"FindCont"函数进行查找,然后将查找到的联系人进行打印
void SearchContact(const Cont* pc)
{
assert(pc);
if (pc->sum == 0)
{
system("cls");
printf("无可修改联系人\n");
return;
}
char arr[name_max] = { 0 };
printf("请输入需要查找的联系人:>");
scanf("%s", arr);
int ret = FindCont(pc, arr);
if (ret == -1)
{
system("cls");
printf("要查找的人不存在\n");
return;
}
system("cls");
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex,
pc->data[ret].number, pc->data[ret].addr);
}
4.打印联系人:
该代码不用修改我们可在传参时加“const”进行修饰——
void PrintContact(const Cont* pc)
{
assert(pc);
int i = 0;
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->sum; i++)
{
printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex,
pc->data[i].number, pc->data[i].addr);
}
}
5.修改联系人:
同删除类似,修改需先找到此联系人才可进行后续 *** 作——我们可以修改其联系人内容——
void AlterContact(Cont* pc)
{
assert(pc);
if (pc->sum == 0)
{
system("cls");
printf("无可修改联系人\n");
return;
}
char arr[name_max] = { 0 };
printf("请输入需要查找的联系人:>");
scanf("%s", arr);
int ret = FindCont(pc, arr);
if (ret == -1)
{
system("cls");
printf("要查找的人不存在\n");
return;
}
printf("%-20s %-5s %-5s %-12s %-30s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-20s %-5d %-5s %-12s %-30s\n", pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex,
pc->data[ret].number, pc->data[ret].addr);
printf("请选择需要%s修改的内容:>",pc->data[ret].name);
printf("1.名字\t 2.年龄\t 3.性别\t 4.电话\t 5.住址\n");
int a = 0;
scanf("%d", &a);
switch (a)
{
case 1:
memset(pc->data->name, 0, sizeof(pc->data[ret].name));
printf("请输入修改后的名字:>");
char new_name[name_max] = { 0 };
scanf("%s", new_name);
strcpy(pc->data->name, new_name);
printf("修改成功\n");
break;
case 2:
memset(pc->data->age, 0, sizeof(pc->data[ret].age));
printf("请输入修改后的年龄:>");
scanf("%d", &pc->data[ret].age);
printf("修改成功\n");
break;
case 3:
memset(pc->data->sex, 0, sizeof(pc->data[ret].sex));
printf("请输入修改后的性别:>");
scanf("%s", pc->data[ret].sex);
printf("修改成功\n");
break;
case 4:
memset(pc->data->number, 0, sizeof(pc->data[ret].number));
printf("请输入修改后的号码:>");
scanf("%s", pc->data[ret].number);
printf("修改成功\n");
break;
case 5:
memset(pc->data->addr, 0, sizeof(pc->data[ret].addr));
printf("请输入修改后的号码:>");
scanf("%s", pc->data[ret].addr);
printf("修改成功\n");
break;
default:
printf("选择错误\n");
break;
}
}
6.联系人排序:
在添加完联系人后整个结构体会显得杂乱无章,此时我们可以用到排序的函数将通讯录按照人名进行排序——
int cmp_name(const void* e1, const void* e2)
{
return strcmp(((Peo*)e1)->name, ((Peo*)e2)->name);
}
void SortContact(Cont* pc)
{
assert(pc);
qsort(pc->data, pc->sum, sizeof(pc->data[0]), cmp_name);
PrintContact(pc);
}
注:(qsort函数使用方法及模拟实现请看—— qsort - C++ Reference)
—————————————优化————————————————
这里可以将储存联系人数量的结构体进行修改——
同上用“sum”表示记录人数,用“capacity”来表示最大容量:
typedef struct Contact
{
Peo* data;//可以存放1000个人的信息
int sum;//记录通讯中已经保存的信息个数
int capacity;//记录通讯录当前的最大容量
}Cont;
此时我们初始化结构体也需要一点改变——
初始化最大值定义为三个,每当达到这个预定值,则进行扩容,(注释:malloc函数详见:malloc - C++ Reference,realloc函数详见:realloc - C++ Reference)
#define DEFUALT_MAX 3
void InitContact(struct Contact* pc)
{
pc->sum = 0;
pc->capacity = DEFUALT_MAX;
pc->data = (Peo*)malloc(pc->capacity * sizeof(Peo));
if (pc->data == NULL)
{
perror("InitContact::malloc");
return;
}
memset(pc->data, 0, sizeof(pc->data));
}
void CheckCapacity(struct Contact* pc)
{
if (pc->sum == pc->capacity)
{
if (pc->sum == pc->capacity)
{
Peo* tmp = (Peo*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peo));
if (tmp != NULL)
{
pc->data = tmp;
}
else
{
perror("CheckCapacity::realloc");
return;
}
pc->capacity += 2;
printf("增容成功\n");
}
}
}
这里我们引用了动态分配函数,则在程序退出时候,需要释放内存,否则会引起内存泄漏等问题,则我们在末尾可以封装一个销毁函数。
void DestroyContact(Cont* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sum = 0;
printf("销毁成功\n");
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)