Understanding function called by reference on lists - c

I'd like to know why the code given below works well.
It should,recursively, given a list, put a -1 in front of the even numbers.
Ex. Input : 4->7->1->10->NULL Output : -1->10->1->7->-1->4->NULL
I don't understand how the function,being recursive, could keep track of the eventual *head,which is changed every time , due to the fact that the function called itself by reference.
In the end what I'm not getting is how the output could be correct given those (to me) misconception of how a recursive function by reference works.
Here's the code with the following declarations :
typedef struct El {
int info;
struct El *next;}ElementoLista;
typedef ElementoLista *ListaDiElementi;
void inserisci(ListaDiElementi *head) {
if((*head) != NULL && ((*head)->info)%2 == 0) {
inserisci(&(*head)->next);
ListaDiElementi aux = malloc(sizeof(ElementoLista));
aux->info = -1;
aux->next = *head;
*head = aux;
} else {
if((*head) != NULL) {
inserisci(&(*head)->next);
}
}
}

I think your troubles with the code is due to the code being "a bit poorly" written, i.e. less clear than it could be. I see three issues.
1) "typedef of pointer" makes it hard to understand what types are involved. Especially when it's not clear that a specific type is a pointer. A name like ListaDiElementi is not (at least not to me) making it clear that this is a pointer. A better name could be ElementoLista_ptr but overall it's better to avoid pointer typedef.
2) The function argument is named head. This is confusing because we normally think of head as the pointer to the first element of a list. But that's not what is going on here. The argument is really a double pointer and further it does not point to the first element. It points to next pointers.
3) The if constructs hides logic of the program.
So let's rewrite the code to get rid of the above while still keeping the same functionality:
typedef struct El {
int info;
struct El *next;
} ElementoLista;
void inserisci(ElementoLista **pNext) {
if ((*pNext) == NULL) return;
inserisci(&(*pNext)->next);
if(((*pNext)->info)%2 == 0) {
ElementoLista* aux = malloc(sizeof(ElementoLista));
aux->info = -1;
aux->next = *pNext;
*pNext = aux;
}
}
With this code it's easier to see that the code keeps calling it self recursively until it reaches the end. On the way back, i.e. as the function calls return, the code checks whether it needs to insert a "-1" node.
The same code with some comments to explain:
typedef struct El {
int info;
struct El *next;} ElementoLista;
// pNext is a pointer to the "next pointer" of the previous node
// Consequently (*pNext) is a pointer to the current node
void inserisci(ElementoLista **pNext) {
// Return if we have reached the end of the list
if ((*pNext) == NULL) return;
// Keep calling until the end is reached
inserisci(&(*pNext)->next);
// On the "way back" (i.e. as the recursive calls return) check
// if we need to insert a "-1" node
if(((*pNext)->info)%2 == 0) {
// We need a new node
ElementoLista* aux = malloc(sizeof(ElementoLista));
aux->info = -1;
// Make the new node point to current node
aux->next = *pNext;
// Update the next pointer to point to the new node
*pNext = aux;
}
}
When you understand this simplified version of the code, you should also understand the original version.

Related

Understanding type functions with linked-list

