如题所示,本文是围绕链表与函数展开的,也就是如何传进传出以及遇到的问题。
1--
首先观察如下代码,这是之前的知识(套中套那部分),指针p指向一个int变量k,指针pp指向p,
注意他们都是一级指针,所以这里的指针pp紧紧是指向,他具有修改*p也就是k的值的能力,但是!他并没有改变p的地址的能力。
(之前在《遗漏掉的关于字符串,指针以及数组的一些知识(6)字符指针易混》中详细讲过)
#include <stdio.h>
int main() {
int k=0;
int* p=&k;
int* pp=p;
*pp=2;
printf("%d",k);
}
2
--------------------------------
Process exited after 0.077 seconds with return value 0
请按任意键继续. . .
2--
接下来回到主题,将我们上文即《链表的创建》修改为函数:
--node.h--
#ifndef _NODE_H_
#define _NODE_H_
typedef struct node{
int value;
struct node* next;
}node;
#endif
这段代码是有问题的,问题在哪?
看node.c的结尾else里面head=p,结合刚刚第一点我们举的例子,head传进来并没有修改原有main函数里head地址的能力,因为他们都是一级指针!所以怎么解决?
3--
方案一:将这个head定义为全局变量。但是我们讲过这种操作看似简单,实际是投机取巧,无论是从破坏函数封装性还是以后想优化这段代码,都不推荐这种方法。
方案二:
将add函数中的head return给main函数里的head即可,但这并不是最优解,我们想的最优解是能够将main函数里的head的地址传到add函数中,然后直接就可以修改,说到这里已经很明了了,那就是用到二级指针。
所以方案三:(注意传的是head的地址进去)。
要注意一点while循环中是last->next!=NULL,不是last!=NULL,注意分别两者差距。
如果是用尾指针那就是:
注意这里为什么要传tail的地址进去,如果不传tail,然后在add函数中定义一个node* tail=NULL;的话,这里观察主函数,每次调用一下这个函数,那么tail每次被调用时就不能保证都指向最后一个结点,如果定义在主函数,那就不存在这个问题。
--main.h--
#ifndef _MAIN_H_
#define _MAIN_H_
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int value;
struct node *next;
}node;
#endif
--main.c--
#include "main.h"
//typedef struct node{
// int value;
// struct node *next;
//}node;
void add(node** head,node** tail,int number);
int main(int argc,char const *argv[]){
int number=0;
node *head;
node *tail;
head=tail=NULL;
while(number!=-1)
{
scanf("%d",&number);
if (number!=-1)
{
add(&head,&tail,number);
}
}
node *p;
for (p=head;p;p=p->next)
{
printf("%d ",p->value);
}
return 0;
}
void add(node** head,node** tail,int number)
{
node *p=(node*)malloc(sizeof(node));
p->next=NULL;
p->value=number;
node *k=*head;
if (k==NULL)
{
*head=p;
*tail=p;
}
else
{
(*tail)->next=p;\
*tail=p;
}
}
4--讲到这并没有完,恺哥还说了一种方案四!!!
这个方案的好处在于我们用了一种自己定义的数据结构来代表整个链表,虽然我们现在在这个数据结构中只放了一个head,举个例子,我们可以定义一个这个链表的尾指针永远指向链表最后,这样我们就不用每次都要循环才能找到尾指针,而这些元素都在我们所定义的那个链表中,也就是我们用来代表整个链表的数据结构,他不再仅仅是孤立的一个head。
恺哥还讲这个方案有利于以后做项目。(说实话自己并不习惯这样用)
--node.h--
#ifndef _NODE_H_
#define _NODE_H_
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int value;
struct node *next;
}node;
#endif
--node.c--
#include "node.h"
//typedef struct node{
// int value;
// struct node *next;
//}node;
typedef struct{
node* head;
node* tail;
}list;
void add(list* plist,int number);
int main(int argc,char const *argv[]){
int number=0;
list plist;
plist.head=NULL;
while(number!=-1)
{
scanf("%d",&number);
if (number!=-1)
{
add(&plist,number);
}
}
return 0;
}
void add(list* plist,int number)
{
node *p=(node*)malloc(sizeof(node));
p->value=number;
p->next=NULL;
node *last=plist->head;
if (last!=NULL)
{
while (last->next!=NULL)
{
last=last->next;
}
last->next=p;
}else
{
plist->head=p;
}
}
接下来就演示有尾指针的操作:
--main.c--
#include "main.h"
//typedef struct node{
// int value;
// struct node *next;
//}node;
typedef struct{
node* head;
node* tail;
}list;
void add(list* plist,int number);
int main(int argc,char const *argv[]){
int number=0;
list plist;
plist.head=plist.tail=NULL;
while(number!=-1)
{
scanf("%d",&number);
if (number!=-1)
{
add(&plist,number);
}
}
return 0;
}
void add(list* plist,int number)
{
node *p=(node*)malloc(sizeof(node));
p->value=number;
p->next=NULL;
if (plist->head==NULL)
{
plist->head=p;
plist->tail=p;
}
else
{
plist->tail->next=p;
plist->tail=p;
}
}
有尾指针的操作关键点就是plist->tail=p这句,这句话保证了tail一定是指向最后一个结点的,当head不为空时,因为tail指向的是最后一个结点,所以就可以直接用tail去让最后一个结点指向新的结点,然后再让tail指向最后一个结点。
这种方法非常简便!!建议掌握。