I have this popFront function for a linked list:
Node* popFront(Node* list)
{
Node* returnMe = (Node*)malloc(sizeof(Node));
Node* oldHead = list;
returnMe->mData = list->mData;
if (list->mNext != NULL)
list = list->mNext; // This line is definitely called
else
list = blankNode; // And not this one
free(oldHead);
return returnMe;
}
But whenever I call it like this:
Node* list = buildList(10);
Node* oldHead = popFront(list);
printInfo(list);
'oldHead' is correct but 'list' still has its first Node.
You need to read up on the difference between pass by value and pass by reference. The pointer list is passed to the function popFront() by value, meaning that its value is copied into the local variable in the function. When you change that copy, the original variable outside of popFront() is unchanged. If you want to be able to change the value of list, then you need to pass a pointer to list (i.e., pass it by reference) and modify popFront() accordingly to work with a pointer to pointer to Node.
Here is a simpler example to understand:
void foo(int x)
{
x = 2;
}
int main()
{
int x = 3;
foo(x);
// if you understand why x is still 3 here,
// then you'll understand your problem as well.
return 0;
}
If you want the variable list to change, you need to pass it by pointer. Since the value of list is Node*, you would need to pass to have the signature of popFront be Node* popFront(Node **list).
Related
EDIT: my struct is of the form:
struct node{
int key;
struct node* next;
}
typedef struct node* LIST;
I'm writing a function, called print_list_iteratively, which takes a singly linked list and prints its elements in reverse order iteratively. Let me put my 3 functions below and then explain what's my problem with them?
LIST reverse_list(LIST L) {
LIST current = L, prev = NULL, subsequent = NULL;
while (current != NULL) {
// first we need to get the next element to not lose the link.
subsequent = current->next;
// now reverse the pointer
current->next = prev;
// we need to update our prev to create link between the currrent and next element.
// in short, we need to get the address of current node
prev = current;
// finally update the current
current = subsequent;
}
return (L = prev);
}
The above code reverses the list L, and returns the new head of the list L.
void print_list(LIST L) {
while (L) {
printf("%d ", L->key);
L = L->next;
}
}
print_list prints the elements of the list in the order they've been connected.
I've all needed to write the print_list_iteratively function I mentioned at the beginning.
void print_list_iteratively(LIST l) {
// first reverse the list, then call print_list. that's all.
printf("address of function parameter is %p\n", l);
l = reverse_list(l);
print_list(l);
}
I've no problem with these functions; they work as expected, but the notion of pass by value and pass by reference confused me, when I tried to understand how the function takes list as a parameter and returns it. Let me simply write a main for testing these and we'll see how things get mixed.
int main(void) {
l = insert(l, 5);
l = insert(l, 10);
l = insert(l, 15);
l = insert(l, 45);
print_list(l);
print_list_iteratively(l);
print_list(l);
return 0;
}
when first print_list function is called, it prints 5->10->15->45. Next print_list_iteratively is called on list l, which in its turn calls reverse_list and print_list in the body of the function. The print_list inside print_list_iteratively give reversed list 45->15->10->5. Eventually, print_list inside main prints 5.
I want to know why has second print_list just printed 5? I've send list to print_list_iteratively pass by value, not pass by referce, despite this it's changed my original list insinde main function. Can somebody explain me how the lists in this example are passed to functions and how they're returned from them? I appreciate your answers.
The problem is that you pass the head pointer by value. This lets your program to modify your linked list, but the head pointer remains the same.
You should pass the head pointer to the function by reference or a pointer which points to your pointer. (node*& or node**)
Keep in mind, if you pass it by pointer, you need to dereference it, when it is needed.
Assuming the relevant header files, functions for Singly Linked List in C are declared.
Is the following definition of Delete() correct?
/* The Structure for SLL
typedef struct SLL
{
int data;
struct SLL *next;
}node;
Function Delete() deletes a node*/
void Delete( node **head)
{
node *temp, *prev;
int key;
temp = *head;
if(temp == NULL)
{
printf("\nThe list is empty");
return;
}
clrscr();
printf("\nEnter the element you want to delete:");
scanf("%d", &key);
temp = search( *head , key);//search()returns the node which has key
if(temp != NULL)
{
prev = get_prev(*head, key);
if(prev != NULL)
{
prev->next = temp->next;
free(temp);
}
else
{
*head = temp->next;
free(temp);
}
printf("\nThe node is deleted");
getch();
}
}
1) What happens if I replace(node ** head) with (node *head)?
2) What happens if I replace void Delete (node **head) with node
*Delete(node *head)?
3) Is there an alternate way to delete a node in C?
Thanks in advance
This isn't a tutorial site, but here goes...
You do know that arguments in C are passed by value? Meaning the value is copied.
For example:
void some_function(int a)
{
// ...
}
When calling the function above, like
int x = 5;
some_function(x);
Then the value in x is copied into the argument a in the function. If the code inside the function assigns to a (e.g. a = 12;) then you only modify the local variable a, the copy. It does not modify the original variable.
Now, if we want the function to modify x, then we must emulate pass by reference, which is done using pointers and the address-of operator:
void some_function(int *a)
{
*a = 12; // Modify where a is pointing
}
Now to call that, we don't create a pointer variable and pass that (though it's possible as well), instead we use the address-of operator & to pass a pointer to the variable:
int x = 5;
some_function(&x); // Pass a pointer to the variable x
The pointer &x will be passed by value (since that's the only way to pass arguments in C), but we don't want to modify the pointer, we want to modify the data where it points.
Now back to your specific function: Your function wants to modify a variable which is a pointer, then how do we emulate pass by reference? By passing a pointer to the pointer.
So if you have
node *head;
// Initialize head, make it point somewhere, etc.
Now since the Delete function needs to modify where head points, we pass a pointer tohead`, a pointer to the pointer:
Delete(&head);
The Delete function of course must accept that type, a pointer to a pointer to node, i.e. node **. It then uses the dereference operator * to get where the pointer is pointing:
*head = temp->next;
1) If you replace node** head with node* head you won't modify the original head pointer. You probably have a head somewhere that marks the beginning of the linked list. When you delete a node, there's a chance that you want to delete head. In that case you need to modify head to point to the next node in the linked list.
*head = temp->next;
free(temp);
This part of your code does exactly that. Here, temp == head. We want head to point to head->next, but if we pass in node* head to the function, the pointer will get modified but the changes will disappear because you're passing the pointer by value. You need to pass in &head which will be of type node ** head if you want the changes to be reflected outside of the function.
2) You will then change the function definition to return a void pointer (which is a placeholder pointer that can be converted to any pointer. Take care to not break any aliasing rules with this. But the problem from (1) remains, although, you could return a modified head, and assign it to the returned value. In that case define the function won't fit well with other cases where the head doesn't need to be modified. So you could return a pointer for head if it's modified or return NULL when it doesnt. It's a slightly messier method of doing things imho, though.
3) Yes, but that depends on the way a linked list is implemented. For the datatype shown here, the basic delete operation is as given.
I was wondering why the first method does not work but the second does:
//First method
int create_node(struct node *create_me, int init){
create_me = malloc(sizeof(struct node));
if (create_me == 0){
perror("Out of momory in ''create_node'' ");
return -1;
}
(*create_me).x = init;
(*create_me).next = 0;
return 1;
}
int main( void ){
struct node *root;
create_node(root, 0);
print_all_nodes(root);
}
Ok, here the print_all_nodes function tells me, root has not been initialized. Now second method that works fine:
struct node* create_node(struct node *create_me, int init){ //<-------
create_me = malloc(sizeof(struct node));
if (create_me == 0){
perror("Out of momory in ''create_node'' ");
exit(EXIT_FAILURE);
}
(*create_me).x = init;
(*create_me).next = 0;
return create_me; //<---------
}
int main( void ){
struct node *root;
root = create_node(root, 0); //<---------------
print_all_nodes(root);
}
In my understanding (talking about method 1), when I give the create_node function the pointer to the root node, then it actually changes the x and the next of root.
Like when you do:
void change_i(int* p){
*p = 5;
}
int main( void ){
int i = 2;
printf("%d\n", i);
change_i(&i);
printf("%d", i);
}
It actually changes i.
Get the idea?
Can someone share his/her knowledge with me please !
You need a pointer to pointer, not just a pointer.
If you want to change a variable in another function, you have to send a pointer to that variable. If the variable is an integer variable, send a pointer to that integer variable. If the variable is a pointer variable, send a pointer to that pointer variable.
You are saying in your question that "when I give the create_node function the pointer to the root node, then it actually changes the x and the next of root." Your wording makes me suspect that there is some confusion here. Yes, you are changing the contents of x and next, but not of root. root has no x and next, since root is a pointer that points to a struct that contains an x and a next. Your function does not change the contents of root, since what your function gets is only a copy of that pointer.
Changes to your code:
int create_node(struct node **create_me, int init) {
*create_me = malloc(sizeof(struct node));
if (*create_me == 0){
perror("Out of momory in ''create_node'' ");
return -1;
}
(*create_me)->x = init;
(*create_me)->next = 0;
return 1;
}
int main( void ){
struct node *root;
create_node(&root, 0);
print_all_nodes(root);
}
You need to do something like create_node(&root, 0); and then access it as a ** in the called method. C doesn't have pass by reference concept. You need to give the address to access it in another function.
This is a question of the scope of your variables. In the first example, where you supply a pointer to a node, you could change that node and the changes would persist afterwards. However, your malloc changes this pointer, which is discarded after the scope (your function) ends.
In the second example you return this pointer and therefore copy it before being discarded.
This would correspond to this in your given example no. 3:
void change_i(int* p){
*p = 5; // you can 'change i'
p = 5 // but not p (pointer to i), as it is local -> gets discarded after following '}'
}
when I give the create_node function the pointer to the root node, then it actually changes the x and the next of root.
You don't give the create_node() function (in both versions) a pointer to the root node because you don't have the root node, in the first place.
The declaration:
struct node *root;
creates the variable root, of type struct node * and lets it uninitialized. root is a variable that can store the address in memory of a struct node value (a pointer to a struct node value). But the code doesn't create any struct node value and the value of root is just garbage.
Next, both versions of function create_node() receive the garbage value of root in parameter create_me as a consequence of the call:
create_node(root, 0);
The first thing both implementations of create_node() do is to ignore the value they receive in create_me parameter (be it valid or not), create a value of type struct node and store its address in create_me.
The lines:
(*create_me).x = init;
(*create_me).next = 0;
put some values into the properties of the newly allocated struct node object.
The first version of the function then returns 1 and ignores the value stored in create_me. Being a function parameter (a local variable of the function), its value is discarded and lost forever. The code just created a memory leak: a block of memory that is allocated but inaccessible because there is no pointer to it. Don't do this!
The second version of the function returns the value of create_me (i.e. the address of the newly allocated value of type struct node). The calling code (root = create_node(root, 0);) stores the value returned by the function into the variable root (replacing the garbage value used to initialize this variable).
Great success! The second version of the create_node() function creates a new struct node object, initializes its properties and returns the address of the new object to be stored and/or further processed. Don't forget to call free(root) when the object is not needed any more.
I am solving a program to delete all the elements in a linked list and i encountered the following problem:
When i used a delete function with return type void, and checked if the start pointer is NULL in the main ,it wasn't and gives me absurd result
Code:
void deletes(struct node *start)
{
struct node *current,*next;
current=start;
while(current!=NULL)
{
next=current->link;
free(current);
start=next;
current=next;
}
start=NULL;
return ;
}
But if i change the return type, it works fine:
struct node *deletes(struct node *start)
{
struct node *current,*next;
current=start;
while(current!=NULL)
{
next=current->link;
free(current);
start=next;
current=next;
}
start=NULL;
return start;
}
Why is the start=NULL working in the first code?
My entire code is here
It's because in the first version you pass the list header by value, meaning the pointer to the head is copied, and you change only the copy in the function. Those changes are not visible after the function returns as no changes are made on the original copy.
Either do as you do in the second version, returning the result, or pass the pointer by reference, meaning you pass the address of the pointer (or a pointer to the pointer) using the address-of operator. Of course this means that you have to change the function as well:
void deletes(struct node **start)
{
struct node *current = *start;
/* Deleting the list... */
*start = NULL;
}
Call it like
struct node *list_head = ...;
deletes(&list_head);
Because in C, function arguments are passed by value. If you write start = NULL; inside a function, it will be ineffective outside of that function (it will only set the start pointer to NULL, which is essentially just a copy of the pointer value passed in, and it's local to the function.).
If you want to modify a function argument, you must pass a pointer to it. So,
void delete(struct node **start)
{
// ... delete ...
*start = NULL;
}
then
delete(&list);
would work.
It is because you should have (struct node **start), which can allow you to pass a pointer to the list so you can modify the list.
Currently you are only passing in a copy of the linked list to the function and therefore aren't changing the value of the actual list just a copy. Hence why when you return the copy you see the results
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.