C语言进阶篇 进阶小项目【文件版通讯录】

本文介绍如何在C语言中实现文件操作,包括保存通讯录至'contact.dat'并读取,通过fopen、fwrite和fread函数处理数据。解决了函数调用顺序和扩容问题,详细展示了保存和读取通讯录的步骤及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、说明

这次的通讯录为文件保存的版本,

需求说明:

1、增加保存功能,可以存放到文件中。

2、增加读取功能,读取之前保存的通讯录文件。

小提示:

今天写代码遇到一个BUG,无论怎么更改代码都报错,

后来才调试出:如果你要在A函数中调用B函数,即使在头文件中声明了,但是在函数文件中,一定要先定义B。因为程序是从上至下一行一行读取的,编译不会通过,但是报的错会很奇怪,如报scanf的错,这样很难通过编译器找到错因。所以写函数一定要分先后。 

二、更改代码段 

首先是保存功能:

void SaveContact(struct Contact* ps)
{
	FILE* pfWrite;
	pfWrite = fopen("C:\\Users\\asus\\Desktop\\contact.dat", "wb");
	if (pfWrite == NULL)
	{
		printf("%s\n", strerror(errno));
		return;
	}
	//打开成功
	//写通讯录中的数据到文件中
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		fwrite(&(ps->data[i]), sizeof(PeoInfo), 1, pfWrite);
	}
	//关闭文件
	fclose(pfWrite);
	pfWrite = NULL;
}

 这个函数创建了一个文件指针,指向要保存的数据的地址文件。

然后进行指针判空操作,

如果指针存在,则进行一个for循环,

将当前存放的通讯录中的数据一条一条地通过fwrite函数写进文件里。

fwrite函数:写文件函数。

4个参数,

第一个是要读取的数据元素的地址,

第二个是读取一个元素的大小,

第三个是读取元素的数量,

第四个是要写到哪个文件里去,指向那个文件的指针。

这样就完成了保存文件操作。

 

那么读取通讯录呢?

对于读取通讯录,我们有两个问题:

1、怎么读

2、扩容问题

首先解决第一个问题。

读文件要用到的函数是:

fread();

同样是4个参数,

不过操作不一样了。

第一个是被写的数据元素的地址,

第二个是写的一个元素的大小,

第三个是写元素的数量,

第四个是要读哪个文件,指向那个文件的指针。

综上,文件读写函数分别是:

读文件函数,fread,意思是要把文件里的内容读出来,写到变量中去;

写文件函数,fwrite,意思是要把变量中的数据写进文件里去。

这里的读写均是针对文件。

 

所以,我们先读这个文件里的数据,存放到临时结构体变量tmp中:

PeoInfo tmp = { 0 };
	FILE* PfRead = fopen("C:\\Users\\asus\\Desktop\\contact.dat", "rb");
	if (PfRead == NULL)
	{
		printf("LoadContact::%s\n", strerror(errno));
		return;
	}
	//读取文件,存放到通讯录中
read(&tmp, sizeof(PeoInfo), 1, PfRead);

而fread具有返回类型,是size_t,意思是读取了几个元素;

如果没有读满一个元素,就返回0.

这里我们可以很好的运用这个返回值来解决第二个问题:扩容问题。

首先,我们定义一开始只动态开辟3个元素的内存,

那么前三个好放,我们只需要

ps->data[ps->size] = tmp;
		ps->size++;

但是当放满三个后,需要扩容,我们就在前面加上一个扩容函数。

最后,用返回类型来控制while循环的次数即可:

void LoadContact(Contact* ps)
{
	PeoInfo tmp = { 0 };
	FILE* PfRead = fopen("C:\\Users\\asus\\Desktop\\contact.dat", "rb");
	if (PfRead == NULL)
	{
		printf("LoadContact::%s\n", strerror(errno));
		return;
	}
	//读取文件,存放到通讯录中
	while (fread(&tmp, sizeof(PeoInfo), 1, PfRead))
	{
		CheckCapacity(ps);
		ps->data[ps->size] = tmp;
		ps->size++;
	}
	//关闭文件
	fclose(PfRead);
	PfRead = NULL;
}

而这个函数,我们可以写到初始化函数中:

void InitContact(struct Contact* ps)
{
	ps->data = (struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo));
	if (ps->data == NULL)
	{
		return;
	}
	ps->size = 0;
	ps->capacity = DEFAULT_SZ;
	//把文件中已经存放的通讯录中的信息加载到通讯录中
	LoadContact(ps);
}

这样一份文件版的通讯录就写完了。

三、GitHub地址

https://github.com/kukeoo/Contact.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值