听说你还不会写通讯录?C语言通讯录#存储到文件里去,动态版

前言

会写的不一定真的懂了,本篇文章结合了B站鹏哥的写作手法,循序渐进推进知识点,一步步教你写代码,非常适合初学者学习,建议反复观看。

同时作者我也是一个C语言B站初学者,欢迎一起学习交流,批评指正。

家人们,来都来了,动动你们发财的小手,给我点点关注,点点赞呗,你们的支持就是我创作的动力,我会持续发布高质量的文章供大家一起学习。

课前谈话


首先,我们在写的时候要明白通讯录的作用,其实通讯录就是我们的笔记本,只是用来记录联 系人的信息的,重要的是对通讯录的修改。通讯录的原理实现其实很简单,我们只需要创建一个数组,对这个数组进行增,删,查,改就可以了。写通讯录的基本程序大部分也就是在这方面下手的。接下来的通讯录的编写我会结合一些基本知识点逐步来为大家讲解。

菜单的实现

打印菜单及菜单键


在看我们整个打印菜单及菜单键的实现逻辑之前,我们先看看我们定义的头文件中干了什么吧

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
enum Option
{
	EXIT,
	ADD,
	DEL,
	SAERCH,
	MOD,
	SHOW,
	SAVE

};

没错!我们创建了一个枚举,它的作用就是利用枚举常量代替了数字0到6,接下来我们就可以体验到,当然,在源文件中要引用这个头文件哦。

#define _CRT_SECURE_NO_WARNINGS 1
#include"teat2.h"
void menu()
{
	printf("*********************************************************\n");
	printf("****************** 1.add       2.del ********************\n");
	printf("****************** 3.saerch   4.modify  ********************\n");
	printf("****************** 5.show     6.save ********************\n");
	printf("****************** 0.exit            ********************\n");
	printf("*********************************************************\n");
}
int main()
{
	int arr = 0;
	//创建通讯录
	struct Contact con;
	//通讯录初始化
	InitContact(&con);

	do {
		menu();
		printf("请输入->\n");
		scanf("%d", &arr);
		switch (arr)
		{
//添加联系人
		case ADD:
			AddContact(&con);
			break;
//删除联系人
		case DEL:
			DelContact(&con);
			break;
//查找联系人
		case SAERCH:
			SaerchContact(&con);
			break;
//修改联系人
		case MODify:
			SavveContact(&con);
			ModContact(&con);
			break;
//显示通讯录名单
		case SHOW:
			Contactcpy(&con);
			break;
//保存联系人
		case SAVE:
			SavveContact(&con);
             printf("保存成功!\n");
			break;
		case EXIT:
           //指针指空
			DestroyContact(&con);
			printf("你已经退出。\n");
			break;
		default:
			printf("你的输入有错,请重新输入!\n");
			break;
		}
	} while (arr);
	return 0;
}

 case的同样的效果,而case 后的值再也不是数字了,而是字母,这样是不是很高级?用户在使用时同样输入数字就好了。

枚举有什么作用呢?

通常在没改变枚举常量默认赋值的情况下从前到后,每个枚举的常量是从0,1,2,3,4...这样+1一直到最后一个枚举常量的。就像这里的菜单键EXIT = 0, ADD = 1,DEL = 2,SAERCH = 3,MODIFY = 4,SHOW = 5 ,SAVE = 6一样。

其他的这里switch分支,while循环以及库函数的头文件的引用是为什么就不在这里解释了,不知道的可以看看我的其他文章,或者Q我哦。

看看效果:daa258109b354da1a77b9a982d4e3981.png


 创建通讯录及通讯录初始化

main()中的创建讯录及通讯录初始化

我们创建了一个结构体和一个自定义函数

    //创建通讯录
	struct Contact con;
	//通讯录初始化
	InitContact(&con);

我们先看看我们定义的头文件中干了什么吧

#define DEFAULT_SZ 3
#define MAX_NAME 20
#define MAX_SEC 5
#define MAX_TELE 12
#define MAX_ADDR 20
//存放我们联系人的基本信息
struct Peotnfo
{
	char name[MAX_NAME];
	int age;
	char sec[MAX_SEC];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
};
//通讯录
struct Contact
{
	struct Peotnfo* data;
	int size;
	int capacity;
};

