1、功能要求
制作一个电子通讯录,通过该通讯录能存入好友 ID 号、姓名(英文)、手机号码、家庭住址、公司电话。
I、 主界面:主要显示软件功能
A) 添加好友信息。
B) 列表好友信息。(包含排序功能)
C) 搜索好友
D) 删除好友
II、添加好友:
用户输入 “1” 命令后,让用户输入好友信息。添加成功或失败都需要提示
用户
III、 列表好友:
用户输入 “2” 命令后,好友信息升序排列。
IV、搜索好友:
用户输入 “3” 命令后,让用户输入将要搜索好友姓名查询。如果未搜索到
请友好提示。如果搜索到,显示出该好友信息。
V、删除好友:
用户输入 “4” 命令后,让用输入将要删除好友姓名删除,如果存在同名的多个好友,则列表出,所有同名的好友信息,让用户通过输入ID 号删除。提示用
户删除成功。
2、程序文件
I、
在电子通讯录(自存储)/src目录下新建main.c、Contact.c文件
// main.c
#include <stdio.h>
// 包含open函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Contact.h"
int main()
{
// 创建链表
List *ls = CreateList();
if (NULL == ls)
{
printf ("创建失败\n");
return -1;
}
// 打开文件
BYTE_4 fd = open("Contact", O_RDWR | O_CREAT | O_APPEND, 0766);
if (-1 == fd)
{
perror("打开Contact文件失败");
return -1;
}
// 判断Contact文件是否为空,并进行相应操作
Empty_File(ls, fd);
// 显示主菜单,并进行相应操作
Menu(ls);
// 退出前判断链表是否为空,并进行相应操作
myWrite(ls, fd);
Destory(ls);
close(fd);
return 0;
}
// contact.c
#include <stdio.h>
// 包含malloc()、system("clear")
#include <stdlib.h>
// 包含strcmp()
#include <string.h>
// 包含read、write函数
#include <unistd.h>
// 包含ftruncate函数
#include <sys/types.h>
#include "Contact.h"
// 创建链表
List *CreateList(void)
{
List *ls = (List*)malloc(sizeof(List)/sizeof(char));
if (NULL == ls)
{
return NULL;
}
ls->head = (Node*)malloc(sizeof(Node)/sizeof(char));
if (NULL == ls->head)
{
free(ls);
return NULL;
}
ls->head->next = NULL;
return ls;
}
// 初始运行前判断Contact文件是否为空,并进行相应操作
void Empty_File(List *ls, BYTE_4 fd)
{
// 将文件指针定位到结尾的地方,以判断是否为空文件
// 当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。
off_t ret_last = lseek(fd, 0, SEEK_END);
if (-1 == ret_last)
{
perror("文件指针定位失败");
return;
}
if (ret_last > 0)
{
// 将文件中数据导入链表
file_to_contact(fd, ls);
}
return;
}
// 将文件中数据导入链表
void file_to_contact(BYTE_4 fd, List *ls)
{
if (NULL == ls)
{
return;
}
// 指向文件开头
off_t ret = lseek(fd, 0, SEEK_SET);
if (-1 == ret)
{
perror("文件指针定位失败");
return;
}
BYTE_4 ret_tmp = 0;
BYTE_4 id;
// 不指向文件末尾时就将文件中的数据导入到链表中
while((ret_tmp = read(fd, &id, sizeof(BYTE_4))) != 0)
{
Node *node = (Node *)malloc(sizeof(Node)/sizeof(BYTE_1));
if (NULL == node)
{
return;
}
// 如果返回0,表示已到达文件尾或无可读取的数据。错误返回-1,并将根据不同的错误原因适当的设置错误码。
// 读文件中ID号、姓名、手机号码、家庭住址、公司,并将其写入链表
// ssize_t ret_id = read(fd, &node->id, sizeof(BYTE_4));
node->id = id;
ssize_t ret_name = read(fd, node->name, 10*sizeof(BYTE_1));
ssize_t ret_mobilephone = read(fd, &node->mobilephone, sizeof(BYTE_8));
ssize_t ret_homeaddress = read(fd, node->homeaddress, 20*sizeof(BYTE_1));
ssize_t ret_businessnumber = read(fd, &node->businessnumber, sizeof(BYTE_8));
node->next = NULL;
Node *tmp = ls->head;
while (tmp->next)
{
tmp = tmp->next;
}
tmp->next = node;
}
// 清空文件
ftruncate(fd, 0);
return;
}
// 主界面的显示
BOOL Menu(List *ls)
{
if (NULL == ls)
{
return ERROR;
}
system ("clear");
BYTE_1 buf[10];
// search_flag = 1时,搜索不成功!
BYTE_4 search_flag = 1;
// delete_flag = 1时,删除不成功!
BYTE_4 delete_flag = 1;
while (1)
{
printf ("\n \n \n \n \n \n \n \n");
printf ("\t\t\t\t\t\t**************************************************\n");
printf ("\t\t\t\t\t\t* *\n");
printf ("\t\t\t\t\t\t*\t\t 0.退出 *\n");
printf ("\t\t\t\t\t\t*\t\t 1.添加好友 *\n");
printf ("\t\t\t\t\t\t*\t\t 2.列表好友 *\n");
printf ("\t\t\t\t\t\t*\t\t 3.搜索好友 *\n");
printf ("\t\t\t\t\t\t*\t\t 4.删除好友 *\n");
printf ("\t\t\t\t\t\t* *\n");
printf ("\t\t\t\t\t\t**************************************************\n");
printf ("\n\t\t\t\t\t\t请输入指令:");
// fgets(buf, 10, stdin); ==>改用这条指令有问题,暂未解决
scanf ("%s", buf);
// 退出、增、显、查、删
switch (buf[0])
{
case ADD:
Add_Contact(ls);
break;
case DISPLAY:
Display_Contact(ls);
break;
case SEARCH:
// search_flag = 1时,搜索不成功!
// 搜索成功,返回0
while (1 == search_flag)
{
search_flag = Search_Contact(ls);
}
search_flag = 1;
break;
case DELETE:
// delete_flag = 1时,不成功!
// 删除成功,返回0
while (1 == delete_flag)
{
delete_flag = Delete_Contact(ls);
}
delete_flag = 1;
break;
case QUIT:
// 清屏
system("clear");
return;
default:
printf ("\t\t\t\t\t\t输入指令有误,请重新输入!");
sleep(1);
system("clear");
break;
}
}
}
// 添加好友信息、尾插
BOOL Add_Contact(List *ls)
{
if (NULL == ls)
{
return ERROR;
}
// 清屏
system("clear");
Node *node = (Node *)malloc(sizeof(Node)/sizeof(BYTE_1));
if (NULL == node)
{
return ERROR;
}
// flag = 1 添加成功 flag = 0 添加失败
BYTE_4 flag = 0;
printf ("\n \n \n \n \n \n \n \n");
printf ("\t\t\t\t\t\t\t请输入好友ID号:");
scanf ("%d", &node->id);
printf ("\t\t\t\t\t\t\t请输入好友姓名:");
scanf ("%s", node->name);
printf ("\t\t\t\t\t\t\t请输入好友手机号码:");
scanf ("%lld", &node->mobilephone);
printf ("\t\t\t\t\t\t\t请输入好友家庭住址:");
scanf ("%s", node->homeaddress);
printf ("\t\t\t\t\t\t\t请输入好友公司电话:");
scanf ("%lld", &node->businessnumber);
node->next = NULL;
// 头结点
Node *tmp = ls->head;
// 作表达式时,取指针变量中存放的地址值
while (tmp->next)
{
tmp = tmp->next;
}
tmp->next = node;
flag = 1;
// 清屏
// system("clear");
if (1 == flag)
{
printf ("\n");
printf ("\t\t\t\t\t\t\t好友信息添加成功!\n");
sleep(1);
system("clear");
}
else
{
printf ("\t\t\t\t\t\t好友信息添加失败!\n");
}
return TRUE;
}
// 列表好友信息
BOOL Display_Contact(List *ls)
{
if (NULL == ls)
{
return ERROR;
}
if (NULL == ls->head->next)
{
printf ("\t\t\t\t\t\t您暂未添加联系人!");
sleep(1);
system("clear");
return TRUE;
}
system("clear");
// 冒泡排序:按ID从小到大
Sort(ls);
printf("\n\t\t\t\t\tID号\t姓名\t手机号码\t\t家庭住址\t\t公司电话\n");
Node *tmp = ls->head->next;
while (tmp)
{
printf ("\t\t\t\t\t%-4d\t", tmp->id);
printf ("%-4s\t", tmp->name);
printf ("%-13lld\t\t", tmp->mobilephone);
printf ("%-10s\t\t", tmp->homeaddress);
printf ("%-13lld\n", tmp->businessnumber);
tmp = tmp->next;
}
}
// 冒泡排序
BOOL Sort(List *ls)
{
if((ls->head -> next == NULL) || (ls->head->next->next == NULL))
{
return ERROR;
}
Node *pre, *cur, *next, *end, *temp;
Node *tmp = ls->head;
end = NULL;
// 从链表头开始将较大值往后沉
while(tmp->next != end)
{
for(pre = tmp, cur = pre->next, next = cur->next;
next != end;
pre = pre->next, cur = cur->next, next = next->next)
{
// 相邻的节点,按id进行比较
if(cur->id > next->id)
{
cur->next = next->next;
pre->next = next;
next->next = cur;
temp = next;
next = cur;
cur = temp;
}
}
end = cur;
}
}
// 搜索好友:按姓名
BYTE_4 Search_Contact(List *ls)
{
if (NULL == ls)
{
return -1;
}
// 清屏
system("clear");
BYTE_1 Name[10];
printf ("\n \n \n \n \n \n \n \n");
printf ("\t\t\t\t\t\t\t请输入您想查找的好友的姓名:");
scanf ("%s", Name);
// tmp相当于头结点
Node *tmp = ls->head;
while (tmp->next)
{
if (0 == strcmp(tmp->next->name, Name))
{
system("clear");
printf ("\t\t\t\t\t\t您所搜索的好友的信息如下:\n\n");
printf ("\t\t\t\t\t\tID号:%d\n", tmp->next->id);
printf ("\t\t\t\t\t\t姓名:%s\n", tmp->next->name);
printf ("\t\t\t\t\t\t手机号码:%lld\n", tmp->next->mobilephone);
printf ("\t\t\t\t\t\t家庭住址:%s\n", tmp->next->homeaddress);
printf ("\t\t\t\t\t\t公司电话:%lld\n", tmp->next->businessnumber);
return 0;
}
tmp = tmp->next;
}
printf ("\t\t\t\t\t\t\t您所搜索的姓名为 %s 的好友不存在!\n", Name);
printf ("\t\t\t\t\t\t\t请再次输入您想查找的好友的姓名!");
sleep(1);
system("clear");
return 1;
}
// 删除好友:按姓名
// 姓名相同,再按ID删除
BYTE_4 Delete_Contact(List *ls)
{
if (NULL == ls)
{
return -1;
}
// 统计姓名相同的人数
BYTE_4 count = 0;
BYTE_4 Id;
BYTE_1 Name[10];
system("clear");
printf ("\n \n \n \n \n \n \n \n");
printf ("\t\t\t\t\t\t请输入您想删除的好友的姓名:");
scanf ("%s", Name);
Node *tmp = ls->head;
// 初始:头结点中存的地址值
while (tmp->next)
{
if (0 == strcmp(tmp->next->name, Name))
{
count++;
}
tmp = tmp->next;
}
// tmp回位
tmp = ls->head;
if (0 == count)
{
system("clear");
printf ("\t\t\t\t\t\t您所删除的姓名为 %s 的好友不存在!\n", Name);
printf ("\t\t\t\t\t\t请再次输入您想删除的好友的姓名!");
sleep(1);
return 1;
}
// 姓名不重复时,直接删除!
while (1 == count)
{
while (tmp->next)
{
if (0 == strcmp(tmp->next->name, Name))
{
Node *p = tmp->next;
tmp->next = p->next;
free(p);
printf ("\t\t\t\t\t\t删除成功!");
sleep(1);
system("clear");
return 0;
}
tmp = tmp->next;
}
}
// 姓名重复时,按ID删除
while(count > 1)
{
printf ("\t\t\t\t\t\t姓名为 %s 的好友共有 %d 人,其信息如下:\n\n", Name, count);
printf ("\t\t\t\t\t\tID号\t姓名\t手机号码\t\t家庭住址\t\t公司电话\n");
while (tmp->next)
{
if (0 == strcmp(tmp->next->name, Name))
{
printf ("\t\t\t\t\t\t%-4d\t", tmp->next->id);
printf ("%-4s\t", tmp->next->name);
printf ("%-13lld\t\t", tmp->next->mobilephone);
printf ("%-10s\t\t", tmp->next->homeaddress);
printf ("%-13lld\n", tmp->next->businessnumber);
}
tmp = tmp->next;
}
// tmp回位
tmp = ls->head;
printf ("\n");
printf ("\t\t\t\t\t\t请输入您想删除的好友的ID:");
scanf ("%d", &Id);
while (tmp->next)
{
if (tmp->next->id == Id)
{
Node *p = tmp->next;
tmp->next = p->next;
free(p);
system("clear");
printf ("\t\t\t\t\t\t删除成功!\n");
return 0;
}
tmp = tmp->next;
}
}
return FALSE;
}
// 退出前判断链表是否为空,并进行相应操作
void myWrite(List *ls, BYTE_4 fd)
{
if (NULL == ls)
{
return;
}
// 判断是否为空链表,为空链表直接退出,不用执行写入
if (NULL == ls->head->next)
{
return;
}
// O_APPEND:每次写之前,将标志位移动到文件的末端。
// fd:文件描述符
Node *tmp = ls->head->next;
while(tmp)
{
// 写入ID号、姓名、手机号码、家庭住址、公司
ssize_t ret_id = write(fd, &tmp->id, sizeof(BYTE_4));
ssize_t ret_name = write(fd, tmp->name, 10*sizeof(BYTE_1));
ssize_t ret_mobilephone = write(fd, &tmp->mobilephone, sizeof(BYTE_8));
ssize_t ret_homeaddress = write(fd, tmp->homeaddress, 20*sizeof(BYTE_1));
ssize_t ret_businessnumber = write(fd, &tmp->businessnumber, sizeof(BYTE_8));
tmp = tmp->next;
}
}
// 销毁
void Destory(List *ls)
{
if (NULL == ls)
{
return;
}
Node *tmp = ls->head;
while (tmp->next)
{
Node *p = tmp->next;
tmp->next = p->next;
free(p);
}
free(ls->head);
free(ls);
}
II、
在电子通讯录(自存储)/include目录下创建Contact.h文件
// Contact.h
#ifndef _CONTACT_H_
#define _CONTACT_H_
// 退出、增、显、查、删
enum menu{QUIT = '0', ADD, DISPLAY, SEARCH, DELETE};
typedef enum {TRUE, FALSE, ERROR} BOOL;
typedef char BYTE_1;
typedef int BYTE_4;
typedef long long BYTE_8;
// 每一个结点中应包含一个指针变量,用它来存放下一结点的地址
typedef struct _node
{
// 数据域
BYTE_4 id;// ID号
BYTE_1 name[10];// 姓名
BYTE_8 mobilephone;// 手机号码
BYTE_1 homeaddress[20];// 家庭住址
BYTE_8 businessnumber;// 公司电话
// 指针域
struct _node *next;
}Node;
typedef struct _list
{
// 头节点
Node *head;
}List;
// 创建链表
List *CreateList(void);
// 初始运行前判断Contact文件是否为空,并进行相应操作
void Empty_File(List *ls, BYTE_4 fd);
// 将文件中数据导入链表
void file_to_contact(BYTE_4 fd, List *ls);
// 主界面的显示
BOOL Menu(List *ls);
// 添加好友信息、尾插
BOOL Add_Contact(List *ls);
// 列表好友信息
BOOL Display_Contact(List *ls);
// 冒泡排序
BOOL Sort(List *ls);
// 搜索好友:按姓名
BYTE_4 Search_Contact(List *ls);
// 删除好友:按姓名
BYTE_4 Delete_Contact(List *ls);
// 退出前判断链表是否为空,并进行相应操作
void myWrite(List *ls, BYTE_4 fd);
// 销毁
void Destory(List *ls);
#endif // _CONTACT_H
III、在电子通讯录(自存储)目录下新建Makefile文件
src1 = $(wildcard ./src/*.c)
obj1 = $(patsubst ./src/%.c, ./obj/%.o, $(src1))
target = ./bin/a.out
all:$(target)
$(target):$(obj1)
gcc $(^) -o $(@)
$(obj1):./obj/%.o:./src/%.c
gcc -c $(^) -I ./include -o $(@) -g
.PHONY:clean all
clean:
-rm -rf $(target) $(obj1)
3、测试结果
略