C++学生信息管理系统(有头链表+文件存取)

C++数据结构:有头链表+文件存取操作

  • 编译环境:vs2019;
  • 注意事项:点个关注吧;
  • 由于代码较多,不贴出完整代码,会挑出主要部分来叙述,我会将源文件上传CSDN,并在文末附上百度网盘链接,有需要可自行下载,若链接失效可评论获取;
  • 建议:各位小伙伴在阅读的时候可以一个函数一个函数的阅读,方便理解;
  • 注:文章仅作为自己成长的记录,不足之处还请多指教(师承大帅)。
运行截图:

C++学生信息管理系统(有头链表+文件存取)_第1张图片

项目分析
  • 有头链表就是通过一个头部指针来操作整个的数据,然后又通过指针互相连接,串在一起;大家可以联想老鹰捉小鸡时,母鸡和小鸡排在一起用手拉着对方的情形;

  • 有头链表也可参考下图:
    C++学生信息管理系统(有头链表+文件存取)_第2张图片

  • 结构体嵌套问题:
    C++学生信息管理系统(有头链表+文件存取)_第3张图片

初始化数据域:
p_Node initNode()
{
	p_Node pN = (p_Node)malloc(sizeof(Node));
	if (!pN)exit(OVERFLOW);
    //exit(OVERFLOW)是强行退出程序
    //这里就是如果指针内存分配失败,强行退出程序
	pN->age = 0;
	pN->number = 0;
   //指针通过动态内存申请可变为变量,SIZE是我定义的宏
	pN->name = (char*)malloc(sizeof(char) * SIZE);
	if (!pN->name)exit(OVERFLOW);

	return pN;
}
初始化指针域:
p_Data createHead()
{
	p_Data p_Head = (p_Data)malloc(sizeof(Data));
	if (!p_Head)exit(OVERFLOW);
	p_Head->next = NULL;
	return p_Head;
}
将节点变为数据:
p_Data createData(p_Node Node)
{
	p_Data p_NewData = (p_Data)malloc(sizeof(Data));
	if (!p_NewData)exit(OVERFLOW);

	p_NewData->next = NULL;
	p_NewData->node = initNode();
    //字符串不能直接赋值,要进行拷贝
	int strLeng = strlen(Node->name) + 1;
	//strlen计算的长度中没有算'/0',终止符,所以要加1;
	strcpy_s(p_NewData->node->name, strLeng, Node->name);
	p_NewData->node->age = Node->age;
	p_NewData->node->number = Node->number;

	return p_NewData;
}
保存函数
  • 文件写操作的一般步骤(读和写步骤一样):
  • 创建写文件流对象 ->打开文件 -> 判断文件是否打开 -> 写入文件 -> 关闭文件;
  • 这里 ios::app 是以追加的方式写文件,否则会覆盖原有文件;
int saveFile(p_Data p_Head)
{
	ofstream ofs;
	ofs.open(FILENAME, ios::binary | ios::out | ios::app);

	if (!ofs.is_open())
	{
		cout << "保存文件时,打开文件失败..." << endl;
		return Error;
	}

	p_Data pMove = p_Head->next;
	if (pMove == NULL)
	{
		cout << "未保存,链表没有数据..." << endl;
		ofs.close();
		return Error;
	}

	while (pMove != NULL)
	{
		ofs << pMove->node->name<<" "<< pMove->node->age<<" "
			<< pMove->node->number << endl;
		pMove = pMove->next;
	}
	ofs.close();
	cout << "保存成功..." << endl;
	return Ok;
}
读取文件:
int readFile(p_Data p_Head)
{
    
	p_Data curData = p_Head->next;
	if (curData != NULL)
	{
		free(curData);
		curData = NULL;
	}
	p_Head->next = NULL;
    //至于上面这里这样写的作用,大家可以注释后感受一下
    //注释快捷键(vs2019中):ctrl+k+c
	ifstream ifs;
	ifs.open(FILENAME, ios::binary | ios::in);
	if (!ifs.is_open())
	{
		cout << "读文件时打开失败..." << endl;
		return Error;
	}

	p_Node Node = initNode();
	//int num = 0;调试作用

	while (ifs >> Node->name >> Node->age >> Node->number)
	{
		insertHead(p_Head, Node);
		//num++;调试作用
	}
	//这里是我调试的时候写的
	/*cout << "循环了" << num << "次" << endl;
	cout << "文件读取完毕..." << endl;*/
	ifs.close();
	cout << "成功读入文件..." << endl;
	return Ok;
}
判断输入类型
  • 因为用户选择功能的方式是输入Int类型的数字,如果不对用户的输入做判断,当用户char类型或其他类型数据时,系统会崩掉或者陷入无线循环,所以最好判断一下输入;
  • cin.fail()判断输入的类型和定义的类型是否一致,一致返回true,否则返回false;
int select;
cin >> select;
if (!cin.fail())
遇到的问题:
  • 文件在读取时数据不正确;
  • 读取的结点数据未能正确保存;
产生原因
  • 结构体赋值时只是进行了简单的赋值操作;
  • 指针指向不明确,出现了野指针;
  • 错误代码1:
p_Data createData(p_Node Node)
{
	p_Data p_NewData = (p_Data)malloc(sizeof(Data));
	if (!p_NewData)exit(OVERFLOW);
	p_NewData->next = NULL;
	p_NewData->node = Node;
	return p_NewData;
}
  • 改正1
p_Data createData(p_Node Node)
{
	p_Data p_NewData = (p_Data)malloc(sizeof(Data));
	if (!p_NewData)exit(OVERFLOW);

	p_NewData->next = NULL;
	p_NewData->node = initNode();

	int strLeng = strlen(Node->name) + 1;
	strcpy_s(p_NewData->node->name, strLeng, Node->name);
	p_NewData->node->age = Node->age;
	p_NewData->node->number = Node->number;

	return p_NewData;
}
  • 错误代码2
//readFile()函数中的代码
p_Data curData = p_Head->next;
	if (curData != NULL)
	{
		free(curData);
		curData = NULL;
	}
  • 改正2:
p_Data curData = p_Head->next;
	if (curData != NULL)
	{
		free(curData);
		curData = NULL;
	}
	p_Head->next = NULL;
结语:
  • 如果本文对小伙伴有帮助,还望点个关注,我会推出更多优质文章的;
  • 关于该项目的主要几点和内容分析我就分析到这儿,如有疑问可私信或评论讨论,不足之处还请各位大佬指教,最后附上项目的网盘链接(嫌弃下载慢的可在我上传的资源中下载):https://pan.baidu.com/s/1SlIiR0ih_DNI9fzDy0aLng 提取码:260y

你可能感兴趣的:(C++基础,c++,小程序)