用C语言单链表实现的一个DotA2英雄管理系统(其实我一直羞于承认这算一个系统。。)

本文介绍了一个使用C语言和链表实现的DotA2英雄管理系统,详细讲解了如何通过链表存储数据,以及在VS2015和VC++6.0环境下遇到的函数差异,如scanf_s()的使用,以及文件读写中关于fopen_s()和_fsopen()的问题及解决方案。
摘要由CSDN通过智能技术生成
  学校这两周安排的一个小实习,用C语言做一个小的管理系统,很多学校应该都要求做过这个吧。
  我本人是一名降级生,以前也做过,但并不是自己做的,而是把高年级的拿来糊弄过去了-_-
  这次我打算自己写,毕竟以后真的打算当一名好的程序员(我是真的对此感兴趣)。C语言也自学过有与段时间了,这个小系统的其实也没什么难度,然后就动手了,用周末两天的时间写了出来。

  我是用链表实现数据的存储的,这个链表的头文件和实现,我用的是《C primer plus》上的代码,然后做了一点小小的改动,并且加入了删除节点的功能。

  我是用的使VS2015环境,而学校的机房用的是VC++6.0,有些函数不太一样,如scanf()函数在VS2015要改成scanf_s()fscanf()一样也要改成fscanf_s(),输入整数和浮点数数据时,这几个函数基本是一样的,但在输入字符串时有一点区别,scanf_s()和fscanf_s()需要第三个参数来确定缓冲区的大小。如下所示:

scanf("%s", hero_name)
scanf_s("%s", hero_name, <span style="color:#ff0000;">_BUFFER_</span>)<span style="color:#ff0000;background-color: rgb(204, 204, 204);">//scanf_s()需要第三个参数确定缓冲区大小,在这里我定义_BUFFER_为20</span>

  除了这个区别外,VS2015还不允许使用fopen()函数,一会我写到文件的读取和写入时再讲。

  下面就先写一下链表的头文件与实现。

  下面是链表的头文件。

#pragma once
#ifndef MYLIST_H_
#define MYLIST_H_

#define _BUFFER_ 20

typedef struct hero
{
	char name[_BUFFER_];
	char main_attribute[_BUFFER_];
	int attack;
	float armor;
	int velocity;
	struct attribute
	{
		int power;
		int agile;
		int intelligence;
	}ATTRIBUTE;
}HERO;

typedef struct node
{
	HERO hero;
	struct node *next;
}NODE;

typedef NODE *LIST;

//初始化一个链表
void initialize_list(LIST *plist);

//确定链表是否为空表
int list_is_empty(const LIST *plist);

//确定链表是否已满
int list_is_full(const LIST *plist);

//确定链表中项目的个数
int list_item_count(const LIST *plist);

//在链表尾部添加一个项目
int add_item(HERO hero, LIST *plist);

//从链表中删除一个项目
int delete_item(HERO hero, LIST *plist);

//把一个函数应用于链表中的每一个项目
void traverse(const LIST *plist, void(*pfun)(HERO hero));

//释放已分配的内存
void empty_list(LIST *plist);

#endif
  下面是链表的实现。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include "mylist.h"

//把链表设置为空链表
void initialize_list(LIST *plist)
{
	*plist = NULL;
}

//确定链表是否为空表
int list_is_empty(const LIST *plist)
{
	if (*plist == NULL)
		return 1;
	else
		return 0;
}

//确定链表是否已满
int list_is_full(const LIST *plist)
{
	NODE *pt;

	pt = (NODE *)malloc(sizeof(NODE));
	if (pt == NULL)
	{
		return 1;
		free(pt);
	}
	else
	{
		return 0;
		free(pt);
	}
}

//确定链表中项目的个数
int list_item_count(const LIST *plist)
{
	int count = 0;
	NODE *pnode = *plist;

	while (pnode != NULL)
	{
		count++;
		pnode = pnode->next;
	}

	return count;
}

