通讯录动态版&文件版

C语言通讯录——动态版&文件版

1.前言:

本篇只讲解通讯录中实现动态内存管理的以及文件版本的部分的功能,其它功能请转至本专栏上一篇C语言通讯录静态版学习,我也更推荐先看那个猜能更好理解。

2.思路解析

书接上回,在上篇我们已经一起学习了通讯录静态版,复习一下,就是
首先创建结构体包含联系人各项信息,再创建结构体包含这个联系人结构体和size整型变量(记录联系人数量)
然后实现通讯录的各种功能,包括增删查改排序显示等(通过结构体传址实现)。
最后再实现一下菜单功能
那么现在我们回到正题,我们要怎么实现“动态”呢?
其实很简单,只需要做两件事。
(1)初始化时用malloc申请start_capacity(规定的一个通讯录初始容量)个结构体
(2)当空间不够用时就realloc再申请空间
接下来看看怎么实现吧

3.代码编写

3.1动态版

3.1.1初始化函数

刚才也说了我们要在初始化函数中做修改,不再规定死通讯录容量。而这首先需要我们对结构体做点小变化

我们可以看到我们加了一个新的整型变量capacity,并且将data的数据类型改成了结构体指针。
首先capacity是干什么的?就是用来记录当前通讯录的容量的。而结构体指针也是为了动态内存管理而设
然后我们看看初始化函数中应该作何变动

void InitContact(struct Contact *ps)
{
	/*memset(ps->data, 0, sizeof(ps->data));
	ps->size = 0;*/
	ps->data = (struct PepInfo *) malloc(START_CAPACITY*sizeof(struct PepInfo));
	if (ps->data == NULL)
	{
		return;
	}
	ps->size = 0;
	ps->Capacity = START_CAPACITY;
}

注释的是原先的。我们可以看到,我们用malloc向内存申请了START_CAPACITY个pepinfo大小的空间。这里这个START_CAPACITY实在头文件中使用宏定义定义的初始容量,我这里给的是3.你们可以根据需要自行设定。这里使用malloc(或者说其它内存函数,都要进行检查是否空间申请成功,否则容易造成内存问题)。

3.1.2checkcapacity函数

这个函数是用来干什么的呢?是用来检查通讯录容量是否满,如果满则再用realloc开辟指定大小空间,否则就不需要开辟了。那么具体怎么实现?首先要进行判断是否满。这里用if判断size(联系人数量)和capacity(通讯录容量)作比较。如果相等就满了需要扩容。
这里我选择让用户自己选择扩容多少空间是让操作更灵活,但是后面文件操作时就不怎么方便了,你也可以直接规定每次满扩多少空间,比如原先的两倍之类的

void CheckCapacity(struct Contact* ps)
{
	if (ps->size == ps->Capacity)
	{
		printf("通讯录已满,请扩容\n");
		int n = 0;
		printf("请输入要扩容的空间>:");
		scanf("%d", &n);
		struct PepInfo* ptr = realloc(ps->data, (ps->Capacity + n) * sizeof(struct PepInfo));
		if (ptr != NULL)
		{
			ps->data = ptr;
			ps->Capacity += n;
			printf("扩容成功\n");
		}
		else
		{
			printf("扩容失败\n");
		}
	}
}

完成这个就大功告成了吗,其实不然。我们还要在原先的ADD函数开头加上这个函数进行判断

void AddContact(struct Contact* ps)
{
	CheckCapacity(ps);

	printf("请输入名字>:");
	scanf("%s", ps->data[ps->size].name);
	printf("请输入年龄>:");
	scanf("%d", &ps->data[ps->size].age);
	printf("请输入性别>:");
	scanf("%s", ps->data[ps->size].sex);
	printf("请输入电话>:");
	scanf("%s", ps->data[ps->size].tele);
	printf("请输入地址>:");
	scanf("%s", ps->data[ps->size].addr);
	ps->size++;
	printf("添加成功\n");
	 /*if (ps->size == MAX)
	{
		printf("通讯录已满\n");
	}
	else
	{
		printf("请输入名字>:");
		scanf("%s", ps->data[ps->size].name);
		printf("请输入年龄>:");
		scanf("%d", &ps->data[ps->size].age);
		printf("请输入性别>:");
		scanf("%s", ps->data[ps->size].sex);
		printf("请输入电话>:");
		scanf("%s", ps->data[ps->size].tele);
		printf("请输入地址>:");
		scanf("%s", ps->data[ps->size].addr);

		ps->size++;
		printf("添加成功\n");
	}*/
}
3.1.3ContactDestroy函数

