前言
因为要做项目三答辩,所以要从众多的选题中找到一个相对简单的,于是就有了制作通讯录管理系统的意向。
准备
根据问题的描述,可以大致概括为结构体+文件读写+链表的操作。
题目要求如下:
问题描述:
设计“通讯录管理系统”使其具有数据插入、修改、删除、显示和查询等 功能。
数据包括:人名、工作单位、电话号码和E-mail地址。
功能要求
(1)可对记录中的姓名和电话号码进行修改。
(2)可增加或删除记录。
(3)可显示所有保存的记录。
(4)可按人名或电话号码进行查询。
(5)每个学生的信息包括:学号no, 姓名, 院系academic,专业major, 籍贯province,家庭地址address,电话phone等。使用结构体存取每个学生的 信息,多个学生的信息可以保存到结构体数组中。最好使用文本文件保存以往 的所有学生信息,添加、删除之后应更新该文本文件。程序运行后,应有一个 简单的操作界面。程序代码要求清晰可读,多加注释。
实施
首先定义一个嵌套结构体:
struct Message
{
char phone[10];
char address[50];
char email[50];
};
struct address
{
char name[20];
int no[10];
char academic[10];
char major[10];
char province[10];
struct Message message;
struct address *pnext;
};
为什么要用嵌套:因为整洁点…
为了方便,以链表的形式进行存储:
struct address *list(struct address *plast)
{
int len = 0;
struct address* pnew;
printf("请输入录入人数:");
scanf("%d", &len);
for (int i = 0; i < len; i++)
{
pnew = (struct address *)malloc (sizeof(struct address));
if (pnew == NULL)
{
printf("系统出错");
exit(1);
}
printf("输入第%d位人员的姓名,学号,院系,专业,籍贯,家庭住址,电话,邮箱:",i + 1);
scanf("%s %d %s %s %s %s %s %s",pnew->name,&pnew->no,pnew->academic,pnew->major,pnew->province,pnew->message.address,pnew->message.phone,pnew->message.email);
plast->pnext = pnew;
pnew->pnext = NULL;
plast = pnew;
}
return plast;
}
其中,用malloc为每个节点分配空间,采用尾插法连接链表,将plast
指向的节点的pnext
字段设置为pnew
,然后将pnew
的pnext
字段设置为NULL
,表示这是链表的最后一个节点。
再遍历下打印下链表
void traversal(struct address *phead)
{
struct address *p;
p = phead->pnext;
printf("姓名\t学号\t院系\t专业\t籍贯\t家庭住址\t电话\t邮箱\n");
while (p != NULL)
{
printf("%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n",p->name,p->no,p->academic,p->major,p->province,p->message.address,p->message.phone,p->message.email);
p = p->pnext;
}
}
写个主函数和界面测试一下
void printf_body()
{
printf("\n通讯录管理系统\n");
printf("1. 添加信息\n");
printf("2. 修改信息\n");
printf("3. 删除信息\n");
printf("4. 显示所有记录\n");
printf("5. 查询记录\n");
printf("6. 退出\n");
}
int main()
{
int choice = 1;
struct address *plast,*phead = NULL; //防止野指针
phead = (struct address *)malloc (sizeof(struct address)); //分配空间
if (phead == NULL) //判断分配是否成功
{
printf("出错,请重试");
exit(-1);
}
phead ->pnext = NULL;
plast = phead;
while (choice != 0)
{
printf_body();
printf("请输入你的选择:");
scanf("%d",&choice);
switch (choice)
{
case 1:
plast = list(plast);
traversal(phead);
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 0:
printf("再见");
break;
default:
printf("出错,请输入有效数字");
break;
}
开始写查询模块,要考虑到用人名或电话号码来查询信息:
void search_name(struct address *phead)
{
struct address *p;
char name_i[20];
p = phead;
printf("输入查询的姓名:");
scanf("%s",name_i);
while (strcmp(p->name,name_i) != 0 && p->pnext != NULL)
{
p = p->pnext;
}
if (strcmp(p->name,name_i) == 0)
{
printf("找到如下信息:\n");
printf("姓名\t学号\t院系\t专业\t籍贯\t家庭住址\t电话\t邮箱\n");
printf("%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n",p->name,p->no,p->academic,p->major,p->province,p->message.address,p->message.phone,p->message.email);
}
else
{
printf("未找到信息\n");
}
}
void search_phone(struct address *phead)
{
struct address *p;
char phone_i[20];
p = phead;
printf("输入查询的电话:");
scanf("%s",phone_i);
while (strcmp(p->message.phone,phone_i) != 0 && p->pnext != NULL)
{
p = p->pnext;
}
if (strcmp(p->message.phone,phone_i) == 0)
{
printf("找到如下信息:\n");
printf("姓名\t学号\t院系\t专业\t籍贯\t家庭住址\t电话\t邮箱\n");
printf("%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n",p->name,p->no,p->academic,p->major,p->province,p->message.address,p->message.phone,p->message.email);
}
else
{
printf("未找到信息\n");
}
}
主函数修改一下:
case 5:
printf("请输入查询方式:");
printf("\n1.按姓名查询");
printf("\n2.按电话号码查询\n");
int choose = 0;
scanf("%d",&choose);
if (choose == 1)
{
search_name(phead);
}
else if (choose == 2)
{
search_phone(phead);
}
else
{
printf("请输入有效数字\n");
break;
}
system("pause");
break;
再来写个修改函数模块:
void modify(struct address *phead)
{
struct address *p;
char name_i[20];
printf("请输入你要修改的人的姓名:");
scanf("%s",name_i);
p = phead->pnext;
while (p != NULL){
if(strcmp(p->name,name_i) == 0) //strcmp会返回0,所以与0比较如果相同就进行操作
{
printf("请输入新的姓名和电话:");
scanf("%s %s",p->name,p->message.phone);
printf("修改成功!");
return;
}
p = p->pnext;
}
printf("未找到此人,请重试");
}
因为题目只让修改姓名和电话号码,就改俩好了。
接着就是删除函数:
struct address *delete(struct address *phead,struct address *plast) //通过返回struct address*类型,函数可以返回更新后的尾节点指针plast
{
struct address *p,*pre;
p = phead;
char name_i[20];
printf("请输入要删除的人员姓名:");
scanf("%s",name_i);
pre = phead;
p = phead->pnext;
while (p != NULL && strcmp(p->name,name_i) != 0){
pre = p;
p = p->pnext;
}
if (p != NULL)
{
pre->pnext = p->pnext;
if (p == plast)
{
plast = pre;
}
free(p);
printf("删除成功!\n");
}
else
{
printf("未找到人员\n");
}
return plast;
}
然后就是读取和写入:
void save(struct address *phead)
{
FILE* file = fopen("address.txt","a");
struct address *p;
p = phead;
if (file == NULL)
{
printf("出错!");
return;
}
while (p != NULL)
{
p = p->pnext;
fwrite(p,sizeof(struct address),1,file);
}
fclose(file);
printf("保存成功!");
}
void read(void)
{
FILE* file = fopen("address.txt","r");
struct address txt;
if (file == NULL)
{
printf("出错!");
return;
}
printf("姓名\t学号\t院系\t专业\t籍贯\t家庭住址\t电话\t邮箱\n");
while (fread(&txt, sizeof(struct address), 1, file) == 1)
{
printf("%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\n",txt.name,txt.no,txt.academic,txt.major,txt.province,txt.message.address,txt.message.phone,txt.message.email);
}
if(feof(file))
{
printf("读取完毕");
}
fclose(file);
}
完成。
主函数部分:
if (phead == NULL)
{
printf("出现错误!");
exit(-1);
}
phead ->pnext = NULL;
plast = phead;
while (choice != 0)
{
printf_body();
printf("请输入你的选择:");
scanf("%d",&choice);
switch (choice)
{
case 1:
plast = list(plast);
traversal(phead);
system("pause") ;
break;
case 2:
modify(phead);
system("pause") ;
break;
case 3:
delete(phead,phead);
system("pause") ;
break;
case 4:
save(phead);
system("pause") ;
break;
case 5:
read();
system("pause") ;
break;
case 6:
printf("请输入查询方式:");
printf("\n1.按姓名查询");
printf("\n2.按电话号码查询\n");
int choose = 0;
scanf("%d",&choose);
if (choose == 1)
{
search_name(phead);
}
else if (choose == 2)
{
search_phone(phead);
}
else
{
printf("请输入有效数字\n");
break;
}
system("pause");
break;
case 0:
printf("再见");
break;
default:
printf("出错,请输入有效数字");
break;
}
}
}
注意:仅限c语言,c++环境编译需要更改delete与switch(比如DEV C++)