c++用户管理信息(类指针数组)

用户管理信息--类指针数组

  • 类示意图
    • select类示意图
    • MyIterator示意图
    • VetorCstu示意图
    • ClassStu示意图
  • 项目源代码
    • select
      • select.h
      • select.cpp
    • MyIterator
      • MyIterator.h
      • MyIterator.cpp
    • VetorCstu
      • VetorCstu.h
      • VetorCstu.cpp
    • ClassStu
      • ClassStu.h
      • ClassStu.cpp
    • main源码
  • 总结---数组管理指针

类示意图

select类示意图

在这里插入图片描述

MyIterator示意图

在这里插入图片描述

VetorCstu示意图

在这里插入图片描述

ClassStu示意图

在这里插入图片描述

项目源代码

select

select.h

#pragma once
#include <iostream>
#include "classstu.h"
#include <iomanip>
#include "cfile.h"
#include "vetorcstu.h"
using namespace std;
///*
//类用于在内存中管理用户信息
//提供增删改查  功能等
//*/
//
class Select
{
public:
	/*
		* select  //构造函数
		* 参数一:传入用户个数,用来申请堆空间
		* 功能  : 初始化类成员
		* 返回值 无
		*
	*/

	Select()
	{
		m_pFile = nullptr;
		m_pcMyStu = 0;
	}

	Select(const char* filename) :m_pFile(new cFile(filename))
	{
		//1 委托构造已经初始化了文件类

		//2  初始化  cmystu内存操作的类
		  //2.1:读取文件头四个字节,保存用户的个数
			int nCount = m_pFile->ReadFileHeader();
		  //实例化cmystu类
			m_pcMyStu = new VetorCstu(nCount);
			if (m_pcMyStu == nullptr)
			{
				cout << "--cmystu--初始化申请内存失败" << endl;
				return;
			}

		//3  往m_pcMyStu里面插入5个ClassStu 初始化类成员
			m_pcMyStu->Insert(nCount);
		// 
		//4  把文件所有数据存放内存中
			m_pFile->ReadFileAllDate(m_pcMyStu);
	}

/*
	* ~select  //析构函数
	* 参数一:无
	* 功能  : 释放类成员申请的堆空间
	* 返回值 无
	*
*/
	~Select();


	/*
		* SelectAllDate
		* 参数一:无
		* 功能  : 把所有用户信息输出到标准设备中(屏幕)
		* 返回值 无
		*
	*/
	void SelectAllDate();

/*
	* FindOneDate
	* 参数一:myiterator
	* 功能  : 根据用户nuserid查找用户信息
	* 返回值 无
	*
*/
	bool FindOneDate(int nUserId);

	/*
		* DrawOneDate
		* 参数一:myiterator
		* 功能  : 输出传入用户的信息
		* 返回值 无
		*
	*/
	void DrawOneDate(MyIterator itr);


	/*
		* SelectFileOffOneDateId
		* 参数一:用户id号
		* 功能  : 根据用户userid,检测是否有当前用户,返回用户的文件偏移
		* 返回值 int类型;返回用户的文件偏移
		*
	*/
	int SelectFileOffOneDateId(int userid);


	/*
		* InsertOneDate
		* 参数一:字符串
		* 功能  : 内存中和文件中插入一个用户信息
		* 返回值 :bool
		*
	*/
	bool InsertOneDate(const char* susername,int nId = 0);


	/*
		* DeleteDate
		* 参数一:用户id -- userid
		* 功能  : 删除指定用户id在文件和内存中的数据
		* 返回值 :无
		*
	*/
	bool DeleteDate(int id);//删除数据

/*
	* UpDate
	* 参数一:const char*   修改的用户名
	* 参数一:用户id -- userid
	* 功能  : 修改用户数据
	* 返回值 :无
	*
*/
	bool UpDate(const char* susername, int nuserid);//修改用户数据

/*
	* callanyname   暂未实现
	* 参数一:
	* 功能  :
	* 返回值 :无
	*
*/
	//void callanyname();



/*
	* drawinit  初始化界面
	* 参数一:无
	* 功能  : //初始化界面
	* 返回值 :无
*/
	void DrawInit();//初始化界面


/*
	* drawhead
	* 参数一:无
	* 功能  : 把用户头部信息输出到标准设备中(屏幕)
	* 返回值 :无
*/
	void DrawHead();//封装显示头部
/*
	* IdEmptyFill
	* 参数一:用户id
	* 功能  : 计算id后面需要填充空格多少
	* 返回值 :无
*/
	int IdEmptyFill(int id);





/*
	* GetFlg
	* 参数一:无
	* 功能  : 获取类成员m_flg的值
	* 返回值 :bool
*/
	bool GetFlg();//记录是否有修改或删除数据的标志


/*
	* ReDEFile
	* 参数一:常量字符串  --文件名
	* 参数二:常量字符串  --新文件名
	* 功能  : 重写文件,把内存数据重新写入到文件中
	* 返回值 :bool 
	*
*/
	bool ReDEFile(const char* old_filename, const char* new_filename);//删除数据



/*
	* bubblesort
	* 参数一:无
	* 功能  : 冒泡排序法--大循环为次数,内循环为第n和第n+1依次往下对比
	* 返回值 :无
*/
	//void bubblesort();
	//排序--选择排序法 --取最小的索引;先比较数大小 --然后放在第i位
/*
	* selectionsort
	* 参数一:无
	* 功能  : 选择排序法--大循环为次数,取最小的索引;先比较数大小 --然后放在第i位
	* 返回值 :无
*/
	//void selectionsort();

	/*
		* insertsort
		* 参数一:无
		* 功能  : 插入排序法-- --依次往上对比;--   次数一次比一次对比多
		* 返回值 :无
	*/
	//void insertsort();
public:
	cFile* m_pFile;  //一个操作文件
	VetorCstu* m_pcMyStu;//一个操作内存

	bool m_flg = false;// 需要重写文件标志 记录是否有修改 或删除过数据  id为0的数据

};

select.cpp

#include "Select.h"


void Select::SelectAllDate()
{
	//显示头部标题
	DrawHead();
	//内存数据进行冒泡排序
	m_pcMyStu->BubbleSort();
	//序号 nIndex
	int nIndex = 1;
	//int nCount = m_cMyStu->GetCount();
	//迭代器输出
	for (auto Val : *m_pcMyStu)
	{
	
		if (Val.m_Id != 0)
		{

			cout << nIndex << setw(14 - (IdEmptyFill(nIndex))) << " ";

			cout << Val.m_Id << setw(8 - (IdEmptyFill(Val.m_Id))) << " ";

			cout << Val.m_StuName->GetStr() << setw(14 - ((Val.m_StuName->GetLen()))) << "  ";

			cout << Val.m_FileOffset << endl;
		}
		else
		{
			m_flg = true;
		}

		nIndex++;
	}

}

bool Select::FindOneDate(int nUserId)
{
	if (nUserId < 0)
	{
		return false;
	}
	MyIterator Itr = m_pcMyStu->Find(nUserId);
	DrawOneDate(Itr);
	return true;
	
}

void Select::DrawOneDate(MyIterator Itr)
{
	if (Itr == nullptr)
	{

		cout << "没有该用户Id" << endl;
		return;
	}

   DrawHead();
//	//打印pFindName查找到的用户信息
	cout << (*Itr).m_Id << setw(8 - IdEmptyFill((*Itr).m_Id)) << " ";
	cout << (*Itr).m_StuName->GetStr()<< setw(14 - (*Itr).m_StuName->GetLen()) << "  ";
	cout << (*Itr).m_FileOffset << endl;
}


//
int Select::SelectFileOffOneDateId(int UserId)
{
	//检查 UserId  // 检测最大是 也是要迭代
	if (UserId <= 0)
	{
		return 0;
	}
	for(auto Val:*m_pcMyStu)
	{
	
		if (UserId == Val.m_Id)
		{

			return Val.m_FileOffset;//返回在文件中的偏移
		}
		
	}
	return 0;
}

bool Select::InsertOneDate(const char* sUserName, int nUserId)
{
	//检测指针和长度
	int nLen = strlen(sUserName);
	if (sUserName == nullptr || nLen == 0)
	{
		cout << "sUserName写入失败" << endl;
		return false;
	}

	//如果为了就是插入新数据 否则是修改数据
	if(nUserId == 0)
	{ 
		nUserId = m_pcMyStu->GetMaxUserId();//用户id
	}

	MyStr* cStr = new MyStr(sUserName);

		//文件中插入数据
	ClassStu* cTmp = m_pFile->WriteInsertFile(cStr, nUserId);
	if (cTmp == nullptr)
	{
		cout << "ClassStu* cTmp写入失败" << endl;
		return false;
	}

	//内存插入数据
	m_pcMyStu->push_back(cTmp);

	//直接赋值cStr 空指针
	cStr = nullptr;
	cTmp = nullptr;
	return true;
}


bool Select::DeleteDate(int nId)
{
	//nId为用户序号  序号-1 为用户的数组索引
	int nIndex = nId - 1;
	int FileOffset = (*m_pcMyStu)[nIndex].m_FileOffset;
	
	if (!FileOffset == 0)
	{
		//需要判断一下  是否找到了
		//获取到文件偏移 修改文件的数据 把用户Id改为0即可
		if (m_pFile->WriteDeleteFile(FileOffset) == 1)
		{
			//内存中删除
			m_pcMyStu->Erase(nIndex);
			m_flg = true;
			return m_flg;
		}
	}
	return false;
}

bool Select::UpDate(const char* sUserName, int nId)
{
	//nId转为 用户的userid
	int nUserId = (*m_pcMyStu)[nId - 1].m_Id;
	//先插入数据
	if (!InsertOneDate(sUserName, nUserId))
	{
		cout << "InsertOneDate失败" << endl;
		return false;
	}
	//在把原来的删除
	if (!DeleteDate(nId))
	{
		cout << "DeleteDate失败" << endl;
		return false;
	}

	return true;
}


void Select::DrawInit()
{
	cout << "========" << "欢迎来到电话薄操作" << "========" << endl;
	//封装一个.cpp文件
	cout << "一:显示所有数据。" << endl;
	cout << "二:查询联系人" << endl;
	cout << "三:增加联系人。" << endl;
	cout << "四:修改联系人。" << endl;
	cout << "五:删除联系人。" << endl;
	cout << "六:随机拨打任意联系人。" << endl;
	cout << "七:退出程序。" << endl;
	cout << "请选择操作:" << endl;

}

//void Select::CallAnyName()
//{
//}

void Select::DrawHead()
{
	cout << "用户序号" << setw(6) << " ";
	cout << "用户ID" << setw(4) << " ";
	cout << "用户名称" << setw(6) << "  ";
	cout << "文件偏移" << endl;
}
int Select::IdEmptyFill(int Id)
{
	int nCount = 0;
	while (Id > 9) {
		Id = Id / 10;  // 整数除法,相当于取整除
		nCount++;
	}
	return nCount;
}

	bool Select::GetFlg()
	{
		return m_flg;
	}

	bool Select::ReDEFile(const char* old_filename, const char* new_filename)
	{
		return m_pFile->ReDeFileName(old_filename, new_filename,m_pcMyStu);
	}

Select::~Select()
{
	delete m_pcMyStu;
	delete m_pFile;
}

MyIterator

MyIterator.h

#pragma once
#include "ClassStu.h"

class MyIterator
{

public:

	/*******************构造函数系列开始***********************/
/*
	* MyIterator
	* 参数一 :无
	* 功能   :初始化类成员
	* 返回值 :无

*/
	MyIterator();
	
	/*
		* MyIterator
		* 参数一 :ClassStu** 数据成员的指针
		* 参数二 :当前指向ClassStu* 成员索引
		* 参数三 :成员的个数
		* 功能   :使用类来管理指针,使数组更安全的遍历
		* 返回值 :无

	*/
	MyIterator(ClassStu** cStuStart, int nIndex,int nMax);

	

