struct of linked list, passing paramters - c - c

?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
.
.
}

Related

Insertion into a Linked list using double pointer in C

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.

Passing point as a reference in C?

In C, I want to pass a pointer to another function so I coded the following,
node* list // contains linked list of nodes
void function (node* list){
/*Whatever I do here, I want to make sure that I modify the original list,
not the local copy. +
how do I pass the original pointer 'list' to this function so that I'm working
on the same variable? */
}
[EDIT]
I just like to clarify few things here,
I actually have a void function which takes a struct argument,
void function (struct value arg){ }
and in the struct, I'm defining one of my internal variables as,
node* list-> list;
so in my function, if I do something like,
arg->list
am I accessing the original list variable?
To answer your edit:
No, you are passing the structure by value, so the function contains a copy of the structure. If you don't return the structure in the function and grab it from where you called the function from, it will be lost.
Keep in mind that C does not pass by reference. It is instead simulated by passing the pointer. You could instead do this:
void function (struct value* arg)
{
....
}
And it will modify the original structure.

creating a binary search tree not updating the pointer

I am creating a simple binary search tree.When I am calling the add method using head pointer,changes made in the method are not reflected to this head pointer.It still points null.
struct node *add(struct node *root,int data)
{
if (root==NULL)
{
root=(struct node *) malloc(sizeof(struct node));
root->data=data;
root->left=NULL;
root->right=NULL;
return root;
}
else
{
if (data<=root->data)
{
root->left=add(root->left,data);
}
else
{
root->right=add(root->right,data);
}
return root;
}
}
I am calling the function as
struct node *head=NULL;
add(head,1);
add(head,3);
add(head,15);
In my understanding, on calling the add method, root=head, so head would point to the same memory location where root is pointing and should be updated with the changing value of root accordingly.
UPDATE
head=add(head,1);
When you pass a pointer (node* here), you just copy the value of the memory address it's pointing to, you can change the contents of this address in the function, but the pointer outside of it would still contain the same address.
Initially you have head = NULL, it's not pointing anywhere. When you call the function you create a local variable called root, and copy the value of the pointer (NULL) into that. You then allocate some space and change root to point there, but changes to the local variable would be lost once you leave the function, and head outside will continue holding the value NULL. You actually lost the memory you allocated as no one points there any longer (valgrind could have told you that).
If you passed &head to the function instead (the type would then be node**, note that you'd have to use *root inside the function this way), the changes would be made directly on the outside variable (thanks to the fact c would actually pass the address where main() allocated it on the stack directly to the function).
By the way, in c++, Passing the value by reference would emulate the same thing internally and would be even simpler (you'll be able to keep your code referring to root as is).
Alternatively, you can just return the value of the new head pointer from the function. This would limit you to a single return value though (which is fine in this case)

Delete whole linked list in C - Why not use reference pointer?

I have found this piece of code in a book:
void DeleteList(element *head)
{
element *next, *deleteMe;
deleteMe = head;
while (deleteMe) {
next = deleteMe->next;
free(deleteMe);
deleteMe = next;
}
}
Assuming that the argument that we are passing to the function is the pointer to the head of the list, why are we not passing a reference to that pointer?
If we don't do that, aren't we just going to delete a local copy of that pointer? That is why we pass reference pointers right? So the callee get the changes that have been done inside the function?
If we don't do that, aren't we just going to delete a local copy of that pointer?
Well, there is no such thing as a reference in C, but I assume you mean a pointer-to-pointer, and the answer would be no.
You are freeing the memory that the pointer points to on the heap, not the pointer itself. You are not mutating the pointer, so a copy is fine. Regardless of whether it is a copy or not, they point to the same place.
You are confusing this with assigning a completely new value to a variable passed to a function, in which case you would need to take a pointer-to-pointer. for example:
// only changes the local copy
void init(some_type *foo) {
foo = malloc(sizeof(some_type));
}
// initializes the value at *foo for the caller to see
void init(some_type **foo) {
*foo = malloc(sizeof(some_type));
}
Passing a pointer to a pointer (not a reference to a pointer, because C does not have references at all) would be a better solution, because you'd be able to null it out after the deletion. As it is currently defined, the function may leave dangling pointers behind if its caller is not careful. Other than that little problem, this solution is valid: the caller can always assign NULL to the list head manually after passing it to DeleteList().
Here is how I would rewrite this with a pointer to pointer:
void DeleteList(element **head) {
element *next, *deleteMe;
deleteMe = *head;
while (deleteMe) {
next = deleteMe->next;
free(deleteMe);
deleteMe = next;
}
*head = NULL;
}
The code from #dasblinkenlight can be made more compact.
void DeleteList(element **head) {
element *deleteMe;
while ((deleteMe = *head)) {
*head = deleteMe->next;
free(deleteMe);
}
}
When calling free, the pointer itself is not changed, so there is no need to pass it by reference.
You don't need to change the value of the head of the list in the caller.
// caller
DeleteList(head);
// head points to an invalid place (the place where the list used to be)
// for convenience sake, reset to NULL
head = NULL;

Create a generic stack implemented with a linked-list in C

I want to create a generic stack. I want to implement it with a linked-list.
I created this structures stack_l :
typedef struct stack
{
void * data;
void (*copy)(void *o);
struct stack *next;
} stack_l;
I have some questions:
The second field of the structures is a pointer to a function, to copy a new data (passing by argument in a function Push).
The prototype of the function Push is:
stack_l * Push( stack_l * head, void * d );
Is it correct how I pass the pointer to the function copy?
I have to implement it in the function Push??
Is it necessary create a function NewStack (for example) to inizialize the field of the structures, or is better have only a Push function that create the 1st element if the stack is empty, and add new element on top if there is at least one element?
A void * need to be allocated with a malloc ?
First of all, you do not require different identifiers for stack and stack_l. Now, to your questions:
Your Push function is incompatible with the type of the copy field in stack_l. If you want to include a pointer to (member-)functions in your struct to make it look like C++, you still have to pass your object to these functions.
Yes ,you have to implement your functionality somewhere, and that cannot be within the definition of struct stack. This means that you do need some sort of constructor function (you may call it newStack if you like). Your constructor must at least initialise your function pointers (if you want to keep them). If you opt not to keep these function pointers you can put the initialisation code well in your push routine, as you suggested:
stack_l* stackPush(stack_l* head, void* content) {
// head might be NULL, meaning the stack is "empty" or it might be an actual pointer
// we don't care
stack_l* const front = malloc(sizeof(stack_l));
*front = (stack_l){.data = content, .next = head};
return front;
}
Note that you have to explicitly state what the empty stack is. So you may want to implement a constructor for clarity:
stack_l* stackCreateEmpty() {
retun NULL;
}
And maybe even a destructor:
void stackDestroyEmpty(stack_l* s) {
assert(s == NULL && "Tried to destroy non-empty stack.");
}
To your last question: As you see above, you have to use malloc to get space to hold your stack_l object, other than that, you do not need to allocate extra space for your void* member, as it is part of stack_l.

Resources