C语言 顺序表实现通讯录【完全版】 含文件版本fwrite、fread和fscanf和fprintf的使用

通讯录需要具备的功能:

1.新增联系人

2.查找联系人

3.删除联系人

4.修改联系人

5.显示联系人

6.通讯录排序(年龄、姓名)

7.销毁通讯录

8.保存通讯录

目录

一、创建结构体

二、添加联系人

三、检查容量

四、删除联系人

五、查找联系人

六、修改联系人

七、排序

八、显示联系人

九、销毁

十、保存通讯录

10.1 fprintf版本

10.2 fwrite版本

十一、文件读到内存

11.1 fscanf版本


一、创建结构体

首先我们需要构建一个结构体,用来保存通讯录的基本信息:

#define MAX_Name 20
#define MAX_Sex 5
#define MAX_Address 20
#define MAX_People 100
struct PeopleInfo
{
    char name[MAX_Name];
    char sex[MAX_Sex];
    int age;
    int telephone;
    char address[MAX_Address];
};
typedef struct Contact
{
    struct PeopleInfo* arr;
    //记录当前的人数
    int sz;
    //用来记录大小
    int capacity;
}Contact;

构建后,我们需要初始化结构体:

//动态
void ContactInit(Contact* con)
{
    con->arr=(struct PeopleInfo*)malloc(sizeof(struct PeopleInfo)*2);
    con->sz=0;
    con->capacity=2;
}
//静态
// void ContactInit(Contact* con)
// {
//     con->sz=0;
//     memset(con->arr,0,MAX_People*sizeof(struct PeopleInfo));
// }

二、添加联系人

构建后,我们就可以开始添加了,添加就是一个一个输入:

void ContactAdd(Contact* con)
{
    checkcapacity(con);
    printf("请输入姓名\n");
    scanf("%s",con->arr[con->sz].name);
    printf("请输入性别\n");
    scanf("%s",con->arr[con->sz].sex);
    printf("请输入年龄\n");
    scanf("%d",&con->arr[con->sz].age);
    printf("请输入电话号码\n");
    scanf("%d",&con->arr[con->sz].telephone);
    printf("请输入地址\n");
    scanf("%s",con->arr[con->sz].address);
    con->sz++;
}

三、检查容量

既然是动态的顺序表,那么我们就需要检查容量:

void checkcapacity(Contact* con)
{
    //当前个数和容量相等时意味着空间用完了,需要重新开辟
    if(con->capacity==con->sz)
    {
        con->capacity*=2;
        //先创建临时空间,以防开辟失败,导致原来的空间也消失了
        struct PeopleInfo* tmp=(struct PeopleInfo*)realloc(con->arr,con->capacity*sizeof(struct PeopleInfo));
        if(tmp!=NULL)
        {
        con->arr=tmp;
        }
        else
        {
            //开辟失败报错
            perror("checkcapacity:");
        }
    }
}

四、删除联系人

删除功能和这个类似,找到删除的位置,然后把后面一个位置给到前一个位置,这样删除的位置就没有了:

//查找位置
//加static可以让别的文件查不到这个自定函数
static int FindLocation(Contact* con,char* name)
{
    int i=0;
    for(i=0;i<con->sz;i++)
    {
        if(strcmp(con->arr[i].name,name)==0)
        {
            return i;
        }
    }
    return -1;
}
void ContactDelete(Contact* con)
{
    printf("请输入要删除人的姓名\n");
    char name[MAX_Name];
    scanf("%s",name);
    int ret=FindLocation(con,name);
    if(ret==-1)
    {
        printf("查无此人\n");
    }
    else
    {
        int i=0;
        for(i=ret;i<con->sz-1;i++)
        {
        con->arr[i]=con->arr[i+1];
        }
        con->sz--;
        printf("删除成功\n");
    }
}

五、查找联系人

查找功能很简单,利用刚刚的自定义函数FindLocation,很容易就能实现这个功能:

void SearchContact(Contact* con)
{
    printf("请输入要查找的姓名\n");
    char name[MAX_Name];
    scanf("%s",name);
    int ret=FindLocation(con,name);
    if(ret==-1)
    {
        printf("查无此人\n");
    }
    else
    {
        printf("%-20s\t%-5s\t%-10s\t%-11s\t%-20s\t\n","姓名","性别","年龄","电话号码","地址");
        printf("%-20s\t%-5s\t%-10d\t%-11d\t%-20s\t",
        con->arr[ret].name,con->arr[ret].sex,con->arr[ret].age,con->arr[ret].telephone,con->arr[ret].address);
        printf("\n");
    }
}

六、修改联系人

修改也是利用FindLocation函数,然后在需要的位置重新输入就可以了:

void ModifyContact(Contact* con)
{
    printf("请输入要更改的姓名\n");
    char name[MAX_Name];
    scanf("%s",name);
    int ret=FindLocation(con,name);
    if(ret==-1)
    {
        printf("查无此人\n");
    }
    else
    {
        printf("请输入姓名\n");
        scanf("%s",con->arr[ret].name);
        printf("请输入性别\n");
        scanf("%s",con->arr[ret].sex);
        printf("请输入年龄\n");
        scanf("%d",&con->arr[ret].age);
        printf("请输入电话号码\n");
        scanf("%d",&con->arr[ret].telephone);
        printf("请输入地址\n");
        scanf("%s",con->arr[ret].address);
    }
}

七、排序

排序需要利用到快速排序:

//以年龄排序
int cmp_by_age(const void* e1,const void* e2)
{
    return ((struct PeopleInfo*)e1)->age-((struct PeopleInfo*)e2)->age;
}
//以姓名排序
int cmp_by_name(const void* e1,const void* e2)
{
    return strcmp(((struct PeopleInfo*)e1)->name,((struct PeopleInfo*)e2)->name);
}
void ContactSort(Contact* con)
{
    qsort(con->arr,con->sz,sizeof(struct PeopleInfo),cmp_by_age);
    //qsort(con->arr,con->sz,sizeof(struct PeopleInfo),cmp_by_name);
    printf("排序成功\n");
    ShowContact(con);
}

八、显示联系人

显示就是利用循环打印出来:

void ShowContact(Contact* con)
{
    printf("%-20s\t%-5s\t%-10s\t%-11s\t%-20s\t\n","姓名","性别","年龄","电话号码","地址");
    int i=0;
    for(i=0;i<con->sz;i++)
    {
        printf("%-20s\t%-5s\t%-10d\t%-11d\t%-20s\t",
        con->arr[i].name,con->arr[i].sex,con->arr[i].age,con->arr[i].telephone,con->arr[i].address);
        printf("\n");
    }
}

九、销毁

因为我们的空间是动态开辟的,不用的时候需要销毁:

void ContactDestroy(Contact* con)
{
    free(con->arr);
    con->sz=con->capacity=0;
}

十、保存通讯录

保存通讯录我们就需要用到fprintf功能,把内存的数据输出到文件里,保存通讯录并不困难,难的是接下来的把文件的数据输出到终端上。

10.1 fprintf版本

void SaveContact(struct Contact* pc)
{
	//打开文件
	FILE* pfW = fopen("data.txt", "w");
	if (pfW == NULL)
	{
		perror("SaveContact::fopen");
		return;
	}
	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		fprintf(pfW,"%s %s %d %d %s\n",pc->arr[i].name,
        pc->arr[i].sex,pc->arr[i].age,pc->arr[i].telephone,pc->arr[i].address);
	}

	//关闭文件
	fclose(pfW);
	pfW = NULL;
}

10.2 fwrite版本

void SaveContact(struct Contact* pc)
{
 	//打开文件
 	FILE* pfW = fopen("data.txt", "wb");
 	if (pfW == NULL)
 	{
 		perror("SaveContact::fopen");
 		return;
 	}
 	//写文件
 	int i = 0;
 	for (i = 0; i < pc->sz; i++)
 	{
        //从arr[i]的位置开始读struct PeopleInfo的数据,一次读一个,读到文件中
 		fwrite(pc->arr+i, sizeof(struct PeopleInfo), 1, pfW);
 	}

 	//关闭文件
 	fclose(pfW);
 	pfW = NULL;
}

十一、文件读到内存

 把文件读到内存是有点困难的,因为我们的通讯录的初始大小是2,所以文件内如果有超过2个数据我们就需要扩容。

11.1 fscanf版本

oid LoadContact(Contact* con)
{
    FILE* pfR=fopen("data.txt","r");
    if(pfR==NULL)
    {
        perror("LoadContact::fopen");
        return;
    }
    struct PeopleInfo tmp={0};
    //fscanf要等于5,因为读5个数据,fscanf会返回5
    while(fscanf(pfR,"%s %s %d %d %s",tmp.name,tmp.sex,&tmp.age,&tmp.telephone,tmp.address)==5)
    {
        //检查容量
        checkcapacity(con);
        con->arr[con->sz]=tmp;
        con->sz++;
    }
    fclose(pfR);
    pfR=NULL;
}

11.2 fread版本

void LoadContact(Contact* con)
{
     FILE* pfR=fopen("data.txt","rb");
     if(pfR==NULL)
     {
         perror("LoadContact::fopen");
         return;
     }
     struct PeopleInfo tmp={0};
     while(fread(&tmp,sizeof(struct PeopleInfo),1,pfR))
     {
         checkcapacity(con);
         con->arr[con->sz]=tmp;
         con->sz++;
     }
     fclose(pfR);
     pfR=NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值