Good Morning/Evening everyone,
I'd like to clarify in my head the following concept about linked list functions (In this case recursive).
Let's take the following program that eliminates the duplicates in a linked list recursively :
ElementoDiLista* deleteDuplicates(ElementoDiLista* head)
{
if (head == NULL)
{
return NULL;
}
if (head->next == NULL)
{
return head;
}
if (head->info == head->next->info)
{
ElementoDiLista *tmp;
tmp = head->next;
head->next = head->next->next;
free(tmp);
return deleteDuplicates(head);
}
else
{
head->next = deleteDuplicates(head->next);
return head;
}
}
With the definition of my struct and list this way :
struct el {int info; struct el *next;};
typedef struct el ElementoDiLista;
typedef ElementoDiLista *ListaDiElementi;
And then in the main i call the function this way :
Lista1 = deleteDuplicates(Lista1);
Where Lista1 is declared as follows : ElementoDiLista Lista1 = NULL
My question was, i was used to declare functions that are void or depends on single types (int,float ecc...)
I'd like to clarify two things :
Why the function is declared as ElementoDiLista* deleteDuplicates(ElementoDiLista* head) because to me it is more intuitive this way ListaDiElementi deleteDuplicates (ListaDiElementi *head) but unfortunately,doesn't work.
It is not very clear to me why the function returns head or NULL values, but this is the reason i think why in the main Lista1 takes the value of the function, because the function modifies the list itself, am i right ?
I'm sorry if the questions are not very exciting i'm just trying very hard to understand list in general and are quite difficult,
Any help or advise would be appreciated,
Thank you all anyway!
Why the function is declared as ElementoDiLista* deleteDuplicates(ElementoDiLista* head) because to me it is more intuitive this way ListaDiElementi deleteDuplicates (ListaDiElementi *head)
Starting with the argument, originally it is declared as,
ElementoDiLista* head
so it takes a pointer to the head element. This would have been equivalent (with a variable name change) to,
ListaDiElementi list
So we're passing as argument a "list", which is a pointer to the head. That pointer is not modified. To modify it indeed we'd need to use as you suggest,
ElementoDiLista** head
or equivalently and perhaps more readable,
ListaDiElementi* list
The question is therefore, "do we need to modify the pointer to the head"? Or in other words, does the original list pointer need to be modified? The answer is no.
If the list is null it will remain null. If the list is not null the head will remain the same. You won't remove the head, only the nodes that follow which hold the same value the head does.
It is not very clear to me why the function returns head or NULL values, but this is the reason i think why in the main Lista1 takes the value of the function, because the function modifies the list itself, am i right ?
Personally I don't like that the function returns a pointer to an element (i.e. a list). Also it appears to always return head, and to be implemented in a rather obfuscated manner.
Firstly regarding me not liking it. If you are changing the structure of an existing list, rather than creating a new one, you want your initial pointer to remain valid after the procedure. So you change that pointer (if you need to) rather than returning a new one. In this case it doesn't even change. So I would either have it void or return some exit code.
Secondly look at the code,
if (head == NULL)
{
return NULL;
It returned head since it is null.
if (head->next == NULL)
{
return head;
It returned head again.
if (head->info == head->next->info)
{
ElementoDiLista *tmp;
tmp = head->next;
head->next = head->next->next;
free(tmp);
return deleteDuplicates(head);
}
It returns deleteDuplicates(head) and head is the original argument which hasn't changed. So if all other cases return head, so will this.
else
{
head->next = deleteDuplicates(head->next);
return head;
}
This too returns head (note head hasn't changed). So its return value is always the original argument head. So this is pointless.
Furthermore note that in the first two cases you do nothing, you just return a value that is useless.
if (head == NULL)
{
return NULL;
}
if (head->next == NULL)
{
return head;
}
So if you do change your procedure to void this code disappears. You don't have to do anything if your list or its tail is null, since there are no duplicates.

Storing data inside structs (Linked List)

Hi guys I'm learning C and there are some issues that I can't solve.
first of all, this are my data structure:
struct user_node {
void *name;
struct user_node *next;
struct msg_node *msgnext;
};
struct msg_node {
void *sender;
void *receiver;
void *title;
void *content;
struct msg_node *msgnext;
};
struct user_node *user_database = NULL;
The idea is that a user may have one or more messages.
Well I can create and delete users but I'm having problem storing messages, for example here:
The purpose of this function is to put temp as a message inside my data structure for a given user that we find in the message itself. (temp is already msg_node with data which I take from another function)
void sendMsg(struct msg_node* temp) {
//if list is empty
if (user_database == NULL) {
printf("There aren't users on the system.\n\n");
return;
}
struct user_node** ptr = &user_database;
while (*ptr) {
if (strncmp((*ptr)->name, (temp)->receiver, strlen(temp-
>receiver)) == 0) {
temp->msgnext = &user_database->msgnext;
user_database->msgnext = temp;
return;
}
ptr = &(*ptr)->next;
}
printf("User not found on the system\n\n");
return;
}
I know that the code is wrong but I been messing arround with this since yesterday and I can't figure it , may someone help me?
Thanks in advance
You can insert a node at the front of a linked list by sett ing the new node's next pointer to the list's head and then setting the lis's head to the new node. This works even for an empty list, when the list's head is NULL.
You've got this almost right, but the List's head is the one associated with the current user, not with the user list's head, i.e. the first user in the database.
The following code should do what you want:
int sendMsg(struct msg_node *msg)
{
struct user_node *user = user_database;
if (user == NULL) {
printf("There aren't users on the system.\n");
return -1;
}
while (user) {
if (strcmp(ptr->name, msg->receiver) == 0) {
msg->msgnext = user->msgnext;
user->msgnext = msg;
return 0;
}
user = user->next;
}
printf("User '%s' not found on the system.\n", msg->receiver);
return -1;
}
Notes:
I've renamed the pointers from the rather nondescript temp and ptr to the more descriptive msg and user.
I've made the function return a success code: 0 for success and −1 for failure.
strncmp will compare only a certain number of characters. I've changed this to strcmp, so that the users Paul and Pauline are considered different.
There's no need to make the traversing pointer a pointer to pointer to node. That technique is useful, but only when you want to insert or delete nodes. Inserting at the front is a special case where you won't need it. (And you insert a message, not a user, so if you wanted to insert the message somewhere else than at the front, you could iterate through the sub-list with a pointer to pointer to message node.)

Creating and displaying linear linked list in C(Recursively)

I'm trying to creating linear linked list recursively with c language,
but keep sticking from here and the code is not working with the error "Linker Tools Error LNK2019". Sadly i can't understand what's the matter. Here is my code.
Thanks for your big help in advance.
#include <stdio.h>
#include <stdlib.h>
struct node
{
char num; //Data of the node
struct node *nextptr; //Address of the next node
};
typedef struct node element;
typedef element *link;
link head;
void displayList(); // function to display the list
int main()
{
char s[] = "abc";
link stol(s);
{
link head;
if (s[0] == '\0')return(NULL);
else {
head = (link)malloc(sizeof(element));
head->num = s[0];
head->nextptr = stol(s + 1);
return(head);
}
}
printf("\n\n Linked List : To create and display Singly Linked List :\n");
printf("-------------------------------------------------------------\n");
displayList();
return 0;
}
void displayList()
{
link tmp;
if (head == NULL)
{
printf(" List is empty.");
}
else
{
tmp = head;
while (tmp != NULL)
{
printf(" Data = %d\n", tmp->num); // prints the data of current node
tmp = tmp->nextptr; // advances the position of current node
}
}
}
You redefine a link object called head in your main() function. It hides the global head variable.
Removing the definition inside main would fix your problem, but you should consider passing a link* as a parameter to your displayList function in any case.
I've just noticed this statement return(head); in main(). You program exits prematurely as a result as well.
Everytime I look at your app, I find more issues. If I were you, I'd start by creating a function that adds a node to the list. It's much easier to add new nodes to the front of the list, so you should try that first. Try adding to the tail once you get this running. Adding to the tail is very similar, but you have to 'walkthe list first to get to the last element, exactly as you already do indisplayList()` Another way is keeping the address of the last node* you've added to the list. Like I said, it adds a bit of complexity, so get it working with addToHead first.
void addToHead(link* l, node* n)
{
n->nextptr = l->nextptr;
l->nextptr = n;
}
in your main, you can allocate one new node at a time, as you already do with malloc(). Initialize its contents num with an integer, and let addToHead deal with the pointer stuff. Your use of pointers is terrible, but lists are quite easy, and addToList pretty much shows what can and what should be put in pointers - namely other pointers.
You can remove almost everything in main() before the first printf. You'll have to
start loop:
write a prompt so the user knows what to do using printf()
read input from user using scanf("%d", &n), or equivalent.
break from the loop if user enters a negative value.
malloc() a new node
set its data num = n
call addToHead to add the node.
Loop until user enters an empty string, or -1.
That should take about 8 to 10 lines of code. if in doubt, you will easily find documentation on scanf, with google or on http://en.cppreference.com/w/c.

Double pointer to binary search-tree node

This might seem like a silly question to some of you and I know that I get things mixed up quite often but I need to understand the code so I can stop obsessing about it and focus on the real matter of why I need to use it.
So, in the code I see several assignments like this:
struct bst_node** node = root;
node = &(*node)->left;
node = &(*node)->right;
is there an invisible parenthesis here?
node = &((*node)->right);
This example is taken from literateprograms.org.
So to me it seems &(*node) is unnecessary and I might as well just write node->left instead, but the code seems to work where I can't make sense of it and I'm wondering if it's because I'm misunderstanding what's happening at those lines. Particularly, at one place in the code where it is deleting a node by constantly moving the "deleted" data to the bottom of the tree to safely remove the node without having to "break things", I'm lost because I don't get how
old_node = *node;
if ((*node)->left == NULL) {
*node = (*node)->right;
free_node(old_node);
else if ((*node)->right == NULL) {
*node = (*node)->left;
free_node(old_node);
} else {
struct bst_node **pred = &(*node)->left;
while ((*pred)->right != NULL) {
pred = &(*pred)->right;
}
psudo-code: swap values of *pred and *node when the
bottom-right of the left tree of old_node has been found.
recursive call with pred;
}
can keep the tree structure intact. I don't understand how this makes sure the structure is intact and would appreciate some help from somebody who knows what's going on. I interpret node being a local variable on the stack, created at the function call. Since it is a double pointer it points to a location in the stack (I assume this, since they did &(*node) previously to the function call), of either it's own stack or the function before, which then points to said node on the heap.
In the example code above what I think it is supposed to do is switch either left or right, since one of them is NULL, and then switch the one that isn't (assuming the other one isn't NULL?) As I said, I'm not sure about how this would work. My question mostly relates to the fact that I think &(*node) <=> node but I want to know if that's not the case etc.
node = &(*node)->right;
is there an invisible parenthesis here?
node = &((*node)->right);
Yes. It is taking the address of the right member of *node. The -> takes precedence over &; see C++ Operator Precedence (-> is 2 and & is 3 in that list) (it's the same general precedence as C).
So to me it seems &(*node) is unnecessary and I might as well just write node->left instead,
Your premise is off. There is no expression &(*node), as explained above, the & applies to the entire (*node)->left, not (*node).
In that code the double pointers are just that, a pointer to a pointer. Just as this works:
int x = 0;
int *xptr = &x;
*xptr = 5;
assert(x == 5);
This is the same, it changes the value of the pointer x:
int someint;
int *x = &someint;
int **xptr = &x;
*xptr = NULL;
assert(x == NULL);
In that code snippet you posted, assigning a pointer to *node changes the value of the pointer that node points to. So, e.g. (pseudo-ish code):
typedef struct bst_node_ {
struct bst_node_ *left;
struct bst_node_ *right;
} bst_node;
bst_node * construct_node () {
return a pointer to a new bst_node;
}
void create_node (bst_node ** destination_ptr) {
*destination_ptr = construct_node();
}
void somewhere () {
bst_node *n = construct_node();
create_node(&n->left); // after this, n->left points to a new node
create_node(&n->right); // after this, n->right points to a new node
}
Noting again that &n->left is the same as &(n->left) because of precedence rules. I hope that helps.
In C++ you can pass arguments to a function by reference, which is essentially the same as passing a pointer except syntactically it leads to code that is a bit easier to read.
That is useful
&(*node)->left <=>&((*node)->left)
The variable edited by this code is *node. I need the context fo this code to give more info

c - Adding new item to a list

This function get a pointer to the "Dummy" item of the list (1st item) and a struct typed "Node" to add...
But it goes into an infinite loop... whats wrong???
void listAdd(Node* dummy, Node tmpNode) {
Node* toAdd = (Node*)malloc(sizeof(Node));
*toAdd = tmpNode;
Node *tmp1,*tmp2;
tmp1 = dummy;
tmp2 = (*dummy).next;
while (tmp1 != NULL){
if ( ((*tmp1).info.id < (*toAdd).info.id && (*tmp2).info.id > (*toAdd).info.id ) || (tmp2==NULL) ) {
(*toAdd).next = (*tmp1).next;
(*tmp1).next = toAdd;
return;
}
tmp1 = (*tmp1).next;
tmp2 = (*tmp2).next;
}
}
EDIT:
I got a bit carried away with this (it's a slow day at work) so I rewrote the function to use (IMHO) clearer variable names, fewer redundant variables, and added basic error handling. The example below supports insertion whereas the previous example assumed simple appending to the end of a list which was the result of not reading the question properly (see edits if you're curious).
void listAdd(Node* currentNode, Node toAdd)
{
Node * newNode = malloc(sizeof(Node));
if(!newNode){
//ERROR HANDLING
}
* newNode = toAdd;
newNode->next = NULL;
while (currentNode)
{
if(!currentNode->next)
//We've got to the end of the list without finding a place to insert the node.
//NULL pointer always evaluates to false in C regardless of the underlying value.
{
currentNode->next = newNode;
return;
}
//Test each member of the list to find out whether to insert or skip.
if((newNode->info.id > currentNode->info.id) && (newNode->info.id <= currentNode->next->info.id) ){
newNode->next = currentNode->next;
currentNode->next = newNode;
return;
}
else currentNode = currentNode->next;
}
}
As has been mentioned in previous posts. dereferencing a pointer to a struct member uses the rather pretty -> notation which has a rather good imagery to it. Note also, that NULL will always evaluate as false, and that unless you want some bad things to happen (at best a segfault, at worst some takes over your machine) you need to make sure you're writing into proper memory areas, so you must always check that malloc returns !NULL.
note: In C, never cast the return value of a malloc() call as this can mask strange and dangerous behaviours. In C++, you must cast the result, so you need to think about who you're going to offend if you expect your program to compile as valid C and C++. See Do I cast the result of malloc? for details.

Resources