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.
Related
I have a type node whose pointer is being used in another struct as shown below.
typedef struct element {
void* data;
struct element *next;
} node;
typedef struct queue {
node *tail;
node *head;
int num_items;
} queue_t;
I create an empty queue using the following code, but I am not sure if head and tail should be set to NULL since temp is not pointing anywhere yet.
queue_t *temp;
temp = malloc(sizeof(queue_t));
if (temp == NULL){
return NULL;
}
temp->head = NULL;
temp->tail = NULL;
temp->num_items = 0;
As per my understanding, malloc will only make temp point to some address space whose size is equal to the size of the struct queue_t. The address space does not contain a valid queue element yet. So how are temp->head = NULL; and temp->tail = NULL; valid statements?
Can someone please explain why this works?
The address space does not contain a valid queue element yet.
Correct, the allocated memory only contains a queue_t
So how are temp->head = NULL; and temp->tail = NULL; valid statements?
head and tail are not part of struct element. head and tail are part of queue_t. You have allocated a queue_t so it is OK to assign values to head and tail. In this case you assign the NULL value to show that they don't point to anything valid yet.
When you allocate a node (aka struct element) you update head and tail like:
// Add first node
temp->head == malloc(sizeof(node));
temp->tail == temp->head;
if (temp->head == NULL){
return NULL;
}
temp->num_items = 1;
// Initialize the new node
temp->head->next = NULL;
temp->head->data = NULL;
// Note: Adding more node requires more complex code
What is the definition of a "valid queue element"? If it's "sufficient space to hold a queue element and where the locations that hold the head and tail pointers have valid values", then setting them, to NULL makes it valid. If it's not that, what is it?
As per my understanding, malloc will only make temp point to some
address space whose size is equal to the size of the struct queue_t.
Correct.
The address space does not contain a valid queue element yet.
Not sure what you what you meant by "valid", but that statement is also correct.
So how are temp->head = NULL; and temp->tail = NULL; valid statements?
It is precisely those statements that makes your allocated space a valid queue element!
Can someone please explain why this works?
Your question fundamentally is no different from a statement such as int i;. Your implementation sets aside a space to hold an integer. However, it is as yet invalid because you have not given it any (meaningful) value. Once you set i = 0; or i = 42;, the space that you call i is now a valid integer.
Hope that helps.
As per my understanding, malloc will only make temp point to some address space whose size is equal to the size of the struct queue_t.
The malloc function call returns an address to the beginning of the allocated memory of size specified in the argument of malloc function call(in bytes). The allocated memory space will be of size specified in the argument of the malloc. However, the address returned by malloc will be the beginning of that memory space. Therefore, you can access upto the size of the memory space safely using the pointer to that memory space.
The address space does not contain a valid queue element yet.
The C Standard library has allocated a valid memory space for your pointer variable temp to point to. However, the values stored at that memory space could be garbage. Therefore, the pointer to node and num_items data members which have some valid memory space allocated to them within your queue_t may have garbage value. For example, after allocating the memory for queue_t, you can try to print the value of num_items using printf function.
queue_t *temp = malloc(sizeof(queue_t));
if (temp == NULL){
return NULL;
}
printf("The value of num_items: %d\n", temp->num_items);
The above example may print any garbage value. Since, C language doesn't have constructors to initialize newly created variables, you should initialize every variable you create with some stable value.
You can also use calloc function call which also sets allocated memory to zero after allocating the memory space.
So how are temp->head = NULL; and temp->tail = NULL; valid statements?
The memory is allocated by malloc which may contain any garbage value. The data members of queue_t share that memory space. Since, memory space can have garbage data, the data members will be having any random garbage data. That's why it is a good approach to initialize data members of the struct allocated by malloc to some stable values. That's what you have done in your program.
Actually, temp's data members head and tail should point to the addresses of variables of type node. The malloc call has allocated the pointer variables. These pointer variables can point to any variable of type node (or store the address of variable of type node). But you haven't allocated any node variable yet and you don't want to create dangling pointer. Therefore, you should initialize these pointer variables with NULL.
Your program should look like this:
queue_t *temp;
temp = malloc(sizeof(queue_t));
if (temp == NULL){
return NULL;
}
temp->head = NULL;
temp->tail = NULL;
temp->num_items = 0;
//Allocate some node
node *n = malloc(sizeof(node));
int data = 1;
n->data=&data;
n->next=NULL;
temp->head=n;
temp->tail=n;
temp->num_items=1;
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.
This is what I have right now for my code (just a simple BST)
typedef struct bsn{
int val;
struct bsn *left, *right;
} bsn_t;
typedef struct bst{
bsn_t *root;
int size;
} bst_t;
My question is that for the functions which I'll use, the input is an address like this
void init( bst_t * tree )
How would I use this? This is what I have right now but I'm not sure if it's correct or not
tree->size = 0;
tree->root = NULL;
Also for other functions like
bool insert( bst_t *tree, int val )
I want to declare a temp node to use. Does this work?
bsn_t temp = (bsn_t *) malloc (sizeof (bsn_t));
And my last question is that how would I check if a node is null or not. I tried
bsn_t visitor = (bsn_t*)malloc(sizeof(bsn_t));
visitor = *tree->root;
Then doing
if (visitor != NULL)
But when I compile it says that
'!=': illegal for struct
Please help..
In your tree, the connections between the nodes and the connection from outside, i.e the root, are all pointers. They point to nodes that are allocated on the heap with malloc.
If you define a local variable like:
bsn_t temp;
you get a node on the stack that will be invalid after the returning from the function. In your case, you should never need to create nodes on the stack. You should work with pointers to nodes throughout, which point to existing nodes, to frshly allocated nodes or to nothing (NULL).
So:
bsn_t *temp = malloc (sizeof (bsn_t));
(I've removed the cast to (bsn_t *). It is strange that in the original code, you have cast the return value from malloc to a pointer type when assigning to a struct.)
As for your second question, your code:
bsn_t visitor = (bsn_t*)malloc(sizeof(bsn_t));
visitor = *tree->root;
is wrong in several places. First, as above, the visitor should be a pointer to a node, not a node struct.
Then the visitor is supposed to travel from the root down the tree. By doing so, it does not create any new nodes, so there is no need to malloc at all. Remember, malloc gives you new memory on the heap, in effect creating a node. The visitor just points to existing objects. One object can have more pointers pointing to them.
Even if malloc were the right ting to do, you shouldn't malloc and then overwrite the pointer that holds the (so far only) handle to the ne memory.
You've also got the * wrong. The visitor is a pointer ans tree->root is a pointer, too, so there's no need to dereference. What you have done is to copy the contents of the root to your local struct.
What you want to do is someting like this:
bsn_t *visitor = tree->root;
while (visitor != NULL) {
// Do stuff
visitor = visitor->right; // or left, whatever
}
The use of asterisks in declaration and use may be confusing. In a declaration, you use a start to make a thing a pointer:
bsn_t node; // uninitialised node struct on the stack
bsn_t *pnode; // uninitialised pointer to node
After that, when you use the pointer variable, the unadorned name refers to the the pointer. An asterisk means that you dereference it to get at what the pointer points to. When you work with structures, you usually won't see many stars, because the -> syntax is preferred, but node->left is essentially the same as (*node).left.
You can't assign memory addresses (The return value from a malloc call) to struct typed variables. You need to assign these to pointer typed variables.
bsn_t *temp = (bsn_t *) malloc (sizeof (bsn_t));
bsn_t *visitor = (bsn_t*)malloc(sizeof(bsn_t));
Then you won't have compile time errors.
How would I use this? This is what I have right now but I'm not sure if it's correct or not
tree->size = 0;
tree->root = NULL;
Yes this is the right way to use it. If you have a pointer you can access the struct elements with(->) operator otherwise, use . (dot) operator.
bsn_t temp = (bsn_t *) malloc (sizeof (bsn_t));
Yes this is the right way as well but you are missing a '*' before temp on left hand side which states that this is a pointer type variable. Remember, it will allocate the object in heap so you have to explicitly free that memory when you no longer need it. Also, note that casting the newly allocated memory to (bsn_t *) is optional, if you don't do, compiler will implicitly do it for you depending upon your l-value type.
bsn_t visitor = (bsn_t*)malloc(sizeof(bsn_t));
Again, it should be bsn_t *visitor on your left hand side.
visitor = *tree->root;
Following that it should be *visitor = *tree->root;
Also, try to make your code more readable by writing *(temp->root) instead of *temp->root.
if (visitor != NULL) Now you should be able to use this since visitor is a pointer now.
I can't get that why are we using a * in a function declaration like:
struct node *create_ll(struct node *)
{
body here
}
Why do we use that * before create_ll which is the function name?
And it is called using the statement:
start = create_ll(start);
If this could help.
Please explain this.
struct node *create_ll(struct node *)
means the return type of this function will be a pointer of type struct node. read it like
struct node * ,
not like
*create_ll.
This has nothing to do with the NAME of the function.
As stated by Sourav (thought I'd elaborate further, and I can't comment due to low rep), using the * operator returns a pointer to the given type, this pointer is actually just a number that stores the starting memory address of the given object (the actual type of number depends on OS and processor... 32bit numbers on a 32bit OS/processor, 64bit numbers on a 64bit OS/processor) and not the actual object itself.
For instance: even if you have a 64bit processor, if you're running Windows XP (32bit) then the resulting number will be a 32bit number (4 bytes of memory to store), if you switched over to a 64bit OS then the resulting number would be a 64bit number (8 bytes of memory to store).
In order to get a pointer in the first place, the & operator is needed... unless dynamically allocated using malloc() or something similar.
When actually using the pointer, then the -> operator is used (instead of using the . operator).
To give an example in code:
struct test_object
{
unsigned int value;
};
void function()
{
// Declare a POINTER to an object of type <test_object>
test_object *pointer;
// Declare 2 temporary objects
test_object object1, object2;
// Set object1's value using the . operator
object1.value = 1;
// Set object2's value using the . operator
object2.value = 2;
// Set the pointer to point at object2
// Note the usage of the & operator
pointer = &object2;
// Print out whatever the pointer points to (in this case object2)
// Note the usage of -> instead of .
// This is how pointers access the object being pointed at
cout << pointer->value;
// Now set the pointer to point at object1
pointer = &object1;
// Print out whatever the pointer points to (in this case object1)
// Note this is the EXACT same line used above
// but the end result is completely different
cout << pointer->value;
};
A word of warning, pointers can be quite dangerous if used incorrectly. In the above example, I didn't initialize the pointer when I declared it...
IE:
test_object *pointer = NULL;
If you tried to use the COUT line in the above code without setting the pointer first, then really bad stuff can happen (program crashes, accessing the wrong memory location giving unexpected results, etc).
The best way to avoid such things is to ALWAYS initialize pointers to NULL, and ALWAYS check if the pointer is NULL before actually trying to access the memory being pointed to...
Re-using the above code, but making it safer:
void function()
{
// Declare the pointer
test_object *pointer = NULL;
// Declare the 2 actual objects
test_object object1, object2;
// Set values
object1.value = 1;
object2.value = 2;
// Check if pointer isn't pointing at anything
if (pointer == NULL)
{
// At this moment in time, it doesn't point at anything (it's still NULL)
// So this code WON'T run, which stops the program crashing
// Print out whatever the pointer points to
cout << pointer->value;
}
// Set the pointer to point at object2
pointer = &object2;
// Check if pointer isn't pointing at anything
if (pointer == NULL)
{
// Now it DOES point to something (anything other than NULL)
// Print out whatever the pointer points to
cout << pointer->value;
}
};
If you comment out the 2 if statements, then the program will probably crash when the first COUT is reached (it SHOULD crash, but not always).
I hope this answers your question
Here * means you are using pointers.Reason is that since Node could contain lot of variables and it would consume lot of memory So to avoid this we use pointers like
struct Node*
Since in this case when calling function and passing argument or returning argument of type Node you save lot of memory since in pointers only the address of the Node is passed or returned.Otherwise huge copy(If Node have lot of variables) of the Node will be made in memory before passing to or returning from the functions.
It is just like if I take you to an apple store and go with you to buy them and in the pointer case I tell you only the address of the shop and you buy yourself.
Now coming to second part of your question struct Node*
here function will return pointer of type struct Node so to use this you will write following code.
struct Node* someInput;
sturct Node* someOutput=create_ll(someInput);
and to use members inside someOutput for example if there are members like name and age inside Node you will do following
someOutput->age;
someOutput->name;
Your function is returning a pointer.
In this case it is returning a pointer of type struct node.
so the function prototype looks like
struct node *func(struct node *);
I created a linked list with ten nodes. I want to get the address of the first node I created in the linked list. I am getting incorrect address value for the first node. This is the code which I wrote :
#include "singlyLinkedList.h"
#include <stddef.h> //for NULL
#include <stdlib.h> //for malloc
#include <stdio.h> //for printf
node *pNode;
void CreateLinkedList()
{
int i;
pNode = (node*)malloc(sizeof(node)); //create space for first node []
for(i=0;i<10;i++)
{
pNode->element = i; //enter value [0]
printf("Value is %d addr is %p\n",pNode->element,pNode);
pNode->nextPtr = (node*)malloc(sizeof(node)); //[0]->[]->NULL
pNode = pNode->nextPtr;
}
pNode->nextPtr=NULL;
}
//Function to get first node address
void GetFirstNodeAddress()
{
pNode = pNode-10*(sizeof(node));
printf("\n *** Value is %p",pNode);
}
int main()
{
CreateLinkedList();
GetFirstNodeAddress();
}
You assume that the 10 malloc's you do will result in 10 consecutive addresses. You handle it as if it is an array, yet the elemenents of the linked list are independent.
The way these linked lists usually work is that you initialise them and keep the first pointer to be returned later. Then grow more elements on the tail. You can not walk backwards in a single linked list.
I gave a code example in an earlier post today
You don't use pointer arithmetic in linked list implementations, at least not trivial ones. And you're populating your list incorrectly. You need to retain the head pointer. This is one such way to do it:
// Note: do NOT invoke on a non-empty pNode list
void CreateLinkedList()
{
node **pp = &pNode;
int i;
for (i=0;i<10;++i)
{
*pp = malloc(sizeof(**pp));
(*pp)->element = i;
pp = &(*pp)->nextPtr;
}
*pp = NULL;
}
How It Works
Just like pNode is a pointer to a node, pp is a pointer to a node *. During the lifetime of the loop pp always holds the address of the next pointer about to be filled with a new node allocation. After the allocation and node setup, pp is filled with the address of the nextPtr pointer of the node just-created. This continues until the end of the fill. At that point the pointer addressed by pp is the tail nextPtr and should be null-terminated (which is what *pp = NULL does). Step through this code in a debugger to see better how it works.
Personally I would pass the address of the head pointer as a parameter, but this is one immediate way to get your code running.
Try printf("\n *** Value is %p",(void *) &pNode);. & is typically the easiest way to get pointer addresses
also from what I know: pNode = pNode-10*(sizeof(node)); is incorrect.
when you are doing pointers, they point to areas in memory that are not necessarily contiguous (following in order in memory). Meaning you could have one pointer pointing to memory blocks 5-10, which also has a pointer to memory blocks 83-88. If you want to get the first node, create a pNode rootNode and assign your first created pNode to that. Then you can traverse it in a while loop as well as printing out the address as listed above or whatever else you please.