【C语言进阶】干货满满的升级版通讯录(动态内存分配+文件操作)

我们之前讲解了使用结构体的知识实现通讯录管理,在我们学习过动态内存管理和文件操作后,能否对通讯录进行升级呢?今天这篇文章就会为大家讲解通讯录的升级版

一.简易通讯录回顾

1.通讯录功能

在之前的简易通讯录中我们通过创建结构体来存放通讯录中联系人的信息,设置变量维护联系人的个数,也实现了通讯录的增删改、显示、排序、查找、清理等多个功能。

2.通讯录缺点

虽说简易通讯录已经可以实现多种功能了,当时其逻辑和代码上还有很多需要改进升级的地方。简易通讯录还有一些缺点: 比如在我们创建结构体指定通讯录可存放联系人个数的大小时,是将数组大小写死的,这就导致代码使用起来灵活度较低,如果数组大小开辟的不合适,很容易出现空间不够非法访问或者内存浪费等问题。这个问题我们可以使用动态内存来解决,提高代码的灵活度。
另外一个缺点就是,通讯录中的联系人信息无法持久保存,在终端关闭后存放的信息就会被销毁,下一次运行程序时只能重新录入信息存,这就导致简易通讯录的实用性大大降低 ,这里我们就可以使用文件操作的知识,对联系人的信息进行储存维护。理论存在,实践开始:

二.动态内存升级通讯录

为了避免把存放联系人信息的个数给写死,显然我们不可继续使用数组维护结构体联系人的信息。
我们选择重新创建一个结构体 :创建一个结构体指针指向存放联系人信息的结构体,创建一个整形计算已存联系人的个数,再创建一个变量计算当前通讯录的容量,这是实现动态开辟存放联系人个数的重要变量。
如下:

typedef struct peoinf//存放个人的信息
{
	char name[20];
	int age;
	char sex[6];
	char addr[15];
	char tele[13];
}peo;
typedef struct Contacts//通讯录包括联系人信息和联系人个数
{
	peo* data;
	int sz;
	int Capacity;//容量
}contacts;
1.动态初始化通讯录

在先前的版本中,初始化通讯录只需将数组和联系人个数置为零即可,而在动态版本中我们需要将为指针开默认初始容量的内存空间,再将联系人个数置零,容量置为默认初始容量。
如下:

#define Initial_value 3//默认容量
#define Step 2//增容步长
//动态
void ini_con(contacts* p)
{
	assert(p);
	p->sz = 0;
	p->Capacity = Initial_value;//容量置为默认
	peo* ptr=(peo*)calloc(Initial_value, sizeof(peo));
	if (NULL == ptr)//开辟默认容量的空间,并且初始化为零
	{
		perror("calloc:");
		return;
	}
	p->data = ptr;
}
2.动态规划容量

因为我们设置默认通讯录的容量仅为3,所以我们在添加联系人信息时,一定要考虑联系人个数是否要超出容量的问题,所以我们还要编写函数为通讯录增加容量,而每次增加的大小用define定义为2。使用realloc函数为通讯录增容

#define Initial_value 3//默认容量
#define Step 2//增容步长
void Increased_capacity(contacts* p)
{
	if (p->sz == p->Capacity)//判断是否需要增容
	{
		peo* ptr = (peo*)realloc(p->data, sizeof(peo) * (Initial_value + Step));
			if (ptr == NULL)
			{
				perror("realloc:");
				return;
			}
			printf("增容成功\n");
			p->data = ptr;
			p->Capacity += Step;//一次增容,容量加一次步长
	}
}
3.释放动态内存空间

使用动态内存对通讯录升级后,在退出通讯录时应该记得释放掉动态开辟的内存防止 内存泄漏

void Destroy(contacts * p)
{
	assert(p);
	free(p->data);
	p->data = NULL;
	p->sz = 0;
	p->Capacity = 0;
	p = NULL;
}

三.文件操作升级通讯录

在使用动态内存管理升级简易通讯录后,通讯录的灵活度得到了提升,减少了内存的浪费,但是这个通讯录管理还是存在着致命的问题------无法将联系人持久保存,在下次运行程时无法保留上次的联系人信息,那我们如何运用文件操作的知识解决这个问题呢?如下:

1.保存通讯录

我希望这次运行的通讯录中保存的信息,在结束程序后依然存在,我们就可以创建一个文件,在退出通讯录时将联系人的信息写入文件,在下次运行程序时再向文件中读取。这里需要用到两个函数fwrite和fread:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

通过观察函数原型可知,fwrite可将ptr指向地址的count个size的字节写入stream指向的文件信息区

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

fread与rwrite相似,只不过它是把stream指向的内容存放到ptr指向的空间。
这样我们就可以去实现保存通讯录的函数了:

//保存通讯录
void Savecon(contacts* p)
{
	assert(p);
	FILE* pf = fopen("contacts.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen:");
	}
	else
	{
		int i = 0;
		for (i = 0; i < p->sz; i++)
		{
			fwrite(p->data + i, sizeof(peo), 1, pf);
		}
		fclose(pf);//记得关闭文件
		pf = NULL;
		printf("保存成功\n");
	}
}
2.加载通讯录

我们在上次运行通讯录程序结束后,会将联系人信息保存到文件中,而为了下次运行程序依旧保存着上次的信息,我们在初始化通讯录后,就要加载上次通讯录留下的信息。

//加载通讯录
void Loadcon(contacts* p)
{
	assert(p);
	FILE* pf = fopen("contacts.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen:contacts.txt:");
	}
	else
	{
		peo tmp = { 0 };
		int i = 0;
		while (fread(&tmp, sizeof(peo), 1, pf))
		{
			Increased_capacity(p);//判断是否需要增容
			p->data[i] = tmp;
			i++;
			p->sz++;
		}
		fclose(pf);
		pf = NULL;
	}
}

需要注意的是,读取上次通讯录留下的信息时,应判断默认容量是否能够放的下,如果不能就要进行增容

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aomnitrix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值