的节点数据值
p->next = NULL; //将新建的节点置为表尾
return head; //返回添加节点后的链表的头指针
}
/* 函数的功能:显示链表中所有节点的节点号和该节点中的数据项的内容*/
void DisplyNode (struct link *head)
{
struct link *p = head;
int j = 1;
while (p != NULL) //若不是表尾,则循环打印节点的数值
{
printf("%5d%10d\n", j, p->data);//打印第j个节点数据
p = p->next; //让p指向下一个节点
j++;
}
}
//函数的功能:释放head所指向的链表中所有节点占用的内存
void DeletMemory(struct link *head)
{
struct link *p = head, *pr = NULL;
while (p != NULL) //若不是表尾,则释放节点占用的内存
{
pr = p; //在pr中保存当前节点的指针
p = p->next;//让p指向下一个节点
free(pr); //释放pr指向的当前节点占用的内存
}
}
上面的代码使用了三个函数AppendNode、DisplyNode、DeletMemory
struct link *AppendNode (struct link *head);(函数作用:新建一个节点并添加到链表末尾,返回添加节点后的链表的头指针)
void DisplyNode (struct link *head);(函数功能:显示链表中所有节点的节点号和该节点中的数据项的内容)
void DeletMemory (struct link *head);(函数功能:释放head所指向的链表中所有节点占用的内存)
(还使用了malloc函数和free函数)
5、malloc函数
作用:用于分配若干字节的内存空间,返回一个指向该内存首地址的指针,若系统不能提供足够的内存单元,函数将返回空指针NULL,函数原型为void *malloc(unsigned int size)
其中size是表示向系统申请空间的大小,函数调用成功将返回一个指向void的指针(void*指针是ANSIC新标准中增加的一种指针类型,
具有一般性,通常称为通用指针或者无类型的指针)常用来说明其基类型未知的指针,即声明了一个指针变量,但未指定它可以指向哪一种基类型的数据,
因此,若要将函数调用的返回值赋予某个指针,则应先根据该指针的基类型,用强转的方法将返回的指针值强转为所需的类型,然后再进行赋值
1 int *pi; 2 pi = (int *)malloc(4);
其中malloc(4)表示申请一个大小为4字节的内存,将malloc(4)返回值的void*类型强转为int*类型后再赋值给int型指针变量pi,即用int型指针变量pi指向这段存储空间的首地址
若不能确定某种类型所占内存的字节数,则需使用sizeof()计算本系统中该类型所占的内存字节数,然后再用malloc()向系统申请相应字节数的存储空间
pi = (int *)malloc(sizeof(int));
6、free函数
释放向系统动态申请的由指针p指向的内存存储空间,其原型为:Void free(void *p);该函数无返回值,唯一的形参p给出的地址只能由malloc()和calloc()申请内存时返回的地址,
该函数执行后,将以前分配的指针p指向的内存返还给系统,以便系统重新分配
为什么要用free释放内存
(在程序运行期间,用动态内存分配函数来申请的内存都是从堆上分配的,动态内存的生存期有程序员自己来决定,使用非常灵活,但也易出现内存泄漏的问题,
为了防止内存泄漏的发生,程序员必须及时调用free()释放已不再使用的内存)
7、单向链表的删除操作
删除操作就是将一个待删除的节点从链表中断开,不再与链表的其他节点有任何联系
需考虑四种情况:
1.若原链表为空表,则无需删除节点,直接退出程序
2.若找到的待删除节点p是头节点,则将head指向当前节点的下一个节点(p->next),即可删除当前节点
3.若找到的待删除节点不是头节点,则将前一节点的指针域指向当前节点的下一节点(pr->next = p->next),即可删除当前节点,当待删除节点是末节点时,
由于p->next值为NULL,因此执行pr->next = p->next后,pr->next的值也变成NULL,从而使pr所指向的节点由倒数第2个节点变成了末节点
4.若已搜索到表尾(p->next == NULL),仍未找到待删除节点,则显示“未找到”,注意:节点被删除后,只是将它从链表中断开而已,它仍占用着内存,必须释放其所占的内存,否则将出现内存泄漏
(头结点不是头指针,注意两者区别)
8、头节点和头指针
头指针存储的是头节点内存的首地址,头结点的数据域可以存储如链表长度等附加信息,也可以不存储任何信息
值得注意的是:
1.无论链表是否为空,头指针均不为空。头指针是链表的必要元素
2.链表可以没有头节点,但不能没有头指针,头指针是链表的必要元素
3.记得使用free释放内存
单向链表的删除操作实现
struct link *DeleteNode (struct link *head, int nodeData)
{
struct link *p = head, *pr = head;
if (head == NULL)
{
printf("Linked table is empty!\n");
return 0;
}
while (nodeData != p->data && p->next != NULL)
{
pr = p; /* pr保存当前节点 */
p = p->next; /* p指向当前节点的下一节点 */
}