void insert(list **l, int x)
{
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l=p;
}
Why did we use double pointer? Could we have done the same thing using single pointer? I saw this example in the book "The Algorithm Design Manual" page 69 2nd Edition.
List is basically node, just for refernce.
Could we have done the same thing using single pointer?
You could have done that using a single pointer with a minor update.
Return the pointer that was allocated and make sure that the function call is changed appropriately.
list* insert(list *l, int x)
{
// list = *p
// What was that? That is not valid code.
list* p = malloc(sizeof(list));
p->item = x;
p->next = l;
return p;
}
and use it as
list* l = NULL;
l = insert(l, 10);
Parameters in C are passed by value. So in order to make some changes to a variable in a function, we have to tell that function the address of the variable. This enables it to change the value of the variable indirectly by writing data to the corresponding memory.
As a result, to modify an int, you have to pass an int *. In your case, to modify a list *(the type of p->next), you have to pass a list **.
using double pointer is justified here because in the function you insert node in the header of list, so the variable l will be changed with the new header *l=p;
*l->|node1|->|node2| //initial value
p->|nodeP| //after p = malloc(sizeof(list)); p->item = x;
p->|nodeP|->|node1|->|node2| //p->next = *l;
*l->|nodeP|->|node1|->|node2| //after *l=p
in this case function is called like this:
list *head;
insert(&head, 4);
For your question:
Could we have done the same thing using single pointer?
Yes, the function will look like this:
list *insert(list *l, int x)
{
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = l;
return p;
}
you can call function in this case like this:
list *head;
head = insert(head, 4);
Basically u might be calling the insert function using insert(&head,x);
Previously head would have stored the address of your first node in the
linked list and u give the address of the head node to l and to access the
address of a u need to dereference it once and to change its value u need to
dereference it twice.
and obviously u can do it without double pointers just giving the value of
head to l insert(head,x)....and in the function declaring insert(int *l,int
x)
suppose
address of a(first node)=123
value of head=123
address of head =456
l(storing address of head)=456
In order to get the address of the first node dereference once
*l=123
in order to change value or to go to the next node you dereference it twice
for visual satisfaction have a look at the diagram image i tried to figure
out for your better understanding.
----------
[Here's an diagram which will give you a clear idea abt how the double pointer
is working here][1]
[1]: http://i.stack.imgur.com/HQOaa.jpg
You need to use double pointer in this example because you would like to also change the starting node of your list. So basically when you're inserting a new element, you also want to make the node that contains it the first one of your list. If you pass only a single pointer(list *l) and you assign to it the newly created node (p), the changes (and by changes I mean the fact that it will be the first node of the list) would only be available inside your function, and would not be propagated outside it.
To make it more clear, if you're taking in a simple pointer (list *l) you're basically copying the address stored by the list* variable that's sitting outside your function, in the newly created pointer (the l parameter). So the l variable inside your function is a different pointer (a different location in memory compared to the pointer variable outside your function) containing the same address as the pointer outside the function. So that's why assigning the newly created element to this l single-pointer would only make the the newly inserted element the first only local (function scope).
Compared to the alternative method when you're taking in a double pointer (so list **l), what really happens is that by passing the outer pointer variable to the function, you're actually passing the address of the outside pointer, not to be confused with the address that the pointer is containing. (take care since you will have to call the function something like this: insert(&l, 2)). This way you will still have the address contained by the outer pointer by dereferencing it and using it as rvalue (p->next = *l) and at the same time you have the address of the outside variable, so when you're making *l = p (notice *l is used as lvalue here), you're actually dereferencing the double pointer and in consequence you will obtain the the address of the real variable (the outside one), assigning to it the newly created node. In other words you're actually setting the newly created node as the starting node but this time also outside the function.
Really hope this is not extremely confusing.
Related
I've been searching around for a good while now on google and a few text books and I can't seem to understand why it is, when building a linked list, that the nodes need to be pointers.
Eg. If i have a node defined as:
typedef struct Node{
int value;
struct Node *next;
} Node;
why is it that in order to create a linked list, I would say:
Node *a = malloc(sizeof(Node));
Node *b = malloc(sizeof(Node));
a->value = 1;
b->value = 2;
a->next = b;
b->next = NULL;
rather than:
Node a, b;
a.value = 1;
b.value = 2;
a.next = &b;
b.next = NULL;
To my understanding, the list will still be able to be referenced and traversed as normal, the only difference is the use of the dot, ampersand syntax rather than the arrow?
You can create the list in a way that you mentioned.
But you must care for the life time of the list members. If your
Node a, b;
are in scope of a function then these are lost after the return of that function.
When you use pointers then you usually use the heap and the instances live until they are deleted.
Your first example will not work. You are declaring two Node pointers. However, since you do not initialize these to anything, it is illegal to deference them, since they don't point to anything. You must first use something like malloc to declare memory for them to point to, or assign them to a previously declared local variable. However, you must also remember to call free when you are done with the memory.
In the second example, you are declaring two Node variables, which you use to store instances of the Node. These will be allocated on the stack if they are local variables, and they will live for as long as they are in scope. They hold valid memory, and thus you can use them in the way you have demonstrated.
I was reading Skeina's book. I could not understand this code. Basically what is the use of double pointer. And what is the use of *l = p? Can anyone please explain by diagram.
void insert_list(list **l, item_type x) {
list *p; /* temporary pointer */
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
You shouldn't call it a "double pointer" because that would be a pointer to a double. It is a pointer to a pointer, and it is used to allow the function to alter the value of an argument which happens to be a pointer. If you're familiar with C#, it's like an out argument. In this situation the l argument used to get both IN and OUT behavior, but you may often see this used for output only.
Since this function returns type void it very well could have been written without the use of the pointer to a pointer like this:
list * insert_list(list *l, item_type x) {
{
list *p; /* temporary pointer */
p = malloc(sizeof(list));
p->item = x;
p->next = l; // note that this is not *l here
return p;
}
This change would require the code that calls the function to update it's own handle to the list since the head of the list is what's being changed.
This function performs a very simple task: it inserts a list node at
the position for which it receives a pointer. There is nothing
special about double pointers, they are just pointers to pointers. They hold the address of a pointer, which contains the address of an object.
void **l contains the address of a list * pointer. *l retrieves
this address and *l = p stores it.
malloc is used to allocate a
list structure, p receives the address of the allocated structure.
The code is somewhat sloppy as p is not checked for NULL before
dereferencing it. If malloc fails because of lack of memory, the
program will invoke undefined behaviour, hopefully stopping with a
segmentation fault or something potentially worse.
The node is initialized, its next pointer is set to the node pointed
to by the l argument, and finally the new node's address is stored
at the address passed as the l argument. The effect is simple: the node is inserted at *l.
This method is clever ad it allows the same function to insert a new node anywhere is a list. For example:
list *head = NULL;
...
/* Insert a LIST_A node at the beginning of the list */
insert_list(&head, LIST_A);
...
/* insert a LIST_B element as the second node in the list */
insert_list(&head->next, LIST_B);
...
/* find the end of the list */
list *node;
for (node = head; node->next; node = node->next)
continue;
/* insert a LIST_Z node at the end of the list */
insert_list(&node->next, LIST_Z);
The only tricky thing above is the concept of pointer itself, here is a simple overview:
Memory can be conceptualized as a (large) array of bytes, addresses are offsets in this array.
char variables by definition are single bytes,
int variables occupies a number of bytes specific to the architecture of the system, typically 4 or 8 bytes in current hardware.
Think of pointers as variables holding the address in memory of another variable. They need to be large enough to hold any valid address in the system, in current systems with more than 4 GB of physical and addressable memory, they are 64 bit long and occupy 8 bytes.
There is a special address value NULL which represents no object and is used to specify that a given pointer does not point to any real object. The address 0 is used for this purpose. malloc will return NULL if it cannot allocate the memory requested, the return value should be tested, as storing a value at this address is forbidden and usually caught as an invalid access (segmentation fault).
This summary is purposely simplistic. I used the term variable instead of object to avoid the confusion with OOP concepts.
?Hello,
I have implemented a struct of link, and with this made a list.
typedef struct link1 {
char* a;
char* b;
int i;
struct link1* next;
};
and I have functions for append, delete etc, from the list. Those functions get the first link in the list. The problem is the after using the functions the information didn't update.
Is there a way to pass the parameter of the first link, such that the list will be updated?
The first link is from type:
link1* first;
**I have tried to return the first link and it works, but I have nested function and I can't return those links in the external functions, so I think that the only way is to pass the paramter in other way.
Right now I send the parameter like this:
link1* first;
func(first);
void func(link1* l){...}
Thank you!
Link list manipulations, such as append, delete, etc., must often affect the "head" node in the list. For example, when the "head" node is deleted, then "head->next" must now assume the role as the new list head node. In such a case, your pointer
link1* first;
(which points to the head node of the list) must be modified to point to the "head->next" node. Unfortunately, passing first to a function in this manor
func(first);
does not allow func() to manipulate where 'first' is pointing. In order for func() to manipulate where 'first' is pointing, you must pass the "address" of first to func():
func(&first);
Now, if func() performs an operation such as 'delete node' or 'add node', it would have the address of 'first', and thereby it can change where 'first' is pointing:
func(struct link1 **first);
{
...
*first = head->next;
...
}
Whenever you'd like to change ANYTHING in a function using OUT BYREF parameter, u ought to send a pointer to the value that you are setting. I.E: If you were to set an int then u'd pass int *; If the value that you are assigning is of type struct link1* than you ought to pass a pointer to this type (pointer to pointer for the struct) where you can allocate the memory and set the pointer of the calling function.
void init(struct link1 **top)
{
//assign the pointer of the calling function
*top = ...;
}
calling function code
struct link1 *top;
init(&top);
Your problem is that you pass as an attribute in your function, the data of the first node and not the address of the data of your first node. How does this affects us in this case? Any changes you make on the first node, are just changes in a local variable of your function that lives in the stack of your program and when your function returns, this variable will be gone and so the changes you have made.
Check this out, you may understand it better. Imagine that this is a snapshot of your ram and the grey cells are memory indexes and the white cells are the corresponding data:
When you have a variable like b (lets call it a "single pointer" variable) and you pass b as an attribute to a function, you actually pass the data of b (0x1) and not the address of b (0x3). With this in mind, you can notice that you are able to change the contents of 0x1 (for example add 10 and make it '30') but you cannot change the contents of 0x3, which is what you want.
If you want to be able to change the root of your list from a function without returning something, you have to pass the address of the address, or the "double pointer" variable, like c. Passing it like this you are able to:
a) change the data of 0x3: *first = ....
b) change the data of 0x1: **first = ....
If you want to check if understood it, think want is going to happen if you change the data of first. For example:
int **temp = ....;
first = temp;
Now that we mention the theoretical part, in order to follow what i am proposing, you have to change your code into something like this:
func(&first); //pass the address of first variable
.
.
func(<variableType> **first) { // receive with double star
.
.
*first = ...; // change the root using single star
.
.
}
I am having trouble understanding this code. All I really need is to modify the head pointer to point to the first element. So why won't *head work ? Changing the value of *head changes where this pointer points to and that should work, right ? I have read the pass by reference/pass by value, but am finding it hard to understand. Can someone help clarify this ?
Appreciate your help. Thanks.
In C/C++ it’s easier to make mistakes with pointer misuse. Consider this C/C++ code for inserting an element at the front of a list:
bool insertInFront( IntElement *head, int data ){
IntElement *newElem = new IntElement;
if( !newElem ) return false;
newElem->data = data;
head = newElem; // Incorrect!
return true;
}
The preceding code is incorrect because it only updates the local copy of the head pointer. The correct version passes in a pointer to the head pointer:
bool insertInFront( IntElement **head, int data ){
IntElement *newElem = new IntElement;
if( !newElem ) return false;
newElen->data = data;
*head = newElem; // Correctly updates head
return true;
}
You need help understanding the difference right?
Imagine the caller of the function in the first case:
IntElement *head;
int data;
...
insertInFront (head, data);
Now, in this case, the address pointed to by head is placed on the stack and passed in as an argument to insertInFront. When insertInFront does head = newElement; only the argument (on the stack) is modified.
In the second case, the caller would be:
IntElement *head;
int data;
...
insertInFront (&head, data);
In this case, the address of head is placed on the stack and passed in as an argument to insertInFront. When you do *head = newElement, this passed in address is de-referenced to get the address of the original list head, and that is modified.
Its fairly simple when you get your head around what a pointer is. In the first code IntElement *head, head is a pointer to the existing head of the linked list. So the caller is passing in the address of the head element of the list. Changing the value of head in the insert-in-front function doesn't change ANYTHING back at the caller. The value of that address was passed to your function - not what was holding that address back at the caller.
You need to pass your function 'the address of the address of the head' - or IntElement **head. This will allow this function to modify the address held by the caller - i.e. update the linked list to point to the new head.
You don't want to change the value head points to, you want to change the pointer that is stored in head itself, so don't use *head, use a pointer to head itself. Head is of type IntElement *, so the parameter should be a pointer to such a type: IntElement **
Whenever you have a value T x somewhere and you want some other function to modify it, you pass a pointer to x:
T x; // set to some value
modify_me(&x); // will change x
/* ... */
void modify_me(T * x)
{
*x = new_value;
}
Now just apply this mechanic to T = IntElement*. The values that you want to modify are themselves pointers!
(Maybe using a typedef would make things look less confusing: typedef IntElement * NodePtr;.)
Also note that your linked list is broken because you never set the "next" pointer of the new element to point to the old head, and similarly for the "previous" pointer if the list is doubly-linked.
In the code of table.h for mysql. There are the following code
typedef struct st_table_share
{
...
struct st_table_share * next, /* Link to unused shares */
**prev;
in the text book, we usally have
sometype *next, *prev;
but here it use **prev instead of *prev. What the reason to use double pointer for prev?
It's not pointing to the previous structure, as next is, it's pointing to the pointer that's pointing to this structure.
The benefit of doing this is that it can point to either the 'next' member of the preceding structure, or it can point to the actual head pointer itself - in the case where this is the first item in the list. This means that removing the item involves "*prev = next" in both cases - there's no special case for updating the head pointer.
The downside is that you can't (easily) use it to traverse the structure backwards; so it's really designed to optimize the case where you only care about traversing forwards, but want to easily remove an arbitrary node.
it is not a "double pointer" as you mention. rather it is referred to as "de-referencing".
int x = 10;
int* prev = &x;
*prev is the address of variable x.
now lets say you need to pass the address of the pointer variable prev to another function named foo which accepts an address of a pointer as its parameter (pointer to a pointer).
void function foo(int** ptr)
{
prinft("%p", ptr); //this would print the address of prev
printf("%p", *ptr); //this would print the value (the address of x) contained inside address contained inside ptr.
printf("%d", **ptr); //this would print the value (the value of x, 10) contained at the address(address of x) contained inside address (address of prev) contained inside ptr
}