参考教程:黑马程序员 ——01 通讯录管理系统 - 系统功能介绍及展示_bilibili

1. 项目功能介绍

对于一个简单的通讯录管理系统,其主要功能有:

  • 添加联系人:向通讯录中添加新联系人,固定需要添加的信息有:姓名、性别、年龄、联系电话和家庭住址。要求最多支持添加 1000 个联系人。
  • 显示联系人:显示通讯录中所有联系人的信息
  • 删除联系人:按照姓名删除指定的联系人
  • 查找联系人:按照姓名查看指定联系人信息
  • 修改联系人:按照姓名重新修改指定联系人
  • 清空联系人:清空通讯录中所有联系人信息
  • 退出通讯录:退出当前使用的通讯录

该通讯录应该进行具备一定的人机交互特征(命令行下),具体有:

  • 初始的功能菜单:列出以上功能,并用数字代号提示各个功能。用户可以输入代号来访问对应的功能。可以对菜单做一些装饰性元素

  • 不重启切换功能:要求切换功能时保持当前程序运行,而不是让用户一遍遍重启程序。菜单不要重复输出

  • 添加联系人:以问答式方式引导用户输入需要添加的信息。性别一栏可以提供选项,如果要考虑 DEI,也可以让用户自己输入自己的性别。所有信息添加完成后,需要明确提示用户 “添加成功”。

  • 显示联系人:要求格式化输出。建议在一行内输出且只输出一个联系人的信息。如果没有任何联系人信息,应输出 “当前记录为空” 之类的提示信息

  • 删除联系人:以问答式方式确认需要删除的联系人。删除成功后需要说明。如果删除了不存在的联系人,程序也需要提示 “查无此人”。

  • 查找联系人:以问答式方式确认需要查询的联系人。如果查询了不存在的联系人,程序需要提示 “查无此人”。

  • 修改联系人:实质上相当于调用 “添加联系人” 功能。修改成功后需要提示

  • 清空联系人:清空后需要提示。更好的做法是在删除前加上确认信息,防止误删

  • 退出通讯录:建议输出退出语,比如 “欢迎下次使用”


2. 分功能开发

2.1 添加联系人

  • 数据方面

我们使用结构体来存储单个联系人信息,因为我们要存储的信息的类型明显不同,并且应该归属于同一个条目下。

对于联系人信息结构体的集合,我们使用数组存储。

结构体数组之前没有介绍,可参见:C 结构体 | 菜鸟教程下面列出的笔记,以及 C 语言数组、结构体、结构体数组作为函数参数_结构体数组作为函数参数传递 - CSDN 博客

  • 算法方面

使用最经典的 scanf 输入单个结构体的成员的数据。提示语用 printf 输出。

单个信息输入完毕后,在 main 函数中对计数器 i++,标示数组元素个数以供索引

不得不说,Clang 的代码诊断对于中文疑似不太友好啊,一直输出 warning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void add_person(info arr[], int i) {
//input name
printf("请输入姓名:\n");
scanf("%s", arr[i].name);
//input gender
printf("请输入性别:\n");
scanf("%s", arr[i].gender);
//input age
printf("请输入年龄:\n");
scanf("%d", &arr[i].age);
//input phone number
printf("请输入联系电话:\n");
scanf("%s", arr[i].phone);
//input location
printf("请输入家庭住址:\n");
scanf("%s", arr[i].location);
}

实机演示:

2.2 显示联系人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void list_person(info arr[], int i) {
if (i == 0) {
printf("当前记录为空\n");
}
else {
for (int cnt = 0; cnt < i; cnt++) {
printf("姓名:%s \
性别:%s \
年龄:%d \
联系电话:%s \
家庭住址:%s\n", arr[cnt].name, arr[cnt].gender, arr[cnt].age, arr[cnt].phone, arr[cnt].location);
}
}
}

实机演示:

2.3 删除联系人

初始版本仅仅令计数器 i--,但在后续测试中发现只考虑到最后一个联系人数据的删除。

为了让任意一个元素均可以被删除,我们可以移动数组内元素,用后续元素把目标元素给覆盖掉,再令计数器 i--,防止数组越界

由于我们需要改变实参 i 的数值,因此传入 i 的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void delete_person(info arr[], int* i) {
bool check = 0;
if (*i == 0) {
printf("当前通讯录为空\n");
}
else {
printf("请输入将要删除的联系人的姓名:\n");
char goal[MAX_CHARACTER_LENGTH];
scanf("%s", goal);
for (int j = 0; j < *i; j++) {
if (!strcmp(goal, arr[j].name)) {
for (int ds = 0; ds < *i - j; ds++) {
arr[j + ds] = arr[j + (ds + 1)];
}
(*i)--;
check = 1;
printf("删除成功!\n");
break;
}
}
if (!check){
printf("查无此人\n");
}
}
}

实机演示:

2.4 查找联系人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void find_person(info arr[], int i) {
printf("请输入将要查询的联系人的姓名:\n");
char goal[MAX_CHARACTER_LENGTH];
scanf("%s", goal);
for (int j = 0; j < i; j++) {
if (!strcmp(goal, arr[j].name)) {
printf("姓名:%s \
性别:%s \
年龄:%d \
联系电话:%s \
家庭住址:%s\n", arr[j].name, arr[j].gender, arr[j].age, arr[j].phone, arr[j].location);
}
else {
printf("查无此人\n");
}
}
}

2.5 修改联系人

找到目标联系人后调用 add_person 把原来的联系人覆盖掉就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void edit_person(info arr[], int i) {
bool check = 0;
if (i == 0) {
printf("当前通讯录为空\n");
}
else {
printf("请输入将要修改的联系人的姓名:\n");
char goal[MAX_CHARACTER_LENGTH];
scanf("%s", goal);
for (int j = 0; j < i; j++) {
if (!strcmp(goal, arr[j].name)) {
add_person(arr, j);
check = 1;
break;
}
}
if (!check)
{
printf("查无此人\n");
}
}
}

实机演示:

2.6 清空联系人

1
2
3
4
5
6
7
8
9
10
11
12
void empty_person(int* i) {
printf("确定要清空通讯录吗?\n"
"输入'y'确定,输入'n'取消\n");
char check = getchar();
if (check == 'y' || check == 'Y') {
*i = 0;
printf("已清空!\n");
}
else {
printf("已取消操作\n");
}
}

2.7 主界面(退出通讯录)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int main(void) {
int status;
int i = 0;
do
{
printf("*****通讯录*****\n");
printf("*请输入对应代码*\n"
"* 1.添加联系人 *\n"
"* 2.显示联系人 *\n"
"* 3.删除联系人 *\n"
"* 4.查找联系人 *\n"
"* 5.修改联系人 *\n"
"* 6.清空联系人 *\n"
"* 0.退出通讯录 *\n"
"****************\n");
while (scanf("%d", &status) != 1) {
printf("无法识别功能代码,请重新输入:\n");
while (getchar() != '\n');
}
switch (status) {
case 1:
add_person(data, i);
i++;
break;
case 2:
list_person(data, i);
break;
case 3:
delete_person(data, &i);
break;
case 4:
find_person(data, i);
break;
case 5:
edit_person(data, i);
break;
case 6:
empty_person(&i);
break;
case 0:
printf("欢迎下次使用!\n");
break;
default:
printf("功能不存在。请重试!\n");
}
system("pause");
system("cls");
} while (status != 0);
return 0;
}


3. 人机交互优化

3.1 提示非法输入

在主界面中,对于非数字输入,我们将拒绝该输入并要求用户重新输入:

1
2
3
4
while (scanf("%d", &status) != 1) {
printf("无法识别功能代码,请重新输入:\n");
while (getchar() != '\n');//将新数据传入缓冲区,让scanf函数读取
}

程序首先检查 scanf 返回的成功匹配参数的数据个数。当用户输入一个以数字开头的数据时,scanf 返回 1,程序进入功能代码匹配环节;当用户输入一个以其他字符开头的数据时,scanf 返回 0,进入该循环。


对于不存在的功能代码,提示 “功能不存在”:

1
2
default:
printf("功能不存在。请重试!\n");


©2025-Present Watermelonabc | 萌ICP备20251229号

Powered by Hexo & Stellar latest & Vercel & 𝙌𝙞𝙪𝙙𝙪𝙣 𝘾𝘿𝙉 & HUAWEI Cloud
您的访问数据将由 Vercel 和自托管的 Umami 进行隐私优先分析,以优化未来的访问体验

本博客总访问量:capoo-2

| 开往-友链接力 | 异次元之旅 | 中文独立博客列表

猫猫🐱 发表了 41 篇文章 · 总计 209.8k 字