模拟实现通讯录的功能,主要功能包括增加联系人信息、删除联系人信息、修改联系人信息、查找联系人、对现有联系人排序、清空联系人和显示所有联系人信息这七大功能块。
需利用结构体嵌套的思想去定义通讯录的结构,将联系人的信息包括姓名、街道、城市、邮编、国家等保存在一个自定义结构体类型,在将自定义的联系人信息类型嵌套使用在自定义通讯录结构体类型中实现多个联系,为合理使用通讯录的存储空间采用柔性数组设计一个变长的通讯录顺序表。,代码如下:
#ifndef _CONTACT_H_
#define _CONTACT_H_
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <errno.h>
#include <string.h>
#define NAME_SIZE 64
#define TELE_SIZE 16
#define ELP_SIZE 16
#define STATE_SIZE 16
#define ADDRESS_SIZE 128
#define LIST_DEFAULT 5
#define INC_SIZE 2
#define CT_FILE "contact.bin"
typedef struct Person{
char name[NAME_SIZE];
char elp[ELP_SIZE];
char state[STATE_SIZE];
char street[NAME_SIZE];
char city[ADDRESS_SIZE];
}person,*person_p,**person_pp;
typedef struct Contact{
int cap;
int size;
person contact[0];
}contact,*contact_ct;
int InitContactFile(contact **ct, FILE *fp);
void InitContactDefault(contact **ct);
void AddList(contact_ct ct);
void DeletList(contact_ct ct);
void CheckList(contact_ct ct);
void AlterList(contact_ct ct);
void ShowList(contact_ct ct);
void ClearList(contact_ct ct);
void SortList(contact_ct ct);
void DesList(contact_ct ct);
void Menue();
void Save(contact_ct ct);
int Load(contact **ct);
#endif
将每一个功能封装成一个函数体,具体实现如下:
1:初始化通讯录,分为两种情况,第一次使用通讯录时即当保存通讯录的本地文件不存在或为空时,初始化方法是为通讯录申请空间进行操作,当保存通讯录的文件不为空时,从本地文件中获取通讯录的数据恢复至当前通讯录中,并根据文件中通讯录存储联系人的数目为通讯录申请空间。代码如下:
/初始化通讯录文件
int InitContactFile(contact **ct,FILE *fp){
contact_ct ct_p = (contact_ct)malloc(sizeof(contact));
if (ct_p){
fread(ct_p, sizeof(contact), 1, fp);//第一部分从fp中读通讯录头部包括通讯录的容量和现有联系人个数的大小到ct_p中。
int _cap = ct_p->cap;
int size = sizeof(contact)+ct_p->cap*sizeof(person);
contact_ct p = (contact_ct)realloc(ct_p, size);//进行扩容,扩容大小为通讯录头部大小+通讯录所保存的用户个数cap
if (p){
ct_p = p;
fread(ct_p->contact, ct_p->cap*sizeof(person), 1, fp);//第二部分从fp中读通讯录cap个联系人的信息到ct_p->contact中。
*ct = ct_p;
return 1;//数据分两部分从文件中读取,数据恢复成功。
}
else{
return 0;
}
}
else{
return 0;
}
}
//打开文件失败或第一次打开通讯录文件时使用该方法初始化通讯录
void InitContactDefault(contact **ct){
*ct = malloc(sizeof(contact)+sizeof(person)*LIST_DEFAULT);//首次为通讯录申请空间
if (NULL == *ct){
printf("%s:%d", strerror(errno), errno);
exit(1);
}
(*ct)->cap = LIST_DEFAULT;
(*ct)->size = 0;
printf("Init Conact Success!\n");
}
//程序的入口
int Load(contact **ct){
FILE *fp = fopen(CT_FILE, "rb");//打开文件
if (NULL == fp){//打开文件失败或第一次使用该通讯录
printf("Init Contact Default!\n");
InitContactDefault(ct);
return 1;
}
int ret = InitContactFile(ct, fp);//从本地文件中恢复信息到通讯录中
fclose(fp);//关闭文件啊
return ret;
}
2:添加联系人,动态的为通讯录申请空间当前通讯录容量以满时,需实现动态扩容。使用内存函数。代码如下:
//添加联系人
void AddList(contact_ct *cp){
if (!Isfull(*cp) || Inc(cp)){//或的特点当第一个条件为真时不判断第二个条件,当第一个条件为假时才判断第二个条件
person_p a=&((*cp)->contact[(*cp)->size]);
printf("Please Enter Name:");
scanf("%s", a->name);
printf("Please Enter Elp:");
scanf(" %s", a->elp);//sacnf前置空格防止回车被下一个scanf输入。
printf("Please Enter State:");
scanf(" %s", a->state);
printf("Please Enter Street:");
scanf(" %s", a->street);
printf("Please Enter City:");
scanf(" %s", a->city);
((*cp)->size)++;
}
else{
printf("realloc error!\n");
return;
}
}
//判断该通讯录是否满
}static int Isfull(contact_ct ct){
return ct->size == ct->cap ? 1 : 0;
}
//对已满的通讯录进行扩容
static int Inc(contact_ct *cp){
int new_size = sizeof(contact)+((*cp)->cap + INC_SIZE)*sizeof(person);//扩容的大小为原来数组的大小加上增加的数组长度
contact_ct c = realloc(*cp, new_size);
if (!c){
printf("Inc error!\n");
return 0;
}
c->cap = (*cp)->cap + INC_SIZE;
*cp = c;
printf("Inc success!\n");
return 1;
}
3:查找联系人:
void CheckList(contact_ct ct){
char per[NAME_SIZE];
printf("Please enter contact information to find:\n");
scanf("%s", per);
int i = 0;
int flag = 1;
for (i = 0; i <= ct->size; i++)
if (!(strcmp(ct->contact[i].name, per))){
printf("name:%s elp:%s state:%s street:%s city:%s\n", ct->contact[i].name, ct->contact[i].elp, ct->contact[i].state, ct->contact[i].street, ct->contact[i].city);
flag = 0;
printf("Check!\n");//已找到联系人
}
if (flag){
printf("Not Exit!\n");//联系人不存在
}
}
4:删除联系人:
void DeletList(contact_ct ct){
char per[NAME_SIZE];
printf("Please enter contact information to delet:\n");
scanf("%s", per);
int i = 0;
int flag = 1;
int j = 0;
while (flag){
for (i = 0; i <= ct->size; i++){
if (!(strcmp(ct->contact[i].name, per))){
for (j = i; j < ct->size; j++){
ct->contact[j] = ct->contact[j + 1];
}
ct->size--;
printf("Delet\n");//联系人删除成功
flag = 0;
}
}
if (flag){//联系人不存在
printf("Not exit!Failure\n");
flag = 0;
}
}
}
5:修改联系人信息:
//修改当前联系人信息
void AlterList(contact_ct ct){
char per[NAME_SIZE];
printf("Please enter contact information to alter:\n");
scanf("%s", per);
int i = 0;
int flag = 1;
for (i = 0; i <= ct->size; i++){
if (!(strcmp(ct->contact[i].name, per))){
printf("Please enter modified contact information:\n");
printf("Please Enter Name:");
scanf("%s", ct->contact[i].name);
printf("Please Enter Elp:");
scanf(" %s", ct->contact[i].elp);
printf("Please Enter State:");
scanf(" %s", ct->contact[i].state);
printf("Please Enter Street:");
scanf(" %s", ct->contact[i].street);
printf("Please Enter City:");
scanf(" %s", ct->contact[i].city);
flag = 0;
printf("Alter!\n");//修改成功
}
}
if (flag){
printf("Contact person not exit!\n");//联系人不存在无法修改
}
}
6:清空联系人:
//清空联系人
void ClearList(contact_ct ct){
ct->size=0;
}
7:采用快排的思想对当前联系人按照名字进行排序:
static int person_cmp(const void *x, const void *y){
person_p _x = (person_p)x;
person_p _y = (person_p)y;
return strcmp(_x->name, _y->name);
}
//利用快排实现按照联系人名字排序
void SortList(contact_ct ct){
person_p p = ct->contact;
qsort(p, ct->size, sizeof(person), person_cmp);
}
8:显示所有联系人信息:
//显示所有联系人信息
void ShowList(contact_ct ct){
if (ct->size == 0){
printf("Contact book is empty.please enter information first\n");
}
else{
int i = 0;
for (i = 0; i < ct->size; i++){
printf("name:%s elp:%s state:%s street:%s city:%s\n", ct->contact[i].name, ct->contact[i].elp, ct->contact[i].state, ct->contact[i].street, ct->contact[i].city);
printf("\n");
}
}
}
9:保存当前通讯录信息至本地文件:
//将每次写进通信录中的有效信息保存在本地文件中。
void Save(contact_ct ct){
FILE *fp = fopen(CT_FILE, "wb");//打开文件
if (NULL == fp){//打开文件失败
printf("fopen error!\n");
return;
}
int size = sizeof(contact)+ct->cap*sizeof(person);//通讯录本身的大小+通讯录所存储有效用户大小
fwrite(ct, size, 1, fp);//写入时需确定有几个字节,确定基本单位大小,而一个单位的大小就是整个通讯录即size。
fclose(fp);//关闭文件
}
将所有功能以索引的形式呈现给用户,当用户选择某一索引时,就执行当前索引对应的函数体。在用户选择退出时同时将通讯录中的信息保存到本地文件中:代码如下:
//菜单,选择执行操作
void Menue(){
printf("____________________________\n");
printf(" 1.Show | 2.Delet \n");
printf(" 3.Alter | 4.Check \n");
printf(" 5.Add | 6.Clear \n");
printf(" 7.Sort | 8.Exit \n");
printf("____________________________\n");
printf("Please enter your choice:\n");
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"
int main(){
contact_ct ct;
volatile int quit = 0;
int select = 0;
Load(&ct);//每次运行程序时先判断按哪种方式初始化通讯录
while (!quit){
Menue();
scanf("%d", &select);
switch (select){
case 1:
ShowList(ct);
break;
case 2:
DeletList(ct);
break;
case 3:
AlterList(ct);
break;
case 4:
CheckList(ct);
break;
case 5:
AddList(&ct);
break;
case 6:
ClearList(ct);
break;
case 7:
SortList(ct);
break;
case 8:
Save(ct);
quit = 1;
break;
default:
break;
}
}
system("pause");
return 0;
}
以上程序即可简单的模拟通讯录的功能。