我无法理解使用双指针的链表的C代码的含义。这是我正在阅读的代码
struct list
{
int value;
struct list *next;
};
//Insert an element at the begining of the linked list
void insertBegin(struct list **L, int val)
{
//What does **L mean?
//Memory allocation for the new element temp
struct list *temp;
temp = (struct list *)malloc(sizeof(temp));
//The new element temp points towards the begining of the linked list L
temp->next = *L;
//Set the beginning of the linked list
*L = temp;
(*L)->value = val;
}
void loop(struct list *L)
{
printf("Loop\n");
//Run through all elements of the list and print them
while( L != NULL )
{
printf("%d\n", L->value);
L = L->next;
}
}
struct list* searchElement(struct list *L,int elem)
{
while(L != NULL)
{
if(L->value == elem)
{
printf("Yes\n");
return L->next;
}
L = L->next;
}
printf("No\n");
return NULL;
}
int main()
{
struct list *L = NULL;
insertBegin(&L,10); // Why do I need
return 0;
}
**L
中的insertElement
是什么意思,**L
函数中的*L
和loop
之间有什么区别?为什么在声明struct list *L = NULL
的时候我应该使用参数insertBegin
而不是简单的&L
来调用函数L
?
我猜*L
是指向链表的第一个节点的指针,而**L
可能指向列表的任何元素。但是,我不确定这是否正确。
感谢您的帮助!
答案 0 :(得分:1)
类型**L
被读作指向L的指针。因此,如果你有一个指向L的指针并获取它的地址,那就是你得到的。函数参数(在C中)中的**L
模式通常用于实现" out参数" - 代码可以更新的参数。要在开头插入,您需要更新指向列表头部的指针 - 这就是该函数将指向头部的指针作为参数的原因。分配给*L
时,该函数会更新参数。
答案 1 :(得分:1)
它表示"指向指针的指针"。在C指针中按值传递,因此如果您希望能够修改传递给该函数之外的函数的指针,则必须将指针传递给它。传递指针只会为它传递另一个值,该值将在函数中修改,但不会反映对其外部值的更改。作为指针指针传递基本上允许您修改传递地址的值,而不仅仅是修改本地。
考虑这两个功能:
void foo(int * p, int * t) {
p = t;
}
void foo2(int ** p, int * t) {
*p = t;
}
代码:
int a = 1, b = 2;
int * p = &a;
foo(p, &b);
// in foo *p == 2, but here *p is still == 1, because p didn't change, only the copy that was passed to foo changed
foo2(&p, &b); // now *p == 2, p was changed in foo2
答案 2 :(得分:1)
L存储列表中第一个链接的地址。从而: * L是列表中第一个链接的内容,并且 & L是变量的地址,用于存储列表中第一个链接的地址。
换句话说,通过将参数传递给函数来为列表分配内存和初始化列表的唯一方法是提供& L作为参数。如果您将L作为参数传递,则该函数将接收第一个链接的地址,而是需要一个位置存储第一个链接的地址。
答案 3 :(得分:0)
insertBegin中的双指针用于将L的位置从L所在的位置更改为要插入的节点。在调用你需要的函数& L时,因为你需要通过引用传递它,因为你正在改变L
答案 4 :(得分:0)
如果您希望函数写入参数并在调用者中反映新值,则必须传递该参数的指针:
void foo( T *p ) // for any type T
{
*p = new_value(); // write a new value to the thing p points to
}
void bar( void )
{
T var;
foo( &var ); // foo writes a new value to var
}
如果我们用指针类型T
替换Q *
,则代码为
void foo( Q **p ) // for any type Q
{
*p = new_value(); // write a new value to what p points to
}
void bar( void )
{
Q *var;
foo( &var ); // foo writes a new value to var
}
两种情况下的语义完全相同;我们希望foo
通过指针var
更新p
中存储的值。唯一的区别是在第二种情况下var
已经有一个指针类型,因此p
必须是指向该指针类型的指针。
在您发布的代码中,insertBegin
函数更新L
中存储的值,该值是指向列表头部的指针。由于main中的变量L
具有类型struct list *
,因此L
中参数 insertBegin
的类型必须为struct list **
。