	/*
		* MyIterator
		* 参数一 :MyIterator&
		* 功能   :默认构造 浅拷贝
		* 返回值 :无

	*/




	/*******************构造函数系列结束***********************/


	/*******************运算符重载函数系列结开始***********************/

/*
	* operator*
	* 参数一 :无
	* 功能   :返回当前用户信息
	* 返回值 :ClassStu&

*/

	ClassStu& operator*();

	/*
		* operator++
		* 参数一 :无
		* 功能   :数组往前移动一位
		* 返回值 :ClassStu& 引用

	*/

	MyIterator& operator++();

	/*
		* operator--
		* 参数一 :无
		* 功能   :数组往前移动一位
		* 返回值 :MyIterator& 引用

	*/

	MyIterator& operator--();


	/*
		* operator !=(MyIterator Iterator)
		* 参数一 :MyIterator
		* 功能   :用来判断begin 和end   迭代使用
		* 返回值 :MyIterator& 引用

	*/

	bool operator !=(MyIterator Iterator);


/*
	* operator ==(MyIterator Iterator)
	* 参数一 :MyIterator
	* 功能   :用来判断begin 和end   迭代使用
	* 返回值 :MyIterator& 引用

*/

	bool operator ==(void* pVoid);

	/*******************运算符重载函数系列结结束***********************/
private:
	ClassStu** m_cStuStart;
	int m_nIndex;//指向成员的索引值
	int m_nMax;//最成员的个数
};


MyIterator.cpp

#include "MyIterator.h"

MyIterator::MyIterator()
{
	m_cStuStart = nullptr;
	m_nIndex = 0;
	m_nMax = 0;
}

MyIterator::MyIterator(ClassStu** cStuStart, int nIndex,int nMax)
{
	m_cStuStart = cStuStart;
	m_nIndex = nIndex;
	m_nMax = nMax;
}

ClassStu& MyIterator::operator*()
{
	return **m_cStuStart;
}

MyIterator& MyIterator::operator++()//这里有问题
{
	
	if (m_nIndex == m_nMax)
	{
		m_nIndex++;
		return *this;
	}
	m_nIndex++;
	m_cStuStart++;
	return *this;
}
//
MyIterator& MyIterator::operator--()
{

	if (m_nIndex == 0)
	{
		return *this;
	}
	m_nIndex--;
	m_cStuStart--;
	return *this;
}
//
bool MyIterator::operator!=(MyIterator Iterator)
{
	if (m_nIndex == ((Iterator.m_nMax)))
	{
		return false;
	}
	return true;
}

bool MyIterator::operator==(void* pVoid)
{
	if (m_cStuStart == pVoid)
	{
		return true;
	}
	return false;
}

VetorCstu

VetorCstu.h

#pragma once
#include "ClassStu.h"
#include "MyIterator.h"

class VetorCstu
{
public:
	/*******************构造函数系列开始***********************/
/*
	* VetorCstu
	* 参数一 :无
	* 功能   :初始化类成员,默认构造30个
	* 返回值 :无

*/
    VetorCstu(int InitNumber = 0);
/*
	* VetorCstu
	* 参数一 :无
	* 功能   :析构函数  释放堆空间资源
	* 返回值 :无

*/

	~VetorCstu();

	/*******************构造函数系列结束***********************/


	/*******************增删改查函数系列开始***********************/


/*
* Insert
* 参数一 :int 插入的位置
* 参数二 :ClassStu*
* 功能   : 数组中指定位置插入一个成员
* 返回值 :bool

*/
	bool Insert(int nPos,ClassStu* cStu);

/*
	* push_back
	* 参数一 :ClassStu*
	* 功能   :数组中尾部插入一个成员
	* 返回值 :无  

*/
	void push_back(ClassStu* cStu);

/*
	* Insert
	* 参数一 :int nCount
	* 功能   :数组成员实例化ClassStu->nCount个
	* 返回值 :无

*/
	void Insert(int nCount);
/*
	* push_front
	* 参数一 :ClassStu*
	* 功能   :数组首部插入一个成员
	* 返回值 :无

*/
	void push_front(ClassStu* cStu);
/*
	* Erase
	* 参数一 :int  数组的索引值
	* 功能   :数组中删除指定成员 --- 老式删除方法:从数组中移除      另一种删除软删除方法成员属性ClassStu->m_id 改为0
	* 返回值 :bool

*/
	void Erase(int nPos);


/*
	* pop_back
	* 参数一 :无
	* 功能   :删除数组最后一个成员
	* 返回值 :无

*/
	void pop_back();

/*
	* Front
	* 参数一 :无
	* 功能   :访问第一个数组成员
	* 返回值 :ClassStu&

*/
	ClassStu& Front();


/*
	* Front
	* 参数一 :无
	* 功能   :访问最后一个数组成员
	* 返回值 :ClassStu&

*/
	ClassStu& Back();


/*
	* Find
	* 参数一 :int
	* 功能   :通过用户m_Id查找到用户信息
	* 返回值 :MyIterator

*/
	MyIterator Find(int nUserId);


	/*******************增删改查函数系列结束***********************/


	/*******************检查访问数组类开始***********************/
/*
	* IsEmpty
	* 参数一 :无
	* 功能   :检查容器是否为空
	* 返回值 :bool   不为0 返回真

*/
	bool IsEmpty();


/*
	* IsFind
	* 参数一 :int
	* 功能   :通过用户Id返回在数组中的索引
	* 返回值 :int   返回用户的索引,没有返回-1

*/
	int IsFind(int nUserId);

	/*
	* size
	* 参数一 :无
	* 功能   :返回成员个数
	* 返回值 :int

*/
	int Size();



/*
	* GetMaxUserId
	* 参数一:无
	* 功能  : 获取用户最大的UserId号
	* 返回值 :int  返回用户最大UserId号
	*
*/
	int GetMaxUserId();

