这个问题是在一次尾插法创建单链表的时候发现的。
以往写这个函数CreatLinkList()总是习惯不给它传入参数,然后用一个链表指针作为返回值,在主函数中接受,即LinkList CreatLinkList(void)。
然后想了一下,我在写其它单链表函数比如插入删除的时候总是用布尔类型作为返回值,直接让链表头指针L传入函数中,比如:bool ListInsert(LinkList L,int i,int e),也总是能够成功。
于是我就这样写了一次创建链表的函数:
Status CreatList(LinkList L)
{
L=(LinkList)malloc(sizeof(LNode));
if(L==NULL) exit(1);
else
L->next=NULL;
LinkList Ptail=L;
Ptail->next=NULL;
int i,len,val;
printf("请输入您需要的链表长度:");
scanf("%d",&len);
for(i=1;i<=len;i++)
{
printf("请输入%d个结点的数据:",i);
scanf("%d",&val);
LinkList p=(LinkList)malloc(sizeof(LNode));
p->data=val;
Ptail->next=p;
Ptail=p;
Ptail->next=NULL;
}
printf("%d",L->next->data);
return OK;
}
创建完当进行遍历的时候,发现出故障了,想了很长时间也没找到原因,一个最大最大的问题就是为什么就创建函数不能这样写,但其它都能成功呢?
看来还是我指针的知识没有学好。
原来应该是这样的,
比如,主函数里有个变量m,想通过函数改变m的值需要传入m的地址(指针),如果想改变m的指针的值,需要传入m的指针的指针。
创造链表的时候,刚开始L指向空,是空指针,现在想让L指向一个新的结点(头结点),实际是改变了指针的指向,或者说是指针变量保存的地址,而不是地址里面存的东西的内容,那么就需要传入L的指针LinkList *p,在插入删除函数中之所以可以直接传入L,是因为函数没有改变L的指向,而是改变了L指向的变量所以可以直接传入这些内容的指针也就是L
所以就有两种解决方案,一种是直接返回一个链表指针,还有一种就是利用二级指针
LinkList CreatList(void)
{
LinkList L=(LinkList)malloc(sizeof(LNode));
if(L==NULL) exit(1);
else
L->next=NULL;
LinkList Ptail=L;
Ptail->next=NULL;
int i,len,val;
printf("请输入您需要的链表长度:");
scanf("%d",&len);
for(i=1;i<=len;i++)
{
printf("请输入%d个结点的数据:",i);
scanf("%d",&val);
LinkList p=(LinkList)malloc(sizeof(LNode));
p->data=val;
Ptail->next=p;
Ptail=p;
Ptail->next=NULL;
}
return L;
}
当这个问题解决之后,突然想起来不久前,在写数据结构实验的时候,有一个很简单的约瑟夫环问题,当时也遇到了类似的情况。
问题描述如下:
先给出约瑟夫环的成功代码:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct YSFLNode{
int data;
int password;
struct YSFLNode *next;
}YSFLNode,*YSFLPtr;
YSFLPtr CreatYSFL(void);
bool DeleteYSFL(YSFLPtr *t,int m,int *e);//删除按照t的后继的序号为1顺时针第m个结点,并把新的m返回到e中
int n;
int main()
{
YSFLPtr L;
L=CreatYSFL();
int m;
int e=0;
printf("请输入您想设定的初始值m:");
scanf("%d",&m);
YSFLPtr t=L;//一直指向p的前驱
while(n)
{
DeleteYSFL(&t,m,&e);
m=e;
}
return 0;
}
YSFLPtr CreatYSFL(void)//头指针指向末尾
{
YSFLPtr tail,p;
tail=NULL;
printf("请输入总人数:");
int i,val;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
printf("请输入第%d个人的密码:",i);
scanf("%d",&val);
p=(YSFLPtr)malloc(sizeof(YSFLNode));
if(tail==NULL)
{
p->next=p;
tail=p;
tail->data=i;
tail->password=val;
}
else
{
p->next=tail->next;
tail->next=p;
tail=p;
tail->data=i;
tail->password=val;
}
}
return tail;
}
bool DeleteYSFL(YSFLPtr *t,int m,int *e)
{
int j;
YSFLPtr p=(*t)->next;
for(j=1;j<=(m-1)%n;j++)
{
*t=p;
p=p->next;
}
printf("%d ",p->data);
*e=p->password;
(*t)->next=p->next;
free(p);
n--;
return true;
}
起初的时候对于函数DeleteYSFL()传入的函数就是链表指针t,但结果一直错误,然后当时也赖得管,就直接把这个函数去掉了,一起放到了主函数里面就浑浑噩噩成功了。现在明白了原因,把传入的YSFLPtr 类型改成了二级指针YSFLPtr *就成功了!
最后再对我写的代码做一点解释:
为什么for(j=1;j<=(m-1)%n;j++)里面要取余n?
n是现在剩下的总人数,由于是循环链表,为了省时间做一个取余,结果还是一样的!
效果如下: