常规的创建单链表(FIFO和FILO都行)和遍历的题。
typedef和struct的声明可以写在一起。
链表所有的处理函数,不管有没有必要,都使用二级指针(Node**)传入,保证接口的一致性。
现在的代码还要要求代码风格了,至于什么是代码风格我也不是太清楚。
大概是:
1.模块化的程序设计,功能用子函数来做,接口尽量做到同一。
2.遵循命名规则,比如函数用驼峰命名法,枚举变量和符号常量用全大写,变量取有意义的名字等,必要时使用下划线。
3.代码整体清爽,结构清晰。
4.良好的代码习惯,拒绝野指针,单入单出。
为什么要使用二级指针
就单链表而言,头结点有两种,一种是存数据的,另一种是单纯利用其指针域指向下一个节点。
前者像这样
由于头结点也存储了数据,所以使得链表在修改头结点时就遇到了麻烦,比如在移除头结点时,如果传入函数的是头结点的一级指针,由C语言的传值特性,不能修改外界的指针内容。
此时我们利用形参FuncHead修改链表后,外界的HeadPtr的值并没有改变
比如我们想移除头结点,使第二个节点变成新的头结点
当函数执行结束后,形参空间被释放,外界的HeadPtr值并没有改变
外界只能看到他
此时如果再用HeadPtr去访问链表,程序会去读0x0001处的内存,但是这片内存已经被回收了,程序会卡死。
当我们传入二级指针时
就可以透过二级指针来修改头结点的位置,达到修改链表入口的目的。
其实对于不用修改头结点的函数,并不需要传入二级指针,一级已经够用。
但是为了方便记忆,统一传入二级指针,免得在实际运用中需要区分。
上面还有第二种,就是单独用一个节点的指针域指向存有数据的节点,而其本身不存数据的,像这样。
此时只需要修改哨兵的指针域,就可以实现链表入口位置的变化,此时只需要传入一级指针。
显得更为方便。缺点也很明显,如果数据域比较大,会浪费掉一个数据域的空间,其里面没有存储数据。
#include <stdio.h>
#include <stdlib.h>
typedef struct _node
{
int data;
struct _node* nextPtr