	/*******************检查访问数组类结束***********************/


	/********************friend函数**Iterator迭代器********************/



/*
	* Begin
	* 参数一 :无
	* 功能   :数据首个元素 迭代器返回自定义MyIterator,来操作数据
	* 返回值 :无

*/
	MyIterator begin()  //return构造可以返回同等类型
	{
		return MyIterator(m_cStu, 0, m_nCount);
	}
/*
	* Begin
	* 参数一 :int  成员索引
	* 功能   :数据+ nIndex元素 ,来操作数据
	* 返回值 :无

*/
	MyIterator begin(int nIndex)  //return构造可以返回同等类型
	{
		return MyIterator(m_cStu+ nIndex, nIndex, m_nCount);
	}
/*
	* End
	* 参数一 :无
	* 功能   :数据最后一个元素 迭代器返回自定义MyIterator,来操作数据
	* 返回值 :无

*/
	MyIterator end()
	{
		return MyIterator(m_cStu, m_nCount, m_nCount);
	}
/*
	* EmptyItr
	* 参数一 :无
	* 功能   :迭代器Itr赋值为空
	* 返回值 :无

*/
	MyIterator EmptyItr()
	{
		return MyIterator(nullptr, 0, 0);
	}
	/********************friend函数**Iterator迭代器****结束***************/



	/********************运算符重载系列开始********************/
/*
	* ClassStu& operator[](int nIndex)
	* 参数一 :数组成员索引
	* 功能   :实现可以取出每个成员用户信息
	* 返回值 :无
*/

	ClassStu& operator[](int nIndex)
	{
		if (nIndex<0 || nIndex >= m_nSumCount)
		{
			//这里应该报错,超出了边界
			return *m_cStu[m_nSumCount];
		}

		return *m_cStu[nIndex];
	}

	/********************运算符重载系列结束********************/






	/********************数据排序开始****************************/
/*
	* BubbleSort
	* 参数一 :无
	* 功能   :冒泡排序法
	* 返回值 :无
*/
	void BubbleSort();

//
选择性--排序法
//void Select::SelectionSort()
//{
//	ClassStu* pTmpMin = new ClassStu;
//	int nMinIndex = 0;
//	for (int i = 0; i < m_nCount - 1; i++)
//	{
//		//保存堆数组的第一个元素
//		nMinIndex = i;
//		for (int k = i + 1; k < m_nCount; k++)
//		{
//			if (m_pSelePhone[nMinIndex].m_Id < m_pSelePhone[k].m_Id)
//			{
//				nMinIndex = k;
//			}
//		}
//		//这里做交换的值;把索引i存起来
//		memcpy_s(pTmpMin, sizeof(ClassStu), &m_pSelePhone[i], sizeof(ClassStu));
//		//把最小的放到I中
//		memcpy_s(&m_pSelePhone[i], sizeof(ClassStu), &m_pSelePhone[nMinIndex], sizeof(ClassStu));
//		//把I放到值放到nMinIndex中
//		memcpy_s(&m_pSelePhone[nMinIndex], sizeof(ClassStu), pTmpMin, sizeof(ClassStu));
//
//	}
//	//释放临时变量空间
//	delete pTmpMin;
//}
//
插入排序法
//void Select::InsertSort()
//{
//	ClassStu* pTmpMin = new ClassStu;
//	int j = 0;
//	for (int i = 1; i < m_nCount; i++)
//	{
//		//赋值给临时变量
//		memcpy_s(pTmpMin, sizeof(ClassStu), m_pSelePhone + i, sizeof(ClassStu));
//		j = i - 1;
//
//		while (j >= 0 && m_pSelePhone[j].m_Id > pTmpMin->m_Id)
//		{
//			memcpy_s(m_pSelePhone + j + 1, sizeof(ClassStu), m_pSelePhone + j, sizeof(ClassStu));
//			j = j - 1;
//		}
//
//		memcpy_s(m_pSelePhone + j + 1, sizeof(ClassStu), pTmpMin, sizeof(ClassStu));
//
//	}
//
//}



	/********************数据排序结束****************************/


	/********************获取成员数据****************************/






private:
	ClassStu** m_cStu;
    int m_nCount;//当前有new了多少个ClassStu*类
	int m_nSumCount;//容量总大小
	int m_nStep = 10;//每次增加10
	
};


VetorCstu.cpp

#include "VetorCstu.h"

VetorCstu::VetorCstu(int InitNumber)
{
	m_nCount = 0;
	m_nSumCount = InitNumber + m_nStep;
	m_cStu = new ClassStu*[m_nSumCount];//初始化了ClassStu*数组

}

VetorCstu::~VetorCstu()
{
	if (m_cStu != nullptr)
	{

		//要先析构*m_cStu里面的成员
		//析构要判断数组里面存在的指针是否重复,重复的只释放一次
		ClassStu** cStu = m_cStu;

		for (int i = 0; i < m_nCount; i++)
		{
			delete *cStu;
			cStu++;
		}

		delete[] m_cStu;
	}

}

