【项目】-关于通讯录的一系列操作,可以解决学校布置的大作业项目,不会就赶紧进来学习!!!

作者:小树苗渴望变成参天大树
作者宣言:认真写好每一篇博客
作者gitee:gitee
在这里插入图片描述

如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!


前言

我们前面学习了关于结构体,动态内存管理,文件操作这些知识点之后,我们可以自己来设计一个小项目,将我们学到的知识串联起来,才能更好加深我们对知识的理解,我们将使用结构体来存放用户信息,用结构体的自引用来存放数据,在实现一个动态增长的功能,最后在将我们存放的数据通过文件操作的知识将他们存放在一起,不会以至于下次运行时前面的数据没有了我们接下来进入正文,手把手带你实现每个功能!!!


一、前期准备

我们在之前三子棋小游戏的时候说过,我们实现这种小项目前,需要将函数的声明、定义和测试分开来写,所以我们需要建立三个文件,这样的目的是将项目变成清晰化。
在这里插入图片描述

二、头文件(contact.h)

我们需要用一个结构体来存放联系人的信息,在用另一个结构体存放数据,使用到的是结构体的嵌套定义,将其放在头文件里面

typedef struct PeoInfo
{
    
    
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
}PeoInfo;

typedef struct Contact
{
    
    
	PeoInfo* data;//用来存放每个联系人的各个信息
	int sz;//记录通讯录有多少人的
	int capicity;//当前通讯录最大容量
}Contact;

在存放联系人信息的结构体中,每个数组的大小我用宏定义了一个常量,方便以后的修改

#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 12
#define Init_Max 3
#define Add_Max 2

强调一点这不是结构体的自引用,而是嵌套定义

我们需要在还需要把函数的声明放到这个头文件里面,所以头文件里面完整的代码为

#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 12
#define Init_Max 3//初始化容量
#define Add_Max 2//每次增容量
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
typedef struct PeoInfo
{
    
    
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
}PeoInfo;

typedef struct Contact
{
    
    
	PeoInfo* data;
	int sz;//记录通讯录有多少人的
	int capicity;//当前通讯录最大容量
}Contact;

void InitContact(Contact* ps);//初始化通讯录

void AddContact(Contact* ps);//增加联系人的信息

void ShowContact(Contact* ps);//显示所有联系人

void SearchContact(Contact* ps);//查找联系人

void ModifContact(Contact* ps);//修改联系人的信息

void DelContact(Contact* ps);//删除联系人的信息

void SortContact(Contact* ps);//排序

void EmptyContact(Contact* ps);//清空

void SaveContact(Contact* ps);//保存文件

void ReadContact(Contact* ps);//读取文件

void DestroyContact(Contact* ps);//销毁

接下来我将依次实现这些功能

三、测试文件(test.c)

我们将主函数写在这个文件里面,方便测试代码

