结构(4)通讯录实战
结构(4)通讯录实战
1.实现一个通讯录的的基本目的
1.1实现通讯录的前提
我们要实现一个可以存储人的信息的通讯录,基本囊括:名字+年龄+性别+电话+地址
- 可以存放100个人的信息
- 可以 增加/删除/修改 联系人
- 可以 查找/显示/排序 联系人
- 对联系人在通讯录进行某种逻辑的排序
我们要实现一个通讯录少不了封装各种函数和复合各种结构,因此我们采取多文件的方式进行处理
通讯录.c
实现函数模块和功能测试
contact.c
实现通讯录相关函数和结构
contact.h
通讯录的相关声明
1.2实现通讯录的基本框架
- 我们需要一个菜单栏:
void menu()
{printf("********1.add 2.delect***************\n");printf("********3.search 4.modify***************\n");printf("********5.show 6.sort*****************\n");printf("********0.exit ***************\*n");printf("*****************************************\n");
}int main()
{int input;do {scanf("%d", &input);menu();} while (input);return 0;
}
- 我们需要根据菜单栏的输入选择进入到相应的功能模块区,因此有switch—case
switch (input)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 0:printf("退出成功!\n");system("pause");break;
default:printf("非法输入,请重新输入\n");system("pause");system("cls");break;
}
这里需要包含头文件<windows.h>
实现暂停和清除屏幕的效果
1.3通讯录的结构体
- 这一步要在
contact.h
文件中进行
typedef struct contact
{char name[20];int age;char gender[10];int numbers;char address[30];
}contacts;
- 同时,我们也要实现一个最大容纳量的数组和计数的功能
typedef struct list
{contacts pers[100];int cnt;
}list;
- 紧跟着,应该对通讯录进行初始化,为了实现模块化操作,我们选择使用函数进行初始化。
contact.c
void Init_list(list* pers)
{pers->cnt = 0;for (int i = 0; i < 100; i++){pers->cnt = 0;memset(pers->pers, 0, sizeof(pers->pers));}
}
通讯录.c
int input;
list pers;//初始化通讯录
Init_list(&pers);
do {menu();
-
为什么使用memset?
在C语言中,你可以使用直接赋值的方式来初始化字符串成员,但这种方式有一些限制。直接赋值的方式通常只适用于字符串字面量或者已经存在的字符数组。如果你要将一个字符串值赋给结构体中的字符串成员,你可以这样做:
#include <stdio.h>struct Person {char name[50];int age; };int main() {struct Person person;// 直接赋值一个字符串字面量给name成员person.name = "Alice"; // 这行会导致编译错误person.age = 25;printf("Name: %s, Age: %d\\n", person.name, person.age);return 0; }
然而,上述代码会导致编译错误,因为C语言不支持将字符串字面量直接赋值给字符数组,如上面的
person.name = "Alice";
这行代码所示。要在结构体中正确初始化字符串成员,通常需要使用字符串处理函数,如
strcpy
,来将一个字符串复制到字符数组中。例如:#include <stdio.h> #include <string.h>struct Person {char name[50];int age; };int main() {struct Person person;// 使用strcpy将字符串复制到name成员中strcpy(person.name, "Alice");person.age = 25;printf("Name: %s, Age: %d\\n", person.name, person.age);return 0; }
上述代码使用
strcpy
函数将字符串"Alice"复制到了person.name
成员中,这是一种常见的方式来初始化字符串成员。这确保了字符串被正确地复制到了字符数组中,以便后续的操作不会出现问题。
contact.h
void Init_list(list*pers);
-
字符串函数知识补遗
字符串函数传递的都是地址!
2.通讯录的分模块化实现
1.实现通讯录的增加操作
- 在主文件中确定调用的函数
case 1:Add(&pers);system("pause");system("cls");break;
- 在副文件中声明和确定函数
void Add(list* pers)
{
if (pers->cnt >= 100)
{printf("人数已满,无法录入");return;
}
printf("请输入姓名\n");
scanf("%s", &(pers->pers[pers->cnt].name));
printf("请输入年龄\n");
scanf("%d", &(pers->pers[pers->cnt].age));
printf("请输入性别\n");
scanf("%s", &(pers->pers[pers->cnt].gender));
printf("请输入电话号码\n");
scanf("%d", &(pers->pers[pers->cnt].numbers));
printf("请输入地址\n");
scanf("%s", &(pers->pers[pers->cnt].address));
printf("录入成功!\n");
pers->cnt++;
}
void Add(list* pers);
2.实现通讯录的显示效果
- 使用Show函数模块
case 5:Show(&pers);system("pause");system("cls");break;
- 在副文件中声明和确定函数
void Show(list const* pers)
{printf("\t%5s \t%5s \t%5s \t%8s \t%5s\n", "姓名", "年龄", "性别", "电话号码", "地址");for (int i = 0; i < pers->cnt; i++){printf("\t%6s \t%5d \t%5s \t%8d \t%6s\n",pers->pers[i].name, pers->pers[i].age, pers->pers[i].gender, pers->pers[i].numbers, pers->pers[i].address);}
}
void Show(list* pers);
3.实现通讯录的删除和查找效果
- 实现查找效果:
我们使用strcmp进行遍历比较,并打印寻找的元素、返回下标值(便于联动)
int Search(const list* pers,char* name)
{for (int i = 0; i < pers->cnt; i++){if (0 == strcmp(name, pers->pers[i].name)){printf("\t%6s \t%5d \t%5s \t%8d \t%6s\n",pers->pers[i].name, pers->pers[i].age, pers->pers[i].gender, pers->pers[i].numbers, pers->pers[i].address);return i;}}
}
- 实现删除效果:
void Del(list* pers)
{if (pers->cnt <= 0){printf("还没有人员信息\n");return;}printf("请选择你要删除的联系人\n");char name[20];scanf("%s", name);printf("\t%5s \t%5s \t%5s \t%8s \t%5s\n", "姓名", "年龄", "性别", "电话号码", "地址");int result = Search(pers, name);printf("删除成功\n");for (int i = result; i < pers->cnt-1; i++){memcpy(&(pers->pers[i]),&(pers->pers[i+1]),sizeof(pers->pers[0]));}pers->cnt--;}
也可以使用下式操作来进行元素删除!
memcpy(&(pers->pers[i]),&(pers->pers[i+1]),sizeof(pers->pers[0]));
4.实现修改效果
所谓修改就是重新录入的意思!当然我们也要先查找获取角标!
void Modify(list* pers, char* name)
{int result = Search(pers, name);printf("请输入姓名\n");scanf("%s", (pers->pers[result].name));printf("请输入年龄\n");scanf("%d", &(pers->pers[result].age));printf("请输入性别\n");scanf("%s", (pers->pers[result].gender));printf("请输入电话号码\n");scanf("%d", &(pers->pers[result].numbers));printf("请输入地址\n");scanf("%s", (pers->pers[result].address));printf("修改成功!\n");
}
5.实现排序效果
这里我们使用qsort快速排序进行!(因为最容易)按照现实情况,应该对名字进行排序。
int cmp_by_name(const void* p1, const void* p2)
{return strcmp(((contacts*)p1)->name, ((contacts*)p2)->name);
}void sort(list* pers)
{qsort(pers->pers, pers->cnt, sizeof(pers->pers[0]), cmp_by_name);
}
如果你想要升序排序,可以这么写(更有逼格):
return strcmp(((contacts*)p1)->name, ((contacts*)p2)->name) ? -1 : 1;
3.完整代码
我们可以再增加assert.h
确保录入的指针不是空指针,便于防止程序出错!
3.1 contact.h
#pragma once
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef struct contact
{char name[20];int age;char gender[10];int numbers;char address[30];
}contacts;typedef struct list
{contacts pers[100];int cnt;
}list;
void Init_list(list*pers);void Add(list* pers);void Show(list const* pers);void Del(list* pers);int Search(const list* pers,char* name);void Modify(list* pers, char* name);void sort(list* pers);
3.2 通讯录.c
#include<stdio.h>
#include<windows.h>
#include"contact.h"
void menu()
{printf("***********1.add 2.delect***************\n");printf("***********3.search 4.modify***************\n");printf("***********5.show 6.sort*****************\n");printf("***********0.exit *****************\n");printf("********************************************\n");
}int main()
{int input;list pers;//初始化通讯录Init_list(&pers);do {menu();scanf("%d", &input);switch (input){case 1:Add(&pers);system("pause");system("cls");break;case 2:Del(&pers);system("pause");system("cls");break;case 3:printf("请输入你要查找人的名字\n");char name[20];scanf("%s", name);Search(&pers,name);system("pause");system("cls");break;case 4:printf("请输入你要修改的对象\n");char name[20];scanf("%s", name);Modify(&pers, name);system("pause");system("cls");break;case 5:Show(&pers);system("pause");system("cls");break;case 6:sort(&pers);case 0:printf("退出成功!\n");system("pause");break;default:printf("非法输入,请重新输入\n");system("pause");system("cls");break;}} while (input);return 0;
}
3.3 contact.c
#include<stdio.h>
#include"contact.h"
void Init_list(list* pers)
{pers->cnt = 0;for (int i = 0; i < 100; i++){pers->cnt = 0;memset(pers->pers, 0, sizeof(pers->pers));}
}void Add(list* pers)
{assert(pers);if (pers->cnt >= 100){printf("人数已满,无法录入");return;}printf("请输入姓名\n");scanf("%s", (pers->pers[pers->cnt].name));printf("请输入年龄\n");scanf("%d", &(pers->pers[pers->cnt].age));printf("请输入性别\n");scanf("%s", (pers->pers[pers->cnt].gender));printf("请输入电话号码\n");scanf("%d", &(pers->pers[pers->cnt].numbers));printf("请输入地址\n");scanf("%s", (pers->pers[pers->cnt].address));printf("录入成功!\n");pers->cnt++;
}void Show(list const* pers)
{assert(pers);printf("\t%5s \t%5s \t%5s \t%8s \t%5s\n", "姓名", "年龄", "性别", "电话号码", "地址");for (int i = 0; i < pers->cnt; i++){printf("\t%6s \t%5d \t%5s \t%8d \t%6s\n",pers->pers[i].name, pers->pers[i].age, pers->pers[i].gender, pers->pers[i].numbers, pers->pers[i].address);}
}void Del(list* pers)
{assert(pers);if (pers->cnt <= 0){printf("还没有人员信息\n");return;}printf("请选择你要删除的联系人\n");char name[20];scanf("%s", name);int result = Search(pers, name);printf("删除成功\n");for (int i = result; i < pers->cnt-1; i++){memcpy(&(pers->pers[i]),&(pers->pers[i+1]),sizeof(pers->pers[0]));}pers->cnt--;}int Search(const list* pers,char* name)
{assert(pers);printf("\t%5s \t%5s \t%5s \t%8s \t%5s\n", "姓名", "年龄", "性别", "电话号码", "地址");for (int i = 0; i < pers->cnt; i++){if (0 == strcmp(name, pers->pers[i].name)){printf("\t%6s \t%5d \t%5s \t%8d \t%6s\n",pers->pers[i].name, pers->pers[i].age, pers->pers[i].gender, pers->pers[i].numbers, pers->pers[i].address);return i;}}
}void Modify(list* pers, char* name)
{assert(pers);int result = Search(pers, name);printf("请输入姓名\n");scanf("%s", (pers->pers[result].name));printf("请输入年龄\n");scanf("%d", &(pers->pers[result].age));printf("请输入性别\n");scanf("%s", (pers->pers[result].gender));printf("请输入电话号码\n");scanf("%d", &(pers->pers[result].numbers));printf("请输入地址\n");scanf("%s", (pers->pers[result].address));printf("修改成功!\n");}int cmp_by_name(const void* p1, const void* p2)
{return strcmp(((contacts*)p1)->name, ((contacts*)p2)->name) ? -1 : 1;
}void sort(list* pers)
{qsort(pers->pers, pers->cnt, sizeof(pers->pers[0]), cmp_by_name);
}