George
George

Reputation: 193

C double pointer meaning

I cannot understand the meaning of a C code about linked lists that is using double pointers. Here is the code I am reading

    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;
}

What does **L in the insertElement mean and what is the difference between the **L and the *L in the loop function? Why in the main when struct list *L = NULL is declared I should call the function insertBegin with the argument &L and not a simple L?

I guess *L is a pointer towards the first node of the linked list while **L may point toward any element of the list. However, I am not sure this is correct.

Thank you for your help!

Upvotes: 1

Views: 959

Answers (5)

John Bode
John Bode

Reputation: 123548

If you want a function to write to a parameter and have that new value reflected in the caller, then you must pass a pointer for that parameter:

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
}

If we substitute T with a pointer type Q *, then the code is

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
}

The semantics in both cases are exactly the same; we want foo to update the value stored in var through the pointer p. The only difference is that in the second case var already has a pointer type, so p has to be a pointer to that pointer type.

In the code you posted, the insertBegin function updates the value stored in L, which is a pointer to the head of the list. Since the variable L in main has type struct list *, the type of the parameter L in insertBegin needs to be struct list **.

Upvotes: 0

user2551017
user2551017

Reputation: 163

L stores address of the first link in the list. Thus: *L is contents of the first link in the list, and &L is the address of the variable that stores the address of the first link in the list.

In other words, your only way to allocate memory for and initialize a list by passing the argument into a function is by providing &L as an argument. If you pass L as an argument, the function will receive the address of the first link, whereas instead it needs a place where to store the address of the first link.

Upvotes: 1

dtech
dtech

Reputation: 49309

It means "pointer to a pointer". In C pointers are passed by value, so if you want to be able to modify a pointer passed to a function outside of that function, you have to pass a pointer to it. Passing the pointer will only pass another value for it, which will be modified in the function but will not reflect a change to the value outside of it. Passing as a pointer to pointer essentially allows you to modify the value at the address passed rather than just to modify the local.

Consider those two functions:

void foo(int * p, int * t) {
  p = t;
}

void foo2(int ** p, int * t) {
  *p = t;
}

And the code:

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

Upvotes: 2

Sythe
Sythe

Reputation: 143

The double pointer in insertBegin is for when you are changing the location of L from where ever L is to the node you are inserting. When calling the function you need &L because you need to pass it by reference because you are changing L

Upvotes: 0

DrC
DrC

Reputation: 7698

The type **L is read as pointer to a pointer to L. So if you have a pointer to an L and takes its address, that is what you get. The pattern of **L in a function argument (in C) is usually used to implement an "out parameter" - a parameter the code can update. To insert at the beginning, you need to update the pointer to the head of the list - that is why that function takes a pointer to the head as a parameter. When assigning to *L, the function updates the parameter.

Upvotes: 1

Related Questions