#include"contact.h"
void menu()
{
    
    
	printf("*****************************************\n");
	printf("*****   1.添加         2.显示      ******\n");
	printf("*****   3.查找         4.修改      ******\n");
	printf("*****   5.删除         6.排序      ******\n");
	printf("*****   7.清空         0.退出      ******\n");
	printf("*****************************************\n");
}
int main()
{
    
    
	int input = 0;
	Contact con = {
    
    0};
	InitContact(&con);
	do
	{
    
    
		menu();
		printf("请输入你要操作的选项:");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case 1:
			AddContact(&con);
			break;
		case 2:
			ShowContact(&con);
			break;
		case 3:
			SearchContact(&con);
			break;
		case 4:
			ModifContact(&con);
			break;
		case 5:
			DelContact(&con);
			break;
		case 6:
			SortContact(&con);
			break;
		case 7:
			EmptyContact(&con);
			break;
		case 0:
			SaveContact(&con);
			DestroyContact(&con);//销毁
			printf("退出通讯录系统\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

相信看懂我写的三子棋小游戏博客,对这个应该理解起来难度不大

四、定义文件(contact.c)

4.1初始化

void InitContact(Contact* ps)
{
    
    
	ps->data = (int*)malloc(sizeof(PeoInfo) * Init_Max);
	if (ps->data == NULL)
	{
    
    
		perror("malloc:");
		return;
	}
	ps->sz = 0;
	ps->capicity = Init_Max;
	ReadContact(ps);

}

4.2是否增容

void CheakConTact(Contact* ps)
{
    
    
	if (ps->sz == ps->capicity)
	{
    
    
		int* ptr = (int*)realloc(ps->data, sizeof(PeoInfo) * (ps->capicity + Add_Max));
		if (ptr == NULL)
		{
    
    
			perror("realloc:");
			return;
		}
		else
		{
    
    
			ps->data = ptr;
		}
		printf("增容成功!\n");
		ps->capicity += Add_Max;
	}
}

4.3添加

void AddContact(Contact* ps)//增加联系人的信息
{
    
    
	assert(ps);
	CheakConTact(ps);//先检查是否需要增容
	printf("请输入联系人的姓名:");
	scanf("%s", ps->data[ps->sz].name);
	printf("请输入联系人的年龄:");
	scanf("%d", &(ps->data[ps->sz].age));
	printf("请输入联系人的性别:");
	scanf("%s", ps->data[ps->sz].sex);
	printf("请输入联系人的电话:");
	scanf("%s", ps->data[ps->sz].tele);
	ps->sz++;
	printf("添加成功!\n");
}

4.4显示

void ShowContact(Contact* ps)//显示所有联系人
{
    
    
	if (ps->sz == 0)
	{
    
    
		printf("通讯录为空!\n");
		return;
	}
	int i = 0;
	printf("%-5s\t%-4s\t%-4s\t%-15s\n", "姓名", "年龄", "性别", "电话");//水平制表符,左对齐
	for (i = 0; i < ps->sz; i++)
	{
    
    
		printf("%-5s\t%-4d\t%-4s\t%-15s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele);
	}
}

4.5判断有没有此联系人

因为不管是删除或者修改,都涉及到找到那个指定的联系人,所以包装成一个函数:

int PanDuan(Contact* ps)//判断有没有此联系人
{
    
    
	if (ps->sz == 0)
	{
    
    
		printf("通讯录为空!\n");
		return 0;
	}
	char name[MAX_NAME];
	printf("请输入你要查找的联系人的姓名:");
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
    
    
		if (strcmp(ps->data[i].name, name) == 0)
		{
    
    
			break;
		}
	}
	return i;

4.6查找

void SearchContact(Contact* ps)//查找联系人
{
    
    
	int pos = PanDuan(ps);
	if (pos == 0)
	{
    
    
		return;
	}
	if (pos == ps->sz)
	{
    
    
		printf("没有你要查找的联系人!\n");
		return;
	}
	printf("查找成功!,此人的信息如下:\n");
	printf("%-5s\t%-4s\t%-4s\t%-15s\n", "姓名", "年龄", "性别", "电话");
	printf("%-5s\t%-4d\t%-4s\t%-15s\n", ps->data[pos].name, ps->data[pos].age, ps->data[pos].sex, ps->data[pos].tele);
}

4.7修改

void ModifContact(Contact* ps)//修改联系人的信息
{
    
    
	int pos = PanDuan(ps);
	if (pos == 0)
	{
    
    
		return;
	}
	if (pos == ps->sz)
	{
    
    
		printf("没有你要修改的联系人!\n");
		return;
	}
	printf("查找成功,请修改他的信息:\n");
	printf("请输入联系人的姓名:");
	scanf("%s", ps->data[pos].name);
	printf("请输入联系人的年龄:");
	scanf("%d", &(ps->data[pos].age));
	printf("请输入联系人的性别:");
	scanf("%s", ps->data[pos].sex);
	printf("请输入联系人的电话:");
	scanf("%s", ps->data[pos         ].tele);
	printf("修改成功!\n");
}

4.8删除

void DelContact(Contact* ps)//删除联系人的信息
{
    
    
	int pos = PanDuan(ps);
	if (pos == 0)
	{
    
    
		return;
	}
	if (pos == ps->sz)
	{
    
    
		printf("没有你要删除的联系人信息!\n");
		return;
	}
	int j = pos;
	for (j = pos; j < ps->sz - 1; j++)
	{
    
    
		ps->data[j] = ps->data[j + 1];
	}
	ps->sz--;
	printf("删除成功!\n");
}

4.8排序(按名字)

int cmp_name(const void* e1, const void* e2)
{
    
    
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* ps)//排序
{
    
    
	qsort(ps->data, ps->sz,sizeof(PeoInfo), cmp_name);
	printf("排序成功!\n");
}

4.9清空

void EmptyContact(Contact* ps)//清空
{
    
    
	ps->sz = 0;
	printf("清空成功!\n");
}

4.10保存文件和读取文件

第一种:
保存文件

void SaveContact(Contact* ps)
{
    
    
	assert(ps);
	FILE* pf = fopen("tongxunlu.txt", "w");
	if (NULL == pf)
	{
    
    
		perror("fopen:");
		return;
	}
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
    
    
		fprintf(pf, "%s %d %s %s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele);
	}
	fclose(pf);
	pf = NULL;
	printf("保存成功\n");
}

读取文件:

void ReadContact(Contact* ps)//读取文件
{
    
    
	assert(ps);
	FILE* pf = fopen("tongxunlu.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen:");
		return;
	}
	//读取文件
	PeoInfo tmp = {
    
     0 };
	char c = 0;
	int r_n = 0;
	while (!feof(pf))
	{
    
    
		c = fgetc(pf);
		if (c == '\n')
		{
    
    
			r_n++;
		}
	}
	rewind(pf);
	for (ps->sz = 0; ps->sz < r_n; ps->sz++)
	{
    
    
		CheakConTact(ps);//先检查是否需要增容
		fscanf(pf, "%s %d %s %s", ps->data[ps->sz].name, &(ps->data[ps->sz].age), ps->data[ps->sz].sex, ps->data[ps->sz].tele);
	}

	printf("读取文件成功!\n");
	fclose(pf);
	pf = NULL;
}

第二种:
保存文件

void SavehjContact(struct Contact* ps)
{
    
    
    FILE* pfWrite = fopen("contact.dat", "wb");
    if (pfWrite == NULL)
    {
    
    
        printf("SaveContact:%s\n", strerror(errno));
        return;
    }
    //写文件
    int i = 0;
    for (i = 0; i < ps->size; i++)
    {
    
    
       fwrite(&(ps->date[i]),sizeof(struct PeoInfo),1,pfWrite);//以二进制读入文件
    }
    //关闭文件
    fclose(pfWrite);
    pfWrite = NULL;
}

读取文件

void ReadContact(struct Contact* ps)
{
    
     
    struct PeoInfo tmp = {
    
     0 };
    FILE* pfRead = fopen("contact.dat", "rb");
    if (pfRead == NULL)
    {
    
    
        printf("LoadContact:%s\n", strerror(errno));
        return;
    }
    //读文件
    while (fread(&tmp, sizeof(struct PeoInfo),1, pfRead))//一次读取一个,返回实际读取的个数
    {
    
    
        CheckContact(ps);
        ps->date[ps->size] = tmp;
        ps->size++;
    }
    //关闭文件
    fclose(pfRead);
    pfRead = NULL;
}

最后要将读取文件放在初始化函数中去

4.11销毁

void DestroyContact(Contact* ps)//销毁
{
    
    
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->sz = 0;
	ps->capicity = 0;
}

4.12定义文件完整代码

#include"contact.h"
void InitContact(Contact* ps)
{
    
    
	ps->data = (int*)malloc(sizeof(PeoInfo) * Init_Max);
	if (ps->data == NULL)
	{
    
    
		perror("malloc:");
		return;
	}
	ps->sz = 0;
	ps->capicity = Init_Max;
	ReadContact(ps);
}

void CheakConTact(Contact* ps)
{
    
    
	if (ps->sz == ps->capicity)
	{
    
    
		int* ptr = (int*)realloc(ps->data, sizeof(PeoInfo) * (ps->capicity + Add_Max));
		if (ptr == NULL)
		{
    
    
			perror("realloc:");
			return;
		}
		else
		{
    
    
			ps->data = ptr;
		}
		printf("增容成功!\n");
		ps->capicity += Add_Max;
	}
}
void AddContact(Contact* ps)//增加联系人的信息
{
    
    
	assert(ps);
	CheakConTact(ps);
	printf("请输入联系人的姓名:");
	scanf("%s", ps->data[ps->sz].name);
	printf("请输入联系人的年龄:");
	scanf("%d", &(ps->data[ps->sz].age));
	printf("请输入联系人的性别:");
	scanf("%s", ps->data[ps->sz].sex);
	printf("请输入联系人的电话:");
	scanf("%s", ps->data[ps->sz].tele);
	ps->sz++;
	printf("添加成功!\n");
}


void ShowContact(Contact* ps)//显示所有联系人
{
    
    
	if (ps->sz == 0)
	{
    
    
		printf("通讯录为空!\n");
		return;
	}
	int i = 0;
	printf("%-5s\t%-4s\t%-4s\t%-15s\n", "姓名", "年龄", "性别", "电话");
	for (i = 0; i < ps->sz; i++)
	{
    
    
		printf("%-5s\t%-4d\t%-4s\t%-15s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele);
	}
}

int PanDuan(Contact* ps)//判断有没有此联系人
{
    
    
	if (ps->sz == 0)
	{
    
    
		printf("通讯录为空!\n");
		return 0;
	}
	char name[MAX_NAME];
	printf("请输入你要查找的联系人的姓名:");
	scanf("%s", name);
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
    
    
		if (strcmp(ps->data[i].name, name) == 0)
		{
    
    
			break;
		}
	}
	return i;
}

void SearchContact(Contact* ps)//查找联系人
{
    
    
	int pos = PanDuan(ps);
	if (pos == 0)
	{
    
    
		return;
	}
	if (pos == ps->sz)
	{
    
    
		printf("没有你要查找的联系人!\n");
		return;
	}
	printf("查找成功!,此人的信息如下:\n");
	printf("%-5s\t%-4s\t%-4s\t%-15s\n", "姓名", "年龄", "性别", "电话");
	printf("%-5s\t%-4d\t%-4s\t%-15s\n", ps->data[pos].name, ps->data[pos].age, ps->data[pos].sex, ps->data[pos].tele);
}

void ModifContact(Contact* ps)//修改联系人的信息
{
    
    
	int pos = PanDuan(ps);
	if (pos == 0)
	{
    
    
		return;
	}
	if (pos == ps->sz)
	{
    
    
		printf("没有你要修改的联系人!\n");
		return;
	}

	printf("查找成功,请修改他的信息:\n");
	printf("请输入联系人的姓名:");
	scanf("%s", ps->data[pos].name);
	printf("请输入联系人的年龄:");
	scanf("%d", &(ps->data[pos].age));
	printf("请输入联系人的性别:");
	scanf("%s", ps->data[pos].sex);
	printf("请输入联系人的电话:");
	scanf("%s", ps->data[pos         ].tele);
	printf("修改成功!\n");
}

void DelContact(Contact* ps)//删除联系人的信息
{
    
    
	int pos = PanDuan(ps);
	if (pos == 0)
	{
    
    
		return;
	}
	if (pos == ps->sz)
	{
    
    
		printf("没有你要删除的联系人信息!\n");
		return;
	}
	int j = pos;
	for (j = pos; j < ps->sz - 1; j++)
	{
    
    
		ps->data[j] = ps->data[j + 1];
	}
	ps->sz--;
	printf("删除成功!\n");
}

int cmp_name(const void* e1, const void* e2)
{
    
    
	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* ps)//排序
{
    
    
	qsort(ps->data, ps->sz,sizeof(PeoInfo), cmp_name);
	printf("排序成功!\n");
}


void EmptyContact(Contact* ps)//清空
{
    
    
	ps->sz = 0;
	printf("清空成功!\n");
}

void ReadContact(Contact* ps)//读取文件
{
    
    
	assert(ps);
	FILE* pf = fopen("tongxunlu.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen:");
		return;
	}
	//读取文件
	PeoInfo tmp = {
    
     0 };
	char c = 0;
	int r_n = 0;
	while (!feof(pf))
	{
    
    
		c = fgetc(pf);
		if (c == '\n')
		{
    
    
			r_n++;
		}
	}
	rewind(pf);
	for (ps->sz = 0; ps->sz < r_n; ps->sz++)
	{
    
    
		CheakConTact(ps);
		fscanf(pf, "%s %d %s %s", ps->data[ps->sz].name, &(ps->data[ps->sz].age), ps->data[ps->sz].sex, ps->data[ps->sz].tele);
	}

	printf("读取文件成功!\n");
	fclose(pf);
	pf = NULL;
}


void SaveContact(Contact* ps)
{
    
    
	assert(ps);
	FILE* pf = fopen("tongxunlu.txt", "w");
	if (NULL == pf)
	{
    
    
		perror("fopen:");
		return;
	}
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
    
    
		fprintf(pf, "%s %d %s %s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele);
	}
	fclose(pf);
	pf = NULL;
	printf("保存成功\n");
}

void DestroyContact(Contact* ps)//销毁
{
    
    
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->sz = 0;
	ps->capicity = 0;
}

五、总结

本次的小项目我没有对每一行代码具体分析,因为我觉得只要之前的知识学会了就能看懂这个代码,学不会,我在怎么去讲解你还是不懂,按照我的思路一步步的来梳理逻辑,相信大家可以很好的独立的把这个小项目独立写出来,今天的分享九到此结束了,我们下篇再见!!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_69369227/article/details/128728854