bool VetorCstu::Insert(int nPos,ClassStu* cStu)
{
	//越界判断
	if (nPos < 0)
	{
		return false;
	}
	//指针判断
	if (cStu == nullptr)
	{
		return false;
	}
	//容器满了,需要扩容
	if (m_nCount == m_nSumCount)//要重新申请内存
	{
		m_nSumCount = m_nCount + m_nStep;
		//申请新的空间
		ClassStu** cStu = m_cStu;
		m_cStu = new ClassStu*[m_nSumCount];
		//把原来的数据全部移动的新的空间里面
		memcpy_s(m_cStu, m_nSumCount * 4, cStu, m_nCount*4);
		//这里要删除cStu  //但是删除会里面
		delete[] cStu;
	}
	//插入位置判断  头部、中间  尾部  
	// 头部、中间 需要计算向后移动多少位置
	if (nPos != m_nCount)
	{
		//计算后面还有多少个数
		int nSize = (m_nCount - nPos) * 4;
	  memcpy_s(m_cStu + nPos + 1, m_nCount * 4, m_cStu + nPos, nSize);
	}

	m_cStu[nPos] = cStu;

	m_nCount++;
	return true;
}
void VetorCstu::push_back(ClassStu* cStu)
{
	//Insert里面 有判断cStu是否为空
	Insert(m_nCount, cStu);
}
void VetorCstu::Insert(int nCount)
{
	for (int i = 0; i < nCount; i++)
	{
		ClassStu* cStu = new ClassStu;
		push_back(cStu);
	}
}
void VetorCstu::push_front(ClassStu* cStu)
{
	//Insert里面 有判断cStu是否为空
	Insert(0, cStu);
}
void VetorCstu::Erase(int nPos)
{
	//1:先判断nPos删除的位置
	if (nPos < 0 || nPos >= m_nCount)
	{
		return;
	}
	//2: 释放指针下的内存空间
	delete *(m_cStu + nPos);

	//3:计算后面还有多少个数,进行移动位置
	if ((m_nCount - 1) != nPos)
	{
	int nSize = (m_nCount - nPos - 1) * 4;
	memcpy_s(m_cStu + nPos, m_nCount * 4, m_cStu + nPos + 1, nSize);
	}
	m_cStu[m_nCount - 1] = 0;
	m_nCount--;
}

void VetorCstu::pop_back()
{
	Erase(m_nCount - 1);
}

ClassStu& VetorCstu::Front()
{
	if (m_nCount == 0)
	{
		cout << "数据成员为空:报错" << endl;

	}
	return *m_cStu[0];
}

ClassStu& VetorCstu::Back()
{
	if (m_nCount == 0)
	{
		cout << "数据成员为空:报错" << endl;

	}
	return *m_cStu[m_nCount -1];
}

MyIterator VetorCstu::Find(int nUserId)
{

	int nIndex = IsFind(nUserId);

	if (nIndex == -1)
	{
		return EmptyItr();
	}

	return this->begin(nIndex);
}



bool VetorCstu::IsEmpty()
{

	return m_nCount != 0;
}

int VetorCstu::IsFind(int nUserId)
{
	int nIndex = 0;
	for (auto Val : *this)
	{
		if (Val.m_Id == nUserId)
		{

			return nIndex;
		}

		nIndex++;

	}
	return -1;
}

int VetorCstu::Size()
{
	return m_nCount;
}

//
//
//
//bool VetorCstu::Delete(int nIndex)
//{
//	//判断索引nIndex是否越界
//	if (nIndex < 0 || nIndex > m_nCount)
//	{
//		return false;
//	}
//	//把学生类的成员Id置为0
//	m_cStu[nIndex]->m_Id = 0;
//	
//	return true;
//}
//

//
//MyIterator VetorCstu::FindCstu(int UserId)
//{
//
//	//首先判断userid
//	int MaxId = GetMaxUserId();
//	MaxId--;
//	if (UserId < 0 || UserId > MaxId)
//	{
//		return  MyIterator(nullptr, 0, 0);
//	}
//	int nIndex = Find(UserId);
//	if (nIndex == -1)//没有找到用户的UserId
//	{
//		return  MyIterator(nullptr, 0, 0);
//	}
//	return MyIterator(m_cStu + nIndex,m_nCount,nIndex);
//}
//
//
//
//
//
int VetorCstu::GetMaxUserId()
{

		//保存最大索引
	if (m_nCount == 0)
	{
		return 1;
	}
	int nMaxIndex = 0;

	//获取m_pSelePhone->Id的最大索引
	for (int k = 0; k < m_nCount - 1; k++)
	{
		if (m_cStu[k]->m_Id < m_cStu[k + 1]->m_Id)
		{
			nMaxIndex = k + 1;
		}
	}

	//返回最大的Id ++
	return m_cStu[nMaxIndex]->m_Id + 1;
}
//
void VetorCstu::BubbleSort()
{
	//先定义一个变量   这里交换不能用new
	ClassStu* cPtm = nullptr;
	//两层循环
	for (int i = 0; i < m_nCount - 1; i++)
	{
		//用第i和值和所有的都比较一遍
		for (int k = 0; k < m_nCount - i - 1; k++)
		{
			if (m_cStu[k]->m_Id > m_cStu[k + 1]->m_Id)//Id值比他大就交换到后面去
			{
				//先保存&m_pSelePhone[k]的内存
				cPtm = m_cStu[k];
				//把&m_pSelePhone[i]的数据保存到&m_pSelePhone[k]位置
				m_cStu[k] = m_cStu[k + 1];
				//把&m_pSelePhone[k]的数据保存到临时变量
				m_cStu[k + 1] = cPtm;
			}
		}

	}
}
//
//int VetorCstu::GetCount()
//{
//	return m_nCount;
//}

ClassStu

ClassStu.h

#pragma once
#include "ClassStr.h"
class ClassStu
{
public:
	/*******************构造函数系列开始***********************/
/*
	* ClassStu
	* 参数一 : int --学生Id
	* 参数二 : ClassStr字符串 --学生姓名
	* 参数三 : int --文件中的储存偏移
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	ClassStu();

	/*
		* ClassStu(ClassStu& cStu)
		* 参数一 : ClassStu&
		* 功能   :默认构造,浅拷贝
		* 返回值 :无
	*/
	ClassStu(ClassStu& cStu);


/*
	* ClassStu
	* 参数一 : int --学生Id
	* 参数二 : ClassStr字符串 --学生姓名
	* 参数三 : int --文件中的储存偏移
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	ClassStu(int Id, const char* Name, int FileOffset = 0);



/*
	* ClassStu(int Id, const char* Name, int FileOffset = 0)
	* 参数一 : int --学生Id
	* 参数二 : MyStr*字符串 --学生姓名
	* 参数三 : int --文件中的储存偏移
	* 功能   :默认构造,初始化类成员 --为空
	* 返回值 :无
*/
	ClassStu(int Id, MyStr* cStr, int FileOffset = 0);
/*
	* ClassStu
	* 无
	* 功能   :析构函数 --释放空间资源
	* 返回值 :无
*/
	~ClassStu();

	/*******************构造函数系列结束***********************/

	/*******************运算符重载***********************/


/*
	* operator=
	* 参数一 :ClassStu*
	* 功能   :=号运算符重载,浅拷贝
	* 返回值 :无
*/ 


	void operator=(ClassStu* cStu);

/*
	* operator=
	* 参数一 :ClassStu&
	* 功能   :=号运算符重载,浅拷贝
	* 返回值 :无
*/

	//void operator=(ClassStu cStu);

/*
	* operator=
	* 参数一 :ClassStu&
	* 功能   :=号运算符重载,浅拷贝
	* 返回值 :ClassStu&   可以连续=  a=b=c  注:当函数返回时就可以等了   
*/

	ClassStu& operator=(ClassStu& cStu);



/*
	* operator*
	* 参数一 :ClassStu
	* 功能   :*运算符重载,返回用户姓名缓存
	* 返回值 :char*
*/

	char* operator*();




/*
	* operator==
	* 参数一 :ClassStu
	* 功能   :判断是否为空类
	* 返回值 :char*
*/

	bool operator== (void* pVoid);

	/*******************获取类成员***********************/
/*
	* IsEmpty()
	* 参数一 :无
	* 功能   :判断是否为空  m_StuName
	* 返回值 :bool  字符串不为空返回真 为空返回假
*/
	bool IsEmpty();

/*
	* InitClass()
	* 参数一 :无
	* 功能   :封装初始化成员函数
	* 返回值 :无
*/
	void InitClass();

/*
	* IsClear()
	* 参数一 :无
	* 功能   :清除自身
	* 返回值 :无
*/
	void IsClear();
	/*******************获取类成员结束***********************/

	/*******************序列化***********************/

	bool Serialize(FILE* pFile);//序列化--从内存写入文件

	bool Deserialize(FILE* pFile);//反序列化--从文件读到内存

	/*******************序列化***********************/
//类成员信息公开
public:
	int m_Id; //ID
	MyStr* m_StuName;//用户名称
	int m_FileOffset;//存在文件的偏移

	int* m_nIndex;
};


ClassStu.cpp

#include "ClassStu.h"

ClassStu::ClassStu()
{
	InitClass();

}


ClassStu::ClassStu(ClassStu& cStu)
{
	if (cStu == nullptr || cStu.m_StuName == m_StuName)
	{
		InitClass();
		return;
	}

	if (cStu.m_nIndex == nullptr)
	{
		//引用技术
		cStu.m_nIndex = new int(0);
	}

	m_Id = cStu.m_Id;
	m_FileOffset = cStu.m_FileOffset;
	m_StuName = cStu.m_StuName;
	m_nIndex = cStu.m_nIndex;
	(*m_nIndex)++;

}

ClassStu::ClassStu(int Id, const char* Name, int FileOffset)
{
	if (Name == nullptr)
	{
		InitClass();
		return;
	}
	m_StuName = new MyStr(Name);
	m_nIndex = new int(0);
	m_Id = Id;
	m_FileOffset = FileOffset;

}

ClassStu::ClassStu(int Id, MyStr* cStr, int FileOffset)
{
	if (cStr == nullptr)
	{
		InitClass();
		return;
	}
	m_StuName = cStr;
	m_nIndex = new int(0);
	m_Id = Id;
	m_FileOffset = FileOffset;


}

ClassStu::~ClassStu()
{
	IsClear();
}

void ClassStu::operator=(ClassStu* cStu)
{

	if (cStu == nullptr || cStu->m_StuName == m_StuName)
	{
		InitClass();
		return;
	}

	if (cStu->m_nIndex == nullptr)
	{
		//引用技术
		cStu->m_nIndex = new int(0);
	}

	//先清除自身
	IsClear();
	m_Id = cStu->m_Id;
	m_FileOffset = cStu->m_FileOffset;
	m_StuName = cStu->m_StuName;

	m_nIndex = cStu->m_nIndex;
	(*m_nIndex)++;
}

ClassStu& ClassStu::operator=(ClassStu& cStu)
{

	if (cStu == nullptr || cStu.m_StuName == m_StuName)
	{
		return *this;
	}

	if (cStu.m_nIndex == nullptr)
	{
		//引用技术
		cStu.m_nIndex = new int(0);
	}
	//先清除自身
	IsClear();
	m_Id = cStu.m_Id;
	m_FileOffset = cStu.m_FileOffset;
	m_StuName = cStu.m_StuName;
	m_nIndex = cStu.m_nIndex;
	(*m_nIndex)++;
	return *this;
}





char* ClassStu::operator*()
{
	return m_StuName->GetStr();
}

bool ClassStu::operator==(void* pVoid)
{
	if (this == nullptr)
	{
		return true;
	}
	return false;
}

bool ClassStu::IsEmpty()
{
	return m_StuName->GetStr() != nullptr;
}

void ClassStu::InitClass()
{

	m_StuName = nullptr;
	m_nIndex = nullptr;
	m_Id = 0;
	m_FileOffset = 0;

}

void ClassStu::IsClear()
{
	if (m_StuName == nullptr)
	{
		return;
	}
	if (*m_nIndex != 0)
	{
		(*m_nIndex)--;
		return;
	}

	cout << "m_StuName" << m_Id << endl;
	delete m_nIndex;
	delete m_StuName;
}

