链表(C语言)
我们新建一个空链表并对其进行头插
//定义单链表结构体
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
//申请一个新节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("malloc fail");
return;
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
while (plist)
{
printf("%d->", plist->data);
plist = plist->next;
}
printf("NULL\n");
}
// 错误的单链表头插方式
void SListPushFrontfault(SListNode* pplist, SLTDateType x)
{
SListNode* NewNode = BuySListNode(x);
if (pplist == NULL)
{
pplist = NewNode;
}
else
{
NewNode->next = pplist;
pplist = NewNode;
}
}
//代入main函数进行测试
int main()
{
SListNode* phead = NULL;
SListPushFrontfault(phead, 1);
SListPushFrontfault(phead, 2);
SListPushFrontfault(phead, 3);
SListPushFrontfault(phead, 4);
SListPrint(phead);
return 0;
}
运行以上代码我们的预期结果是头插1,2,3,4,打印出来应该为
而实际结果却是
例:编写一个swap函数来交换两个变量的值
我们都知道,如果我们编写以下函数
void swap(int a,int b)
{
int c=a;
a=b;
b=c;
}
这个函数不会对传入的a,b的值产生任何影响,因为函数中的a,b只是一个局部变量,出函数之后a,b便已经销毁,不会改变传入的值
而如果我们需要改变传入的值,我们必须传入a,b的地址,通过对地址的访问来改变a,b的值
void swap(int *a,int *b)
{
int c=*a;
*a=*b;
*b=c;
}
同样,我们在对该函数传参的时候,则必须取其地址传入
swap(&num1,&num2);
而为什么对于单链表的头插传入地址却无法改变他们的值?
因为对于swap函数,我们想改变的是int变量,故只需要传入int变量的地址
而对于该头插函数,我们需要改变的是int(SLTDataType)*变量,改变的是一个指针变量,故需要传入的是指针变量的地址
通过以下图我们可以更好去了解
通过图片我们可以很清晰看出,如果我们传入的是同级变量,那么传入的都会被视为局部变量
而如果我们传入的是上一级变量,则传入的是全局变量的地址,修改的是全局变量
在main函数中,我们先定义了int* phead=NULL;
而在头插的函数中,如果phead为空,则使phead=NewNode;
这里并不是让phead指向NewNode,而是让phead的值等于NewNode,NewNode也是一个指针变量,所以我们的操作实际是修改了phead的值,故改变第一级需要传入第二级,问题得到了解决。
我们沿用引例1中的代码,新建一个非空头结点的单链表并对其进行尾插
//定义单链表结构体
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
//申请一个新节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("malloc fail");
return;
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
while (plist)
{
printf("%d->", plist->data);
plist = plist->next;
}
printf("NULL\n");
}
// 错误的单链表尾插方式
void SListPushBackfault(SListNode* pplist, SLTDateType x)
{
SListNode* NewNode = BuySListNode(x);
SListNode* Lhead = pplist;
if (pplist == NULL)
{
pplist = NewNode;
}
else
{
while (Lhead->next)
{
Lhead = Lhead->next;
}
Lhead->next = NewNode;
}
}
//代入main函数进行测试
int main()
{
SListNode* phead = NULL;
SListNode HeadNode;
HeadNode.data = 0;
HeadNode.next = NULL;
phead = &HeadNode;
SListPushBackfault(phead, 1);
SListPushBackfault(phead, 2);
SListPushBackfault(phead, 3);
SListPushBackfault(phead, 4);
SListPrint(phead);
return 0;
}
与引例1一样,如果我们对空链表进行该尾插,同样会因为局部变量问题而尾插失败,其仍为空链表。
但是在该情况下,我们对非空链表进行尾插,最终得到的结果却大相径庭
为什么在该情况便尾插成功了呢?
我们注意到尾插函数中的如下一段代码
while (Lhead->next)
{
Lhead = Lhead->next;
}
Lhead->next = NewNode;
该代码的意义是找到尾结点,然后对尾结点进行尾插,我们不难发现,这里并没有出现plist
我们需要改变的是结构体变量而非指针变量,通过类比1的图进行理解:
而Lhead刚好为TailNode的地址,即为*TailNode,故改变了Lhead便改变了TailNode的值
如果不想改变传入的变量,便只用传入同级的参数,即与图中在同一层
(例如单链表的打印只传入了头结点的指针而非二级指针)
如果目的是改变传入的参数,那么需要传入上一级的指针,即与图中在上一层