文章目录
一、基本结构的实现
1.菜单
通讯录需要实现添加、删除、查找、展示、修改,基于此可以设计出下面的菜单。
代码如下(示例):
void menu()
{
printf("0.exit\n1.add\n2.del\n");
printf("3.search\n4.modify\n5.show\n\n");
}
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 0:
printf("exit success\n\n");
break;
case 1:
addContact(&con);
break;
case 2:
delContact(&con);
break;
case 3:
searchContact(&con);
break;
case 4:
showContact(&con);
break;
case 5:
modifyContact(&con);
break;
default:
printf("input error\n\n");
break;
}
} while (input);
return 0;
}
这样一个简易的菜单就做好了,但是switch中的case语句后跟的全部是数字,在编写程序时不便于理解。
由于枚举常量在不初始化的情况下默认从0开始依次递增1,所以这里可以用枚举常量来实现,提高代码的可读性。
代码如下(示例):
void menu()
{
printf("0.exit\n1.add\n2.del\n");
printf("3.search\n4.modify\n5.show\n\n");
}
enum Option
{
EXIT,//0
ADD,//1
DEL,//2
SEARCH,//3
MODIFY,//4
SHOW//5
};
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case EXIT:
printf("exit success\n\n");
break;
case ADD:
addContact(&con);
break;
case DEL:
delContact(&con);
break;
case SEARCH:
searchContact(&con);
break;
case SHOW:
showContact(&con);
break;
case MODIFY:
modifyContact(&con);
break;
default:
printf("input error\n\n");
break;
}
} while (input);
return 0;
}
2.通讯录结构体
以下代码就可以实现最简单的功能。
代码如下(示例):
struct Info
{
char name[20];
int age;
char tel[20];
};
但是上面的代码也有缺点,比如无法得知当前通讯录中已经存放的信息个数,如果名字或电话的最大长度超过20需要大量修改代码等等,所以可将其优化为下面的代码。
代码如下(示例):
#define NAME_MAX 20
#define TEL_MAX 14
#define MAX 1000
struct Info
{
char name[NAME_MAX];
int age;
char tel[TEL_MAX];
};
struct Contact
{
struct Info a[MAX];
int sz;//存储当前通讯录中的信息个数
};
而要实现通讯录的动态增长就需要继续对struct Contuct改进。
代码如下(示例):
struct Contact
{
struct Info *a;//存放信息
int capacity;//通讯录存放的最大信息个数
int sz;//通讯录当前存放的信息个数
};
二、通讯录功能的实现
1.通讯录的初始化
在main函数中建立一个通讯录结构体后,首先需要对其进行初始化,否则可能出现难以预料的问题。
(这里要注意,想要通过函数修改主函数内变量的值,就需要传变量的地址,否则无法修改,之后的代码同理)
代码如下(示例):
#define DEFAULT_CAP 4//为便于修改使用宏定义定义capacity的初始值
void initContact(struct Contact* pc)
{
assert(pc);//检查pc是否为空指针
pc->sz = 0;
pc->a = (struct Info*)malloc(sizeof(struct Info)* DEFAULT_CAP);
if (pc->a == NULL)//检查动态开辟是否成功
{
printf("init error\n");
exit(1);
}
pc->capacity = DEFAULT_CAP;
}
2.添加信息
添加信息时要注意先检查当前通讯录是否已满,如果已满则需要扩容,否则直接添加。
代码如下(示例):
void addContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == pc->capacity)//通讯录已满
{
//以扩容二倍为例
pc->a = (struct Info*)realloc(pc->a, pc->capacity * 2 *(sizeof(struct Info)));
if (pc->a == NULL)
{
printf("add1 error\n");
return;
}
else
{
printf("add1 success\n");
pc->capacity *= 2;//注意扩容成功后修改pc->capacity
}
}
//在控制台依次给出输入提示并录入数据
printf("name:");
scanf("%s", pc->a[pc->sz].name);
printf("age:");
scanf("%d", &(pc->a[pc->sz].age));
printf("tel:");
scanf("%s", pc->a[pc->sz].tel);
pc->sz++;//当前通讯录中的信息个数+1
printf("add success\n\n");
}
3.删除信息
删除信息时首先要输入要删除信息的姓名,然后找到这个信息再删除。由于这里通过名字来定位信息的代码在之后也会多次用到,所以这里将它封装为函数来调用,这样可以让代码更加简洁,同时可读性更好。
代码如下(示例):
//由于查找不需要修改,所以用const保护pc的内容
int FindByName(const struct Contact* pc, char name[])
{
int i = 0;
//遍历寻找信息
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->a[i].name, name) == 0)
return i;
}
return -1;//找不到返回-1
}
void delContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == 0)//判断通讯录是否为空
printf("empty\n\n");
else
{
printf("name:");
char name[NAME_MAX];
scanf("%s", name);//从控制台输入要删除信息的名字
int pos = FindByName(pc, name);//找到该信息的位置
if (pos == -1)//找不到直接返回
{
printf("delete error\n");
return;
}
int i = 0;
//从pos开始,将后面的信息依次向前挪一位(删除pos位置的数据)
for (i = pos; i < pc->sz - 1; i++)
{
pc->a[i] = pc->a[i + 1];
}
pc->sz--;//注意pc->sz--
printf("del success\n\n");
}
}
4.查找信息
查找时可以借用FindByName函数来实现。
代码如下(示例):
//加const保护pc的内容
void searchContact(const struct Contact* pc)
{
assert(pc);
printf("name\n");
char name[NAME_MAX];
scanf("%s", name);//输入要查找信息的姓名
int pos = FindByName(pc, name);
if (pos == -1)
printf("no\n");
//找到后打印信息
else
{
printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
printf("%-15s%-5d%-20s\n", pc->a[pos].name, pc->a[pos].age, pc->a[pos].tel);
}
}
5.展示信息
展示信息时按照一定的格式打印,看起来更加美观。
代码如下(示例):
void showContact(const struct Contact* pc)
{
assert(pc);
printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-15s%-5d%-20s\n", pc->a[i].name, pc->a[i].age, pc->a[i].tel);
}
printf("\n");
}
6.修改信息
代码如下(示例):
void modifyContact(struct Contact* pc)
{
assert(pc);
printf("name\n");
char name[NAME_MAX];
scanf("%s", name);
int pos = FindByName(pc, name);//找到要修改信息的位置
if (pos == -1)
printf("no\n");
else
{
//依次录入修改后的内容
printf("name:");
scanf("%s", pc->a[pos].name);
printf("age:");
scanf("%d", &(pc->a[pos].age));
printf("tel:");
scanf("%s", pc->a[pos].tel);
printf("modify success\n\n");
}
}
7.销毁通讯录
代码如下(示例):
void DestroyContact(struct Contact* pc)
{
free(pc->a);
pc->a = NULL;
pc->capacity = 0;
pc->sz = 0;
}
三、完整代码
contact.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define NAME_MAX 20
#define TEL_MAX 14
#define MAX 1000
#define DEFAULT_CAP 4
struct Info
{
char name[NAME_MAX];
int age;
char tel[TEL_MAX];
};
struct Contact
{
struct Info *a;
int capacity;
int sz;
};
void initContact(struct Contact* pc);
void addContact(struct Contact* pc);
void delContact(struct Contact* pc);
void showContact(const struct Contact* pc);
void searchContact(const struct Contact* pc);
void modifyContact(struct Contact* pc);
void DestroyContact(struct Contact* pc);
contact.c
#include "contact.h"
void initContact(struct Contact* pc)
{
assert(pc);
pc->sz = 0;
pc->a = (struct Info*)malloc(sizeof(struct Info) * DEFAULT_CAP);
if (pc->a == NULL)
{
printf("init error\n");
exit(1);
}
pc->capacity = DEFAULT_CAP;
}
void addContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == pc->capacity)
{
pc->a = (struct Info*)realloc(pc->a, pc->capacity * 2 *(sizeof(struct Info)));
if (pc->a == NULL)
{
printf("add error\n");
return;
}
else
{
printf("add1 success\n");
pc->capacity *= 2;
}
}
printf("name:");
scanf("%s", pc->a[pc->sz].name);
printf("age:");
scanf("%d", &(pc->a[pc->sz].age));
printf("tel:");
scanf("%s", pc->a[pc->sz].tel);
pc->sz++;
printf("add success\n\n");
}
int FindByName(const struct Contact* pc, char name[])
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->a[i].name, name) == 0)
return i;
}
return -1;
}
void delContact(struct Contact* pc)
{
assert(pc);
if (pc->sz == 0)
printf("empty\n\n");
else
{
printf("name:");
char name[NAME_MAX];
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("delete error\n");
return;
}
int i = 0;
for (i = pos; i < pc->sz - 1; i++)
{
pc->a[i] = pc->a[i + 1];
}
pc->sz--;
printf("del success\n\n");
}
}
void showContact(const struct Contact* pc)
{
assert(pc);
printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-15s%-5d%-20s\n", pc->a[i].name, pc->a[i].age, pc->a[i].tel);
}
printf("\n");
}
void searchContact(const struct Contact* pc)
{
assert(pc);
printf("name\n");
char name[NAME_MAX];
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
printf("no\n");
else
{
printf("%-15s%-5s%-20s\n", "name", "age", "telephone");
printf("%-15s%-5d%-20s\n", pc->a[pos].name, pc->a[pos].age, pc->a[pos].tel);
}
}
void modifyContact(struct Contact* pc)
{
assert(pc);
printf("name\n");
char name[NAME_MAX];
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
printf("no\n");
else
{
printf("name:");
scanf("%s", pc->a[pos].name);
printf("age:");
scanf("%d", &(pc->a[pos].age));
printf("tel:");
scanf("%s", pc->a[pos].tel);
printf("modify success\n\n");
}
}
void DestroyContact(struct Contact* pc)
{
free(pc->a);
pc->a = NULL;
pc->capacity = 0;
pc->sz = 0;
}
test.c
#include "contact.h"
void menu()
{
printf("0.exit\n1.add\n2.del\n3.search\n4.modify\n5.show\n\n");
}
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW
};
int main()
{
int input = 0;
struct Contact con;
initContact(&con);
do
{
menu();
scanf("%d", &input);
switch (input)
{
case EXIT:
DestroyContact(&con);
printf("exit success\n\n");
break;
case ADD:
addContact(&con);
break;
case DEL:
delContact(&con);
break;
case SEARCH:
searchContact(&con);
break;
case SHOW:
showContact(&con);
break;
case MODIFY:
modifyContact(&con);
break;
default:
printf("input error\n\n");
break;
}
} while (input);
return 0;
}