我们使用内存函数非常非常重要的一件事就是使用完开辟的空间后要free(释放)掉,不然也可能造成内存问题,具体实现很简单直接看代码吧

void DestroyContact(struct Contact* ps)
{
	free(ps->data);
	ps->data = NULL;
}

这样就好了。要在主函数中退出程序处调用此函数

3.2文件操作

**我们在动态版的基础上进行修改
要使用文件操作相关函数先包含头文件<errno.h>

3.2.1增加功能保存ContactSave函数

首先以写的形式打开文件contact.dat,自己在指定路径下创建。然后通过循环和fwrite函数对信息进行写入操作。写入过后将文件关闭

void SaveContact(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->data[i]), sizeof(struct PepInfo), 1, pfWrite);
	}
	printf("保存成功\n");

	fclose(pfWrite);
	pfWrite = NULL;
}

就这样就可以实现文件的操作了最后到主函数相应地方进行调用

3.2.2加载函数LoadContact

在写完上述函数并测试时,我们会发现我们只是将信息保存到文件去了,实际操作时再次运行时控制台中还是没有相应信息。这是因为我们没有对信息进行加载
要实现此功能首先要选定加载的时机,没错就是在初始化函数内,因为我们程序运行时都会进行一次初始化

就像这样。
然后我们来实现load函数
用临时变量tmp来读取之前存储到文件里的信息然后再将信息传给data。

void LoadContact(struct Contact* ps)
{
	struct PepInfo tmp = { 0 };
	FILE* pfRead = fopen("Contact.dat", "rb");
	if (pfRead == NULL)
	{
		printf("LoadContact::%s\n", strerror(errno));
		return;
	}

	while (fread(&tmp, sizeof(struct PepInfo), 1, pfRead))
	{
		CheckCapacity(ps);
		ps->data[ps->size] = tmp;
		ps->size++;
	}
	fclose(pfRead);
	pfRead = NULL;
}

就这样我们就可以实现文件保存的函数,在下一次运行时这些信息也可以很好的打印在屏幕上了

4.完整代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void Menu()
{
	printf("******************************\n");
	printf("**********通讯录生成成功******\n");
	printf("********1.Add***2.Del*********\n");
	printf("*******3.Search***4.Show******\n");
	printf("*******5.Modify***6.Sort*****\n");
	printf("*******7.Save****0.Exit*******\n");
	printf("******************************\n");
}