我们在头文件中完整的写出了Contact这个结构体,这个结构体用来存放的我们联系人,已及一个记录联系人数量的int变量size,还有一个开辟联系人数量空间的int变量capacity,但值得注意的是用来存放我们联系人的基本信息的也是一个结构体,在这个结构体中我们创建了5个变量,分别是name(名字) ,age(年龄),sec(性别),tale(电话),addr(地址)并为他们开辟了空间。

这里#define就是用大写的字母代替数字,数字表示为这个数组向内存申请了多少空间。

超级重要!!!!一开始#define设置开辟的空间一定要满足基本的存储,如这里的电话号码开辟的空间一定要大于12,否则一定会出问题。

通讯录初始化具体实现(开辟动态数组)

void InitContact(struct Contact* pc)
{
	pc->data = (struct Peotnfo*)malloc( DEFAULT_SZ  * sizeof(struct Peotnfo));
	if (pc->data == NULL)
	{
		return;
	}
       //空间初始化为3,DEFAULT_SZ在头文件中指定为3
	pc->capacity = DEFAULT_SZ;
	pc->size = 0;
}

我们在函数中传了一个结构体指针,并为这个指针取了个名字叫pc,然后用malloc库函数动态开辟了空间,data是个指针,指向了存放我们联系人的基本信息的那个结构体。为了严谨,我们还加了一句ifpc->data == NULL来判断是否有效。

动态版 增容的具体实现形式

void CheckCapacity(struct Contact* pc)
{
	if (pc->size == pc->capacity)
	{
		struct Peotnfo* p = (struct Peotnfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct Peotnfo));
		if (p != NULL)
		{
			pc->capacity += 2;
			pc->data = p;
			printf("增容成功!\n");
		}
		else {
			printf("增容失败!\n");
		}
	}
}

存储到文件里去的具体实现方式  

//写入文件
void SavveContact(struct Contact* pc)
{
//二进制wb写入,增加保密性
	FILE* pfwrite = fopen("contat.txt", "wb");
	if (pfwrite == NULL)
	{
		printf("%d\n", strerror(errno));
		return;
	}
	int i = 0;
	for (i = 0; i < pc->size; i++)
	{
		fwrite(&(pc->data[i]), sizeof(Peotnfo), 1, pfwrite);
	}
	fclose(pfwrite);
	pfwrite = NULL;
}
//从文件里读
void LoadContat(struct Contact* pc)
{
	Peotnfo tmp = { 0 };
	FILE* pfwrites = fopen("contat.txt", "rb");
	if (pfwrites == NULL)
	{
		printf("%d\n", strerror(errno));
		return;
	}
	while (fread(&tmp, sizeof(Peotnfo), 1, pfwrites))
	{
		CheckCapacity(pc);
		pc->data[pc->size] = tmp;
		pc->size++;
	}
	fclose(pfwrites);
	pfwrites = NULL;
}

有了这个就可以把联系人的信息存储在"contat.txt"(自动创建)这个文件中,每次打开的时候就有上次写的记录,但是一定记得保存哦。至于fopen和fread的使用的详细语法我会在这几天赶出来,请关注主页。 

看看效果:

完成第一项,添加联系人

void AddContact(struct  Contact* pc)
{
	char arr1;
	CheckCapacity(pc);
		do {
			printf("请输入名字->");
			scanf("%s", pc->data[pc->size].name);
			printf("请输入年龄->");
			scanf("%d", &(pc->data[pc->size].age));
			printf("请输入性别->");
			scanf("%s", pc->data[pc->size].sec);
			printf("请输入电话->");
			scanf("%s", pc->data[pc->size].tele);
			printf("请输入地址->");
			scanf("%s", pc->data[pc->size].addr);
			getchar();
			pc->size++;
			printf("添加完成!是否继续添加->y/n");
			scanf("%c", &arr1);
			getchar();
			if (arr1 == 'n')
			{
				break;
			}
		} while (1);
}

这里没什么讲的,就是利用scanf函数将值输入到pc对应的指针里面去,然后用while循环来保持持续性。

看看效果:

bad95b470c894125a85a887711b795b4.png

完成第五项:显示通讯录名单

