关于链表使用二级指针或者一级指针引用的问题:
1、使用二级指针完全可以代替一级指针。在没有头结点的情况下必须使用二级指针,使用一级指针无效。
2、而如果不用二级指针,直接传一个一级指针,相当于生成L的拷贝M,但是对M分配空间与L无关了。
3、只要是修改头指针则必须传递头指针的地址,否则传递头指针值即可(即头指针本身)。这与普通变量类似,当需要修改普通变量的值,需传递其地址,否则传递普通变量的值即可(即这个变量的拷贝)。使用二级指针,很方便就修改了传入的结点一级指针的值。 如果用一级指针,则只能通过指针修改指针所指内容,却无法修改指针的值,也就是指针所指的内存块。所以创建链表和销毁链表需要二级指针或者一级指针引用。
4、不需要修改头指针的地方用一级指针就可以了,比如插入,删除,遍历,清空结点。假如头指针是L,则对L->next 及之后的结点指针只需要传递一级指针。
5、比如一个结点p,在函数里要修改p的指向就要用二级指针,如果只是修改p的next指向则用一级指针就可以了
函数中传递指针,在函数中改变指针的值,就是在改变实参中的数据信息。但是这里改变指针的值实际是指改变指针指向地址的值,因为传递指针就是把指针指向变量的地址传递过来,而不是像值传递一样只是传进来一个实参副本。所以当我们改变指针的值时,实参也改变了。
headlist.h:
#ifndef _HEADLIST_H
#define _HEADLIST_H
#define OK 0
#define ERROR -1
typedef struct _node
{
char name[10];
int data;
struct _node *next;
}Node;
//创建链表
Node *createList();
// 尾法插入元素
int insertLast(Node *head);
//输出通讯录内容
void display(Node *head);
//在指定位置插入元素
int insertPos(Node *head,int pos);
//根据姓名删除元素
int deleteData(Node *head,char *name);
//根据姓名修改元素ID
int modifyData(Node *head,char *name);
//根据id查找元素
int LocateElem(Node *head,int data);
//逆序
int ReverseLinkList(Node *head);
#endif
headlist.c:
#include"headlist.h"
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
//创建链表就是创建一个头结点
Node *createList()
{
Node * pNode=(Node*)malloc(sizeof(Node)/sizeof(char));
if(pNode==NULL)
{
printf("Failed to create header\n");
return NULL; //返回值类型为指针,所以用NULL
}
pNode->next=NULL;
return pNode;
}
//逆序
int ReverseLinkList(Node *head)
{
if(head==NULL)
return ERROR;
Node *tmp1=head->next;
head->next=NULL;
while(tmp1)
{
Node *tmp2=tmp1;
tmp1=tmp1->next;
tmp2->next=head->next;
head->next=tmp2;
}
return OK;
}
//根据id查找元素
int LocateElem(Node *head,int data)
{
if(head==NULL)
return ERROR;
Node *tmp=head;
while(tmp)
{
if(tmp->data==data)
{
printf("找到的元素信息为:\n");
printf("%s\n",tmp->name);
printf("%d\n",tmp->data);
break;
}
tmp=tmp->next;
}
return OK;
}
//根据姓名修改元素ID
int modifyData(Node *head,char *name)
{
if(head==NULL)
return ERROR;
Node *tmp=head;
while(tmp)
{
if(strcmp(tmp->name,name)==0)
{
int data;
printf("请输入元素修改后的ID:\n");
scanf("%d",&data);
tmp->data=data;
return OK;
}
tmp=tmp->next;
}
return ERROR;
}
//根据姓名删除元素
int deleteData(Node *head,char *name)
{
if(head==NULL)
return ERROR;
Node *tmp=head;
while(tmp->next) //为了跨结点连接
{
if(strcmp(tmp->next->name,name)==0)
{
//tmp->next=tmp->next->next;
//free(tmp->next);
Node *p=tmp->next; /* 为什么要 p */
tmp->next=p->next;
free(p);
return OK; //正确删除,返回ok
}
tmp=tmp->next;
}
return ERROR;
}
//根据位置插入元素
int insertPos(Node *head,int pos)
{
if (head == NULL)
return ERROR;
//遍历到元素的位置,准备插入
int i;
Node *tmp=head;
for(i=0;i<pos-1;i++)
{
if(tmp==NULL)
{
printf("没有pos 这个位置\n");
return ERROR;
}
tmp=tmp->next;
} //tmp遍历到pos-1处
//为新结点创建空间并赋值
Node *node=(Node*)malloc(sizeof(Node)/sizeof(char));
if(node==NULL) //此处 起初将Node 写成node ,malloc 没有成功,报错 "invalid next size (fast):"
return ERROR;
int data;
char name[10];
printf("请输入插入用户的姓名:\n");
scanf("%s",name);
printf("请输入插入用户的ID:\n");
scanf("%d",&data);
strcpy(node->name,name);
node->data=data;
//新结点的指针域指向 tmp 的后继,tmp 指向新结点node,完成插入
node->next=tmp->next;
tmp->next=node;
return OK;
}
// 尾法插入数据
int insertLast(Node *head)
{
if (head == NULL)
return ERROR;
//为新插入的结点创建空间并赋值
Node * node = (Node*)malloc(sizeof(Node)/sizeof(char));
if (node == NULL)
return ERROR;
int data;
char name[10];
printf("请输入好友姓名\n");
scanf("%s",name);
printf("请输入好友ID\n");
scanf("%d",&data);
strcpy(node->name,name); //新结点的赋值
node->data = data;
node->next = NULL;
// 找最后一个结点,准备插入
Node *tmp = head;
while (tmp->next)
{
tmp = tmp->next;
}
//将尾结点的指针域指向新结点,完成尾插
tmp->next = node;
return OK;
}
void display(Node *head)
{
if (head == NULL)
return; //void 类型函数返回值写法
// 第一个结点
Node *tmp = head->next;
while (tmp)
{
printf("%s\n",tmp->name);
printf ("%d\n", tmp->data);
tmp = tmp->next; // 下一个元素
}
printf ("\n");
}
main.c
#include<stdio.h>
#include<stdlib.h>
#include "headList.h"
int main()
{
printf("欢迎来到苏嵌教育\n");
Node *pNode=createList();
if(pNode==NULL)
return ERROR;
int i,pos,a,data;
char name[10];
for(i=0;i<3;i++)
{
insertLast(pNode); //如果用二级指针,这里的实参要改为 &pNode, .c 和 .h 文件中的函数形参要改为
} //Node **head, 函数中 head 要改为 (*head)
printf("尾插法后的通讯录为:\n");
display(pNode);
while(1)
{
printf("请选择以下功能;\n");
printf("1.插入好友信息\n");
printf("2.删除好友信息\n");
printf("3.修改好友信息\n");
printf("4.查找好友\n");
printf("5.通讯录逆序查看\n");
printf("6.退出\n");
scanf("%d",&a);
if(a>6)
printf("无此功能\n");
switch(a)
{
case 1:
printf("请输入要插入的位置:\n");
scanf("%d",&pos);
insertPos(pNode,pos);
printf("插入新元素后的通讯录为:\n");
display(pNode);
break;
case 2:
printf("请输入要删除元素的姓名:\n");
scanf("%s",name);
deleteData(pNode,name);
printf("删除元素后的通讯录为:\n");
display(pNode);
break;
case 3:
printf("请输入要修改元素的姓名:\n");
scanf("%s",name);
modifyData(pNode,name);
printf("修改后的通讯录为:\n");
display(pNode);
break;
case 4:
printf("请输入要查找元素的id:\n");
scanf("%d",&data);
LocateElem(pNode,data);
break;
case 5:
ReverseLinkList(pNode);
printf("逆序后的通讯录为:\n");
display(pNode);
break;
case 6:
exit(0);
break;
}
}
return OK;
}