bool ClassStu::Serialize(FILE* pFile)
{
	//2:将文件偏移指向要写入的位置

	fseek(pFile, 0, SEEK_END);//移动到尾部开始写入

	//3.0 获取文件偏移,后面可以写入
	int FileOffset = ftell(pFile);
	m_FileOffset = FileOffset;

	if (FileOffset == -1L)
	{
		return false;
	}
	//3.1 先写入学生Id

	if (fwrite(&m_Id, 1, 4, pFile) != 4)
	{
		return false;
	}

	//3.2 再写入用户名称的字符串长度
	char nLen = m_StuName->GetLen();
	if (fwrite(&nLen, 1, 1, pFile) != 1)
	{
		return false;
	}
	//3.3 写入用户的姓名
	if (fwrite(m_StuName->GetStr(), 1, nLen, pFile) != nLen)
	{
		return false;
	}
	//3.4 写入文件偏移
	if (fwrite(&FileOffset, 1, 4, pFile) != 4)
	{
		return false;
	}


	return true;
}

bool ClassStu::Deserialize(FILE* pFile)
{

	//2.1 先读用户的ID
	if (fread(&m_Id, 1, 4, pFile) != 4)
	{
		return false;
	}
	//2.2 在读字符串的字节数
	char nLen = 0;
	if (fread(&nLen,1, 1, pFile) != 1)
	{
		return false;
	}
	//2.3 在读字符串
	m_StuName = new MyStr(nLen);
	if (fread(m_StuName->GetStr(), 1, nLen, pFile) != nLen)
	{
		return false;
	}

	//2.4 在读文件偏移
	if (fread(&m_FileOffset, 1, 4, pFile) != 4)
	{
		return false;
	}

	return true;

}

main源码

#include "Select.h"
#include <conio.h>

int main()
{
	//初始化;已经把文件数据读入内存中
	Select MySele2("mystudate.bin");
	int selectId = 0;	//保存操作的选择
	while (selectId != 7)
	{
		system("cls");
		//初始化界面
		MySele2.DrawInit();
		scanf_s("%d", &selectId);//获取用户的输入
		if (selectId < 0 || selectId > 7)
		{
			cout << "输入错误,请重新输入" << endl;
			continue;
		}

		switch (selectId)
		{
			case 1:
			{
				MySele2.SelectAllDate();//显示所有数据
			
				break;

			}
			case 2://查询单个联系人
			{
				
				int nUserId = 0;
				cout << "请输入用户Id:" << endl;
				scanf_s("%d",&nUserId);
				MySele2.FindOneDate(nUserId);
				break;
			}
			case 3://增加联系人
			{
				char sUserName[32] = { 0 };//保存用户的输入查找用户名
				memset(sUserName, 0, 32);
				cout << "请输入姓名:" << endl;
				//获取到用户输入的姓名
				scanf_s("%s", sUserName, 32);
				MySele2.InsertOneDate(sUserName);
				break;
			}
			case 4://修改联系人
			{
				char sUserName[32] = { 0 };//保存用户的输入查找用户名
				memset(sUserName, 0, 32);
				//先修改文件 :先把要修改的删除操作,在新增一项即可 ,序号
				int nId = 0;
				cout << "请输入要求改的用户序号" << endl;
				scanf_s("%d", &nId);
				//获取成员个数、 检测是否超出边界
				int nSize = MySele2.m_pcMyStu->Size();
				if (nId < 1 || nId > nSize)
				{
					cout << "删除失败" << endl;
					break;
				}

				cout << "请输入要修改的名字" << endl;
				scanf_s("%s", sUserName, 32);
				
				//修改数据
				MySele2.UpDate(sUserName, nId);
			

				break;
			}
			case 5://删除联系人
			{
			
				//填写用户ID
				cout << "请输入要删除的用户序号" << endl;
				int nIndex = 0;
				scanf_s("%d", &nIndex);

				int nSize = MySele2.m_pcMyStu->Size();
				if (nIndex < 1 || nIndex > nSize)
				{
					cout << "删除失败" << endl;
					break;
				}

				if (MySele2.DeleteDate(nIndex) == false)
				{
					cout << "删除失败" << endl;
				}

			}
		
		}

		system("pause");


	}
	//退出后,如果有删除 修改文件。则要重写文件
	if (MySele2.GetFlg())
	{
		//重新将内存数据写入文件
		MySele2.ReDEFile("mystudate.bin", "mystudate_old.bin");
	}
	return 0;

}


总结—数组管理指针

时间复杂度

  • 查看数据成员 —直接索引下标—o(1) 常量阶
  • 插入数据—需要移动数据–o(n)线性阶
  • 删除数据—需要移动数据–o(n)线性阶
  • 搜索数据—需要遍历–o(n)线性阶

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/369812.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux Shell命令系列--basename获取基本文件名

一、目的 学习linux shell编程的第一步就是熟悉linux的各种命令的使用&#xff0c;本篇开始逐次介绍一些常用linux shell命令。 今天我们来讲解basename命令的使用。 二、介绍 1、基本概念 basename命令首先去除字符串末尾多余的斜杠&#xff08;如果有的话&#xff09;&#…

【AG32VF407】国产MCU+FPGA Verilog双边沿检测输出方波

视频讲解 [AG32VF407]国产MCUFPGA Verilog双边沿检测输出方波 实验过程 本次使用使用AG32VF407开发板中的FPGA&#xff0c;使用双clk的双边沿进行检测&#xff0c;同步输出方波 同时可以根据输出的方波检测clk的频率&#xff0c;以及双clk的相位关系&#xff0c;如下为verilog…

【c++】vector用法详解

vector用法详解 vector定义vector容器的构造函数vector容器内元素的访问1.通过下标 [ ]来访问2.通过迭代器来访问3.通过范围for来访问 vector常用函数的用法解析1.size()2.clear()3.capacity()4.reserve()5.resize()6.shrink_to_fit()7.pop_back()8.push_back()9.erase()10.in…

父类之王“Object”类和内部类

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;&#x1f468;&#x1f3fb;‍&#x1f393;告别&#xff0c;今天 &#x1f4d4;高质量专栏 &#xff1a;☕java趣味之旅 欢迎&#x1f64f;点赞&#x1f5e3;️评论&#x1f4e5;收藏&#x1f493;关注 &#x1f496;衷心的希…

ES6-let