int main()
{
	int input = 0;

	int n = 0;

	struct Contact con;

	InitContact(&con);

	do
	{
		Menu();
		scanf("%d", &input);
		switch (input)
		{
			case ADD:
				AddContact(&con);
				break;
			case DEL:
				DelContact(&con);
				break;
			case SEARCH:
				SearchContact(&con);
				break;
			case SHOW:
				ShowContact(&con);
				break;
			case MODIFY:
				ModifyContact(&con);
				break;
			case SORT:
				SortContact(&con);
				break;
			case SAVE:
				SaveContact(&con);
				break;
			case EXIT:
				printf("即将关闭通讯录,是否保存本次录入信息:\n1.是\n");
				scanf("%d", &n);
				if (n == 1)
				{
					SaveContact(&con);
				}
				DestroyContact(&con);
				printf("释放成功,已退出程序\n");
				break;
			default:
				printf("选择错误");
				break;
		}
	} while (input);

	return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void InitContact(struct Contact *ps)
{
	/*memset(ps->data, 0, sizeof(ps->data));
	ps->size = 0;*/
	ps->data = (struct PepInfo *) malloc(START_CAPACITY*sizeof(struct PepInfo));
	if (ps->data == NULL)
	{
		return;
	}
	ps->size = 0;
	ps->Capacity = START_CAPACITY;
	LoadContact(ps);
}
void CheckCapacity(struct Contact* ps);

void LoadContact(struct Contact* ps)
{
	struct PepInfo tmp = { 0 };
	FILE* pfRead = fopen("Contact.dat", "rb");
	if (pfRead == NULL)
	{
		printf("LoadContact::%s\n", strerror(errno));
		return;
	}

	while (fread(&tmp, sizeof(struct PepInfo), 1, pfRead))
	{
		CheckCapacity(ps);
		ps->data[ps->size] = tmp;
		ps->size++;
	}
	fclose(pfRead);
	pfRead = NULL;
}

void CheckCapacity(struct Contact* ps)
{
	if (ps->size == ps->Capacity)
	{
		
		struct PepInfo* ptr = realloc(ps->data, (ps->Capacity * 2) * sizeof(struct PepInfo));
		if (ptr != NULL)
		{
			ps->data = ptr;
			ps->Capacity *=2 ;
			printf("扩容成功\n");
		}
		else
		{
			printf("扩容失败\n");
		}
	}
}


void AddContact(struct Contact* ps)
{
	CheckCapacity(ps);

	printf("请输入名字>:");
	scanf("%s", ps->data[ps->size].name);
	printf("请输入年龄>:");
	scanf("%d", &ps->data[ps->size].age);
	printf("请输入性别>:");
	scanf("%s", ps->data[ps->size].sex);
	printf("请输入电话>:");
	scanf("%s", ps->data[ps->size].tele);
	printf("请输入地址>:");
	scanf("%s", ps->data[ps->size].addr);
	ps->size++;
	printf("添加成功\n");
}

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

static int FindContactbyname(const struct Contact *ps,char name[MAX_NAME])
{

	for (int i = 0; i < ps->size; i++)
	{
		if (0 == strcmp(name, ps->data[i].name))
		{
			return i;
		}
	}
	return -1;
}

void DelContact(struct Contact* ps)
{
	char name[MAX_NAME];
	int i = 0;
	int  pos = 0;
	printf("请输入要删除人的名字>:");
	scanf("%s", name);
	pos = FindContactbyname(ps, name);
	if (pos == -1)
	{
		printf("删除的对象不存在\n");
	}
	else
	{
		for (int j = pos; j < ps->size; j++)
		{
			ps->data[j] = ps->data[j + 1];
		}
	}
	printf("删除成功\n");
	ps->size--;
}

void SearchContact(const struct Contact* ps)
{
	char name[MAX_NAME];
	int pos = 0;
	printf("请输入要搜索人的名字\n");
	scanf("%s", name);
	pos = FindContactbyname(ps, name);
	if (pos == -1)
	{
		printf("查找的人不存在\n");
	}
	else
	{
		printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\t\n", "名字", "年龄", "性别", "电话", "地址");
		printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\t\n",
			ps->data[pos].name,
			ps->data[pos].age,
			ps->data[pos].sex,
			ps->data[pos].tele,
			ps->data[pos].addr
		);
		
		
	}
}

void ModifyContact(struct Contact* ps)
{
	char name[MAX_NAME];
	int pos = 0;
	printf("请输入要修改人的名称\n");
	scanf("%s", name);
	pos = FindContactbyname(ps, name);
	if (pos == -1)
	{
		printf("要修改的人不存在\n");
	}
	else
	{
		printf("请输入名字>:\n");
		scanf("%s", ps->data[pos].name);
		printf("请输入年龄>:\n");
		scanf("%d", &ps->data[pos].age);
		printf("请输入性别>:\n");
		scanf("%s", ps->data[pos].sex);
		printf("请输入电话>:\n");
		scanf("%s", ps->data[pos].tele);
		printf("请输入地址>:\n");
		scanf("%s", ps->data[pos].addr);
		printf("修改成功\n");
	}
}

const int* SortByName(const void* c1, const void* c2)
{
	const struct PepInfo* pc1 = (const struct PepInfo*)c1;
	const struct PepInfo* pc2 = (const struct PepInfo*)c2;
	return strcmp(pc1->name, pc2->name);
}

const int* SortByAge(const void* c1, const void* c2)
{
	const struct PepInfo* pc1 = (const struct PepInfo*)c1;
	const struct PepInfo* pc2 = (const struct PepInfo*)c2;
	return pc1->age - pc2->age;
}

const int* SortByTele(const void* c1, const void* c2)
{
	const struct PepInfo* pc1 = (const struct PepInfo*)c1;
	const struct PepInfo* pc2 = (const struct PepInfo*)c2;
	return strcmp(pc1->tele, pc2->tele);
}

int (*CompareFunctions[])(const void*, const void*) =
{
	SortByName,
	SortByAge,
	SortByTele
};


void SortContact(struct Contact* ps)
{
	
	int choice;
	printf("请选择排序规则\n");
	printf("0.按名字排序\n1.按年龄排序\n2.按电话排序\n");
	scanf("%d", &choice);
	if (choice < 0 || choice >= 3)
	{
		printf("无效选择\n");
		return;
	}
	qsort(ps->data,
		ps->size,
		sizeof(struct PepInfo),
		CompareFunctions[choice]);

}

void DestroyContact(struct Contact* ps)
{
	free(ps->data);
	ps->data = NULL;
}

void SaveContact(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->data[i]), sizeof(struct PepInfo), 1, pfWrite);
	}
	printf("保存成功\n");

	fclose(pfWrite);
	pfWrite = NULL;
}

contact.h

#pragma once

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

//#define MAX 1000
#define START_CAPACITY 3//选择通讯录初始容量
//选择通讯录联系人各项信息的最大字符量
#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TELE 12
#define MAX_ADDR 20

enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	SHOW,
	MODIFY,
	SORT,
	SAVE
};

struct PepInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
};

struct Contact
{
	struct PepInfo *data ;
	int size;
	int Capacity;
};



void InitContact(struct Contact* ps);

void AddContact(struct Contact* ps);

void ShowContact(const struct Contact* ps);

void DelContact(struct Contact *ps);

void SearchContact(const struct Contact *ps);

void ModifyContact(struct Contact *ps);

void SortContact(struct Contact *ps);

void DestroyContact(struct Contact *ps);

void SaveContact(struct Contact *ps);

void LoadContact(struct Contact* ps);

5.结语

很快啊动态版和文件操作版就出来了,希望大家可以学到一些东西。也希望可以有人来与我交流不足。
后面,我计划为大家来讲一下数据结构中顺序表和链表(C语言),其实也用了点C++(也只是cout和结构体)。我也是正在学C++和数据结构了。哈哈哈大家一起加油努力学习。

内容概要:本文围绕可变桨叶四旋翼无人机的规范控制与点对点运动模拟展开,重点研究优化推力分配策略在翻转动作中的应用与性能比较。通过Matlab代码实现,构建了四旋翼动力学模型,并设计了多种控制算法以实现精确的姿态调整与轨迹跟踪。研究对比了不同推力分配方案在执行高机动性翻转动作时的稳定性、能耗效率与响应速度,旨在提升无人机在复杂飞行任务中的动态性能与控制精度。该仿真研究为无人机飞控系统的设计与优化提供了理论依据和技术支持。; 适合人群:具备一定自动控制理论基础和Matlab编程能力,从事无人机控制、飞行器动力学或机器人系统研究的科研人员及研究生。; 使用场景及目标:① 实现四旋翼无人机在三维空间中的精确点对点运动控制;② 对比分析不同推力分配策略在执行翻转等高难度动作时的控制效果与能耗表现,优化飞行性能;③ 为无人机自主飞行、特技飞行及复杂环境下的机动控制提供算法验证平台。; 阅读建议:此资源以Matlab仿真为核心,建议读者结合相关控制理论知识,深入理解代码实现细节,重点关注动力学建模、控制律设计与推力分配模块。在学习过程中,应动手调试参数,复现文中翻转动作的仿真结果,并尝试拓展至其他复杂飞行任务,以加深对无人机控制机理的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值