学校这两周安排的一个小实习,用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;
}
}
下面展示其中的一个操作,其他的操作都大同小异。
//删除一个英雄
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