问题:
1.链表有什么作用?
2.如何使用链表制作一个无限输入的空间,怎样实现需要内存就自动添加?
3.静态链表是什么?动态链表如何制作?
4.链表怎么输入,读取,释放内存?如何将表针移动到指定位置?
问题解决:
1.链表需要一个指向自己的指针:
首先制作一个链表类,结构体中需要放置一个指向自己的对象,对象需要指针类型,不然无法为其分配内存。其他成员根据需要添加。
//---------------------------文明时代游戏无限回合链表-------------------------
typedef struct country
{
long long people;
long long money;
long long ecolomic;
float Technology;
int LandNum;
char ID;
int Exist;
char Name[100];
};
//--------国家类---------
typedef struct LinkList
{
int Num; //链表中第几个
struct
{
int Round;
country* country_object[3450] //文明时代一共3400个地,国家小于3400个。
}Round;
LinkList* next; //链表节点
}LinkList;
图1
上述为文明时代游戏无限回合的链表。
其中next成员能不断指向自己的next形成链表。
2.链表为自己申请内存:
通过实现一个表针实现。首先定义一个表头,把表头的首地址给表针,表针就形成了和表头指向同一地址的指针。
typedef struct LinkList
{
int Num;
int Data;
LinkList* next;
}LinkList;
//定义链表类
LinkList* Head = (LinkList*)malloc(sizeof(LinkList));
//定义表头
LinkList* Needle = (LinkList*)malloc(sizeof(LinkList));
//定义表针
Needle = Head;
//让结构体指针指向同一个地址
图2
然后用如下语句实现不断指向下一个对象。
Needle = Needle->next;
图3
图3实现了表针的移动。最后表针移动到最后需要把指针对象设为NULL方便判定结束。
如下图为新成员申请内存:
void New_Load_Fun(int Num,int Data)
{
Needle->next = (LinkList*)(malloc(sizeof(LinkList)));
//内存申请
if (Needle->next == NULL)
{
exit(1);
}
//内存申请出问题直接返回,因为如下操作在内存申请失败都是非法的,VS会严重警告。
Needle->next->Data = Data;
Needle->next->Num = Num;
//数据给予模块
Needle = Needle->next;
//表针移动模块
}
图3
特别注意:
1.函数的形参本质是获取变量的值付给形参参与函数运算,所以不会改变变量本身的数值。
如果函数的形参是变量的地址,就能将变量的地址赋给形参,形参的操作不会改变地址本身,但是能够改变地址中的值。
2.对于全局变量也是:函数如果直接调用全局变量,那么可以直接改变全局变量的值。
如果函数把全局变量作为形参,那么只是把全局变量的算数值赋值给形参,全局变量值不会被改变。
函数中如果调用了1级指针,那么形参就应该给2级及其以上指针才能改变变量值。
函数操作中调用了n级指针,那么形参就必须给予n+1及其以上级指针才能改变变量值;
3.对于常量,能定义N层指针变量,不断指向一个变量。
对于结构体变量:只有.和->两种调用成员方式,如果定义为:
MyStruct** Object = (MyStruct**)malloc(sizeof(MyStruct));
//定义合法
Object->->next;
//明显调用不合理
图4
上述调用是非法的。
结构体变量无法定义为2级及其以上级别的指针对象。
所以:
void LoadFun(Link* Self)
{
Self->next = (Link*)malloc(sizeof(Link));
/*上述赋值不合法:形参Self是Link*类型,是一级指针
(Link*)malloc(sizeof(Link))申请内存操作是赋值给一级指针的,
此时形参需要是二级指针其值才能被改变。
即Link** Self
*/
}
void LoadFun(Link** Self)
{
*Self->next = (Link*)malloc(sizeof(Link));
/*上述赋值不合法:
Self是二级结构体指针,无法调用成员;即使加了地址访问符:*变成*Self,也无法访问成员。
*/
}
图5
综上:每个注册函数只能专门给某个结构体使用,不能对任意结构体类型使用。
3.将表针移动到指定地方:结构体中定义一个变量int Num;记录这是第几曾指针;
void MoveNeedle_Fun(int DstNum)
{
Needle = Head;
//初始化为0
for(;;)
{
if(Needle->Num == DstNum)
{
break;
}
Needle = Needle->Next;
//表针后移一位
}
}
图6
上述为将表针移动到指定位置。
有了移动表针到任意地方的函数,就能够实现任意位置读入与输出。
4.释放链表内存:
需要再定义一个存储中间量来存储表针的下一个成员next,以防释放了表针位置之后,后面的地址就再也找不到了。
void LinkListFree_Fun()
{
while (1)
{
if (Free_A == NULL)
{
break;
}
Free_B = Free_A->next;
//存储下一个对象的地址
free(Free_A);
//从前往后释放
Free_A = Free_B;
//A的下一个地址再次给A
}
object = NULL;
}
图7
图7代码实现了成员内存逐个释放。