1

我无法理解关于使用双指针的链表的 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*Lloopstruct list *L = NULLinsertBegin&LL

我猜*L是指向链表第一个节点的指针,而**L可能指向链表的任何元素。但是,我不确定这是否正确。

谢谢您的帮助!

4

5 回答 5

2

它的意思是“指向指针的指针”。在 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
于 2015-03-12T16:27:53.560 回答
1

该类型**L被读取为指向 L 的指针。因此,如果您有一个指向 L 的指针并获取其地址,那就是您得到的。in 函数参数(在 C 中)的模式**L通常用于实现“输出参数”——代码可以更新的参数。要在开头插入,您需要更新指向列表头部的指针 - 这就是该函数将指向头部的指针作为参数的原因。分配给 时*L,函数会更新参数。

于 2015-03-12T16:25:38.870 回答
1

L 存储列表中第一个链接的地址。因此: *L 是列表中第一个链接的内容,&L 是存储列表中第一个链接地址的变量的地址。

换句话说,通过将参数传递给函数来为列表分配内存和初始化列表的唯一方法是提供 &L 作为参数。如果您将 L 作为参数传递,该函数将接收第一个链接的地址,而相反,它需要一个存储第一个链接地址的地方。

于 2015-03-12T16:35:44.613 回答
0

insertBegin 中的双指针用于将 L 的位置从 L 所在的位置更改为要插入的节点。调用函数时,您需要 &L 因为您需要通过引用传递它,因为您正在更改 L

于 2015-03-12T16:27:39.723 回答
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更新存储的值。唯一的区别是在第二种情况下已经有一个指针类型,所以必须是一个指向该指针类型的指针。 varpvarp

在您发布的代码中,该insertBegin函数更新存储在 中的值L,该值是指向列表头部的指针。由于Lmain 中的变量具有类型struct list *,因此 in 中的参数 L的类型insertBegin需要是struct list **

于 2015-03-12T17:38:24.163 回答