void Contactcpy(struct  Contact* pc)
{
	int arr2;
	if (pc->size == 0)
	{
		printf("通讯录为空\n");
	}
	else {
		for (arr2 = 0; arr2 < pc->size; arr2++) {
			printf("名字:   ");
			printf("%-20s\n", pc->data[arr2].name);
			printf("年龄:   ");
			printf("%-4d\n", (pc->data[arr2].age));
			printf("性别:   ");
			printf("%-5s\n", pc->data[arr2].sec);
			printf("电话:   ");
			printf("%-12s\n", pc->data[arr2].tele);
			printf("地址:   ");
			printf("%-30s\n", pc->data[arr2].addr);
			printf("---------------------------\n");
		}
	}
}

这里也没什么讲的,就是利用printf函数打印联系人信息。这里提前写是为了在写其他函数时方便打印调试。

看看效果:

 

cfe503eb60e84775ac828a196e685b76.png

查找,删除,修改联系人的第一个步骤是对联系人的定位,所有我们可以统一起来写一个对联系人定位的函数

static int FindName(struct Contact* pc, char name[MAX_NAME])
{
	int i;
	for (i = 0; i < pc->size; i++)
	{
		if (0 == strcmp(pc->data[i].name, name))
		{
			return i;
		}
	}
	return -1;
}

 利用循环去遍历,找到了返回i,即联系人的存储序号,没找到返回-1

完成第二项:删除联系人

void DelContact(struct Contact* pc)
{
	int poc;
	char name[MAX_NAME];
	printf("请输入你要删除的对象名字->");
	scanf("%s", &name);
//对定位函数的使用
	 poc = FindName(pc, name);
	if (poc == -1)
	{
		printf("你要删除的对象不在。");
	}
	else {
		for (int j = poc; j < pc->size - 1; j++)
		{
			pc->data[j] = pc->data[j + 1];
		}
		pc->size--;
		printf("删除成功!\n");
	}

}

 减少一个联系人size--一次

看看效果:

 

9f0ba1658d59462995733ebd4338ccab.png

完成第三项:查找联系人

void SaerchContact(struct Contact* pc)
{
	int poc;
	char name[MAX_NAME];
	printf("请输入你要查找的对象名字->");
	scanf("%s", &name);
//对定位函数的使用
	 poc = FindName(pc, name);
	if (poc == -1)
	{
		printf("你要查找的对象不在。");
	}
	else {
		printf("名字:   ");
		printf("%-20s\n", pc->data[poc].name);
		printf("年龄:   ");
		printf("%-4d\n", (pc->data[poc].age));
		printf("性别:   ");
		printf("%-5s\n", pc->data[poc].sec);
		printf("电话:   ");
		printf("%-12s\n", pc->data[poc].tele);
		printf("地址:   ");
		printf("%-30s\n", pc->data[poc].addr);
	}
}

查找联系人的函数使用原理就是定位加打印。

看看效果:

 

440d9c1328454a25a925d4c860c8bcc9.png

完成第四项:修改联系人

void ModContact(struct Contact* pc)
{
	int poc;
	char name[MAX_NAME];
	printf("请输入你要修改的对象->");
	scanf("%s", &name);
//对定位函数的使用
    poc = FindName(pc, name);
	if (poc == -1)
	{
		printf("你要修改的对象不在。");
	}
	else {
		printf("请输入名字->");
		scanf("%s", pc->data[poc].name);
		printf("请输入年龄->");
		scanf("%d", &(pc->data[poc].age));
		printf("请输入性别->");
		scanf("%s", pc->data[poc].sec);
		printf("请输入电话->");
		scanf("%s", pc->data[poc].tele);
		getchar();
		printf("请输入地址->");
		scanf("%s", pc->data[poc].addr);
		getchar();
		printf("修改完成!");
	}
}

 修改联系人的函数使用原理就是定位加添加,但值得注意的是size不变。

看看效果:

 

cbd9c09487e743eeac40dc57c44c3a1d.png

看看文件里的结果吧

414f0e7ce15c4152adc82903bd5dccd4.png

加密的哦。

家人们,来都来了,动动你们发财的小手,给我点点关注,点点赞呗,你们的支持就是我创作的动力,我会持续发布高质量的文章供大家一起学习。 

猜你喜欢

转载自blog.csdn.net/2301_77479336/article/details/130026117