对于初学者来说,函数可以写得更简单
void deleteAllOcc( node **headRef, int d )
{
while ( *headRef != NULL )
{
if ( ( *headRef )->data == d )
{
node *temp = *headRef;
*headRef = ( *headRef )->next;
free( temp );
}
else
{
headRef = &( *headRef )->next;
}
}
}
即第一次检查通过引用传递的指向头节点的指针是否相等是多余的。
首先为什么我们使用 **headRef 而不是 *head?
这取决于函数是如何定义的。在您的问题中提供的函数定义的情况下,指向头节点的指针通过引用传递,即通过指向指针头的指针。在这种情况下,更改函数内的指针头,您正在更改原始函数。
例如假设列表只包含一个节点,其数据成员data 等于参数d 的指定值。
主要
node *head = malloc( sizeof( mode ) );
head->data = 1;
head->next = NULL;
deleteAllOcc( &head, 1 );
//...
在函数deleteAllOcc 内你有
if((*headRef)->data==d)
{
temp=*headRef;
*headRef=(*headRef)->next;
free(temp);
}
由于 *headRef 在 main 中产生原始指针 head 然后这个语句
*headRef=(*headRef)->next;
将 main bot 中的原始指针 head 更改为指针值的副本。
当指向头节点的指针不是通过引用传递而是通过值传递时,您可以用其他方式定义函数。但在这种情况下,您需要在 main 中为指向头节点的指针返回可能的新值。
例如
node * deleteAllOcc( node *head, int d )
{
while ( head != NULL && head->data == d )
{
node *temp = head;
head = head->next;
free( temp );
}
if ( head != NULL )
{
for ( node *current = head; current->next != NULL; )
{
if ( current->next->data == d )
{
node *temp = current->next;
current->next = current->next->next;
free( temp );
}
else
{
current = current->next;
}
}
}
return head;
}
并且在 main 中应该调用该函数,例如
node *head = NULL;
//filling the list
head = deleteAllOcc( head, 1 );
正如你所看到的,当指向头节点的指针通过引用传递时的函数定义看起来更简单。
删除节点后我们如何更新节点之间的链接
你有一个指向当前节点的数据成员next 的指针。当前节点的数据成员next指向的节点包含的值等于参数d的值。所以必须删除下一个节点。 ,表示当前节点的数据成员next应该指向被删除节点之后的节点。那就是你需要写
*headRef = ( *headRef )->next;
其中headRef在当前时刻指向当前时刻的数据成员next
节点。
|node1| next | -> |node2| next | -> |node3| next |
| |
headRef node that must be deleted
所以在headRef指向的数据成员next中,你必须写入被删除节点node2的数据成员next的值。
为什么我们没有做 *headRef=(*headRef)->next);在这里?
在这段代码中sn-p
else
{
headRef=&((*headRef)->next);
}
您正在重新分配指针headRef 以指向下一个节点的数据成员next。如果你会写
*headRef = ( *headRef )->next;
那么你将丢失当前指向的数据成员next中的表达式*headRef中存储的值当前指向的节点将被更改为重写存储的指针。