一、基本语法 ES6 中的 let 关键字用于声明变量&#xff0c;并且具有块级作用域。 - 语法&#xff1a;let 标识符;let 标识符初始值; - 规则&#xff1a;1.不能重复声明let不允许在相同作用域内重复声明同一个变量2.不存在变量提升在同一作用域内&#xff0c;必须先声明才能试…

企查查headers动态加密参数(附代码)

声明 本文以教学为基准、本文提供的可操作性不得用于任何商业用途和违法违规场景。 本人对任何原因在使用本人中提供的代码和策略时可能对用户自己或他人造成的任何形式的损失和伤害不承担责任。 如有侵权,请联系我进行删除。 这里只是我分析的分析过程,以及一些重要点的记录…

c语言:贪吃蛇的实现

目录 贪吃蛇实现的技术前提&#xff1a; Win32 API介绍 控制台程序&#xff08;console&#xff09; 控制台屏幕上的坐标 GetStdHandle GetConsoleCursorInfo CONSOLE_CURSOR_INFO SetConsoleCursorInfo SetConsoleCursorPosition GetAsyncKeyState 宽字符的打印 …

企业在什么情况下需要一款固定资产管理系统?

在现代商业环境中&#xff0c;企业的固定资产是其运营和发展的重要基础。然而&#xff0c;许多企业在固定资产管理方面面临着挑战&#xff0c;如信息不准确、效率低下和资源浪费等问题。为了解决这些问题&#xff0c;越来越多的企业开始意识到引入一款固定资产管理系统的重要性…

BLIP-2:低计算视觉-语言预训练大模型

BLIP-2 BLIP 对比 BLIP-2BLIPBLIP-2如何在视觉和语言模型之间实现有效的信息交互&#xff0c;同时降低预训练的计算成本&#xff1f;视觉语言表示学习视觉到语言的生成学习模型架构设计 总结主要问题: 如何在计算效率和资源有限的情况下&#xff0c;有效地结合冻结的图像编码器…

【NTN 卫星通信】基于NTN的多3GPP连接应用场景

1 概述 同时聚合两条3GPP接入链路&#xff0c;其中一条为非地面网络&#xff0c;可以提供以下5G业务使能&#xff0c;尤其适用于带宽有限或接入链路不可靠的服务不足地区:   -扩展流动宽频   -超可靠的服务通信 如技术报告38.821所述&#xff0c;若干服务场景(例如在偏远地…

时间序列预测 —— ConvLSTM 模型

时间序列预测 —— ConvLSTM 模型 时间序列预测是一项重要的任务&#xff0c;ConvLSTM&#xff08;卷积长短时记忆网络&#xff09;是深度学习领域中用于处理时序数据的强大工具之一。本文将介绍 ConvLSTM 的理论基础、优缺点&#xff0c;与其他常见时序模型&#xff08;如 LS…

golang开发window环境搭建

1.本人开发环境&#xff1a;window10,idea2020.1.3 2.Go语言环境版本1.5.1 2.1. go语言插件 下载地址 csdn - 安全中心 2.2下载安装 3.idea配置go环境 4.创建go项目 、5.运行

ShardingSphere 5.x 系列【4】产品介绍

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 简介2. 核心特性2.1 数据分片2…

空中加油3D可视化:引领航空领域的新革命

随着科技的日新月异&#xff0c;我们生活的方方面面都在发生着深刻的变化。而在航空领域&#xff0c;3D可视化技术正在引领新的革命。它不仅为飞行员提供了一种全新的视角&#xff0c;更在保障飞行安全、提高飞行效率方面发挥着不可替代的作用。 在传统的空中加油中&#xff0c…

无人机遥感技术在地质灾害监测应用分析,多旋翼无人机应急救援技术探讨

地质灾害是指在地球的发展演变过程中&#xff0c; 由各种自然地质作用和人类活动所形成的灾害性地质事件。给人民的生命和财产安全带来严重威胁&#xff0c;因此有必要开展地质灾害预测预报、灾害应急和风险区划 遥感技术的快速发展为我们提供了一种获取实时灾害信息的可靠手段…

Echarts+Vue 首页大屏静态示例Demo 第三版

效果图: 源码: <template><div class="content bg" style="height: 100vh;overflow-y: auto" :class="{ fullscreen-container: isFullScreen }"><div class="reaDiv" style="height: 10vh"><div…

FPGA项目(16)——基于FPGA的音乐演奏电路

1.设计要求 能在实验箱上&#xff0c;循环播放一段音乐。&#xff08;需要源码的直接看最后一节&#xff09; 2.设计原理 组成乐曲的每个音符的发音频率值及其持续的时间是乐曲能连续演奏所需要的两个基本要素&#xff0c;问题是如何来获取这两个要素所对应的数值以及通过纯硬件…

幻兽帕鲁内存溢出怎么办,一键设置定时重启,修改虚拟内存,定时清理,轻松解决卡顿!再也不怕爆内存了!

幻兽帕鲁的内存溢出问题&#xff0c;玩久了确实会变卡。这里给出三个解决思路&#xff1a; 第一种方法是定时进行内存清理&#xff08;装个软件就可以&#xff09;&#xff0c;网上也有很多教程&#xff0c;我会把下载地址放在文章后面&#xff0c;大家可以去下载。第二种方法…

c语言二叉树的创建,三种遍历方式,销毁

二叉树的创建 typedef char datatype; typedef struct Node {datatype data;struct Node *left_child;struct Node *right_child;}*Btree; //二叉树的创建 Btree create_node() {Btree t(Btree)malloc(sizeof(struct Node));if(NULLt)return NULL;t->data0;t->left_chil…

Unity项目从built-in升级到URP(包含早期版本和2023版本)

unity不同版本的升级URP的方式不一样&#xff0c;但是大体流程是相似的 首先是加载URP包 Windows -> package manager,在unity registry中找到Universal RP 2023版本&#xff1a; 更早的版本&#xff1a; 创建URP资源和渲染器​​ 有些版本在加载时会自动创建&#…