//在链表尾部添加一个项目
int add_item(HERO hero, LIST *plist)
{
	NODE *pnew;
	NODE *scan = *plist;

	if (list_is_full(plist))
		return 0;

	pnew = (NODE *)malloc(sizeof(NODE));
	pnew->hero = hero;
	pnew->next = NULL;

	if (list_is_empty(plist))
		*plist = pnew;
	else
	{
		while (scan->next != NULL)
			scan = scan->next;
		scan->next = pnew;
	}

	return 1;
}

//从链表中删除一个项目
int delete_item(HERO hero, LIST *plist)
{
	NODE *scan = *plist;
	NODE *pnew;

	if (list_is_empty(plist))
		return 0;

	if (!(strcmp(scan->hero.name, hero.name)))//检查链表中的第一个项目是否需要删除
	{
		*plist = scan->next;
		free(scan);

		return 1;
	}

	while (scan != NULL)
	{
		if (!(strcmp(scan->next->hero.name, hero.name)))
		{
			pnew = scan->next->next;
			free(scan->next);
			scan->next = pnew;

			return 1;
		}
		else
			scan = scan->next;
	}

	return 0;
}

//把一个函数应用于链表中的每一个项目
void traverse(const LIST *plist, void(*pfun)(HERO hero))
{
	NODE *pnode = *plist;
	while (pnode != NULL)
	{
		(*pfun)(pnode->hero);
		pnode = pnode->next;
	}
}

//释放已分配的内存
void empty_list(LIST *plist)
{
	NODE *psave;
	while (*plist != NULL)
	{
		psave = (*plist)->next;
		free(*plist);
		*plist = psave;
	}
}
     
     
    
    
   
   
  接下来就开始写主程序。主函数main()里面使用菜单选项,根据不同的输入进入到不同的函数进行相应的操作,最后退出时将链表中的数据保存到文件中。

  下面展示其中的一个操作,其他的操作都大同小异。

//删除一个英雄
void delete_hero(LIST *plist)
{
	char hero_name[_BUFFER_];
	NODE *scan;
	<span style="color:#ff0000;">int flag = 1;//设置一个标志,用来表示是否找到英雄,初始值为1</span>

	if (list_is_empty(plist))
	{
		printf("\t\t没有英雄数据,请先添加英雄\n");
		return;
	}
	else
		scan = *plist;

	printf("\t\t请输入您要删除的英雄(输入ctrl+z返回):\n\t\t");

	while (scanf_s("%s", hero_name, _BUFFER_) == 1)
	{
		while (scan != NULL)
		{
			if (strcmp(scan->hero.name, hero_name))
				scan = scan->next;
			else
			{
				if (delete_item(scan->hero, plist))
				{
					<span style="color:#ff0000;">save_to_file(plist);</span>
					printf("\t\t英雄删除成功!\n");
					<span style="color:#ff0000;">flag = 0;//若找到英雄,将标志值设置为0</span>
					break;
				}
				else
				{
					printf("\t\t英雄删除失败!\n");
					break;
				}
			}
		}
		<span style="color:#ff0000;">if (flag)//若标志值为1,表示没有找到英雄
			printf("\t\t没有这个英雄\n");</span>

		<span style="color:#ff0000;">flag = 1;//下一次寻找时,将标志值重置为1</span>
		printf("\t\t请继续输入您要删除的英雄(输入ctrl+z返回):\n\t\t");
		scan = *plist;
	}
}

  个人觉得比较巧妙的一个地方在于,使用了一个flag标志来判断是否找到对应的数据,其实这也是很常见的一种办法。还有,在每次应用这个函数后,都会将链表保存到文件一次(其实有点多余了,因为退出程序时也会保存到问价一次,也懒得改了。。)

  下面是如何保存到文件。

//将链表保存到文件中
void save_to_file(const LIS
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值