Can someone explain me why this code give me as result the empty list:
typedef struct str_node{
int data;
struct str_node *next;
}node;
void begin(node *head);
void display_list(node *head);
int main(){
node *head;
int i;
head = NULL;
for(i=0;i<5;i++) {
begin(head);
}
display_list(head);
return 0;
}
void begin(node *head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = head;
head = new;
}
But if i change the begin() function with the pointer to pointer it gives to me the right list?
void begin(node **head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = *head;
*head = new;
}
Can you also explain me why when i pass in the main the node head to the function begin i have to pass it as "&head"? and no more as "head"
In the first program in this code snippet
head = NULL;
for(i=0;i<5;i++) {
begin(head);
}
the pointer head is passed to the function begin by value. That is a copy of the value of the pointer head declared in main is created and is assigned to the parameter with the same name of the function begin
void begin(node *head);
So within the function it is the parameter head that holds initially a copy of the original pointer head that is changed. The original pointer head the value of which was assigned to the parameter is not being changed.
To change the original pointer head declared in main you have to pass it to the function by reference indirectly through a pointer to the pointer head as it is done in the second program.
So the function should be declared like
void begin(node **head);
And you have to pass the pointer head indirectly through a pointer to it
begin( &head );
In this case dereferencing the passed pointer the function will get a direct access to the original pointer head declared in main and can change it (not a copy of its value as it takes place in the first function definition)
new->next = *head;
*head = new;
To make it more clear consider this simple demonstrative program.
#include <stdio.h>
typedef int T;
void f( T t )
{
t = 10;
}
int main(void)
{
T t = 0;
printf( "Before calling f t is equal to %d\n", t );
f( t );
printf( "After calling f t is equal to %d\n", t );
return 0;
}
Its output is
Before calling f t is equal to 0
After calling f t is equal to 0
As the function f deals with a copy of the value of the passed argument the value of the variable t declared in main was not changed.
So you need to pass the original variable t by reference through pointer like
#include <stdio.h>
typedef int T;
void f( T *t )
{
*t = 10;
}
int main(void)
{
T t = 0;
printf( "Before calling f t is equal to %d\n", t );
f( &t );
printf( "After calling f t is equal to %d\n", t );
return 0;
}
Now the program output is
Before calling f t is equal to 0
After calling f t is equal to 10
In these demonstrative programs the name T is used as an alias for the type int and in main the object t has this type.
Let's now assume that the name T is an alias for the type int *.
typedef int * T;
In this case a declaration in main as for example
T t = NULL;
means that the variable t has the pointer type int *. That is it is equivalent to
int * t = NULL;
So to pass it to a function that must change the original variable t we need to pass it by reference like
f( &t );
that means that the corresponding function shall have the parameter type declared like
void f( T *t );
but as T is an alias for int * hence it means that the function has a parameter of the type int **.
void f( int * *t );
Because head is (effectively) a local variable, so changing it has no effect outside of the function, whereas changing *head changes what head points to, and thus does.
If you wanted a function to be able to change the value in an int variable (say, x), you would pass it a pointer to x, which would have the type int* and you would get the pointer to x by using &x. The same holds no matter what type x is.
A bit of confusion may come from declaring
node *head;
instead of
node* head;
You are declaring head. head is the variable and it is a pointer. It is not a node. Note also that a node is not a linked list: a linked list is a collection of nodes and possibly something else in order to have an useful implementation. More on this later at the end.
Fact is you have in main() declared head, just a node*. The node itself does not even exist yet. You declared begin() as
void begin(node *head);
and I think you will see it more clearly as
void begin(node* parameter);
parameter is node*.
Inside begin() you get a copy of the pointer and changing the pointer will not change the original pointer in main().
In your case it will in main() forever point to NULL.
What matters is that a pointer is like any variable: A pointer has an address. And a content. When you pass by value, just like you did, the pointer in begin() starts with NULL, the VALUE that came from main(). But the bond between them ends int the call: the initial value.
When you pass a pointer to begin(), using the operator 'address of' and writing &head things change: you will change it using the operator '*' meaning that you will change the address it points to, so it will change in main(). Since head is node* a pointer to it will be declared as node**
But consider changing the declaration of begin() for a linked list using:
node* begin(node* node);
The logic is that inserting a node can change the head of the list, so you return the new address, as in
node* _insert_begin(int value, node* pNode)
{
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = pNode;
return new;
}
is a common way to write this. Another is to use node**.
The way I am describing here, any operation that can change the head of the list must
return the new head
receive and update a pointer to the pointer of the head
See again this code that inserts at the beginning of the list:
node* _insert_begin(int value, node* pNode)
{ // insert 'value' at the start of the list
node* new = (node*)malloc(sizeof(node));
(*new).data = value;
new->next = pNode;
return new;
}
returning new you get head updated. And you can write in main()
node* another = NULL;
display_list(another);
// inserts 5 to 0 at the beginning
for (int i = 5; i >= 0; i -= 1)
another = _insert_begin(i, another);
printf("inserted 5..0 at the beginning\n");
display_list(another);
Note the line another = _insert_begin(i, another); and you see how the pointer in main() gets updated.
This is the output
empty list
inserted 5..0 at the beginning
0 1 2 3 4
5
list has 6 elements
Using this implementation of display_list(), that prints 5 values per line:
int display_list(node* p)
{
if (p == NULL)
{
printf("empty list\n");
return 0;
};
int count = 0;
// not empty
do
{
printf("%8d ", p->data);
count++;
if (count % 5 == 0) printf("\n");
p = p->next;
} while (p != NULL);
if (count % 5 != 0) printf("\n");
printf("list has %d elements\n", count);
return count;
};
Another example: inserting at the end
note that inserting at the end can also change the head, in the case that the list is empty, so we still need to return the head address
node* _insert_end(int value, node* pNode)
{ // insert value at the end of the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
while (p->next != NULL) p = p->next;
p->next = new;
return pNode;
}
Another use: inserting in ascending order
Sure, inserting in ascending order can also change the head, as in
node* _insert_ordered(int value, node* pNode)
{ // insert value at ascending order in the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
node* prev = NULL; // previous node: list if forward only
while (p->next != NULL)
{
if (new->data < p->data)
{
// insert before first greater than value
if (prev == NULL)
{
// new head
new->next = p;
return new;
}; // if()
prev->next = new;
new->next = p;
return pNode; // no change in head
};
prev = p; p = p->next; // updates pointers
}; // while()
// we are at the end: new will be the last?
if (new->data < p->data)
{
if (prev == NULL)
pNode = new;
else
prev->next = new;
new->next = p;
}
else
{
p->next = new;
};
return pNode;
} // _insert_ordered()
Deleting a list
Delete a list should also return a node* in order to invalidade the head pointer. It is usual. As you get used to the mechanic of it this ensures that an invalid pointer does not remain around.
Note that this logic is cooperative: you must assign the head pointer back at every call that can change the head
node* delete_list(node* H)
{
if (H == NULL) return NULL;
if (H->next == NULL)
{ // single node
free(H);
return NULL;
};
// more than one node
do
{ node* p = H->next;
free(H);
H = p;
} while (H != NULL);
return NULL;
};
A running program
Output of the example program
empty list
inserted 5..0 at the beginning
0 1 2 3 4
5
list has 6 elements
inserted 6 to 10 at the end
0 1 2 3 4
5 6 7 8 9
10
list has 11 elements
inserted 0 to 10, ordered
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10
list has 22 elements
inserted -1 to -10, ordered
-10 -9 -8 -7 -6
-5 -4 -3 -2 -1
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10
list has 32 elements
inserted 11 to 20, ordered
-10 -9 -8 -7 -6
-5 -4 -3 -2 -1
0 0 1 1 2
2 3 3 4 4
5 5 6 6 7
7 8 8 9 9
10 10 11 12 13
14 15 16 17 18
19 20
list has 42 elements
about to delete list
empty list
The example C program
#include <stdio.h>
#include <stdlib.h>
typedef struct str_node
{
int data;
struct str_node* next;
} node;
void begin(node* pNode);
node* delete_list(node*);
int display_list(node*);
node* _insert_begin(int, node*);
node* _insert_end(int, node*);
node* _insert_ordered(int, node*);
int main()
{
node* another = NULL;
display_list(another);
// insert 5 to 0 at the beginning
for (int i = 5; i >= 0; i -= 1)
another = _insert_begin(i, another);
printf("inserted 5..0 at the beginning\n");
display_list(another);
// insert 6 to 10 at the end
for (int i = 6; i <= 10; i += 1)
another = _insert_end(i, another);
printf("inserted 6 to 10 at the end\n");
display_list(another);
// insert 0 to 10 ordered
for (int i = 0; i <=10; i += 1)
another = _insert_ordered(i, another);
printf("inserted 0 to 10, ordered\n");
display_list(another);
// insert -1 to -10 ordered
for (int i = -1; i >= -10; i -= 1)
another = _insert_ordered(i, another);
printf("inserted -1 to -10, ordered\n");
display_list(another);
// insert 11 to 20 ordered
for (int i = 11; i <= 20; i += 1)
another = _insert_ordered(i, another);
printf("inserted 11 to 20, ordered\n");
display_list(another);
printf("about to delete list\n");
another = delete_list(another);
display_list(another);
return 0;
}
node* delete_list(node* H)
{
if (H == NULL) return NULL;
if (H->next == NULL)
{ // single node
free(H);
return NULL;
};
// more than one node
do
{ node* p = H->next;
free(H);
H = p;
} while (H != NULL);
return NULL;
};
node* _insert_begin(int value, node* pNode)
{ // insert 'value' at the start of the list
node* new = (node*)malloc(sizeof(node));
(*new).data = value;
new->next = pNode;
return new;
}
node* _insert_end(int value, node* pNode)
{ // insert value at the end of the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
while (p->next != NULL) p = p->next;
p->next = new;
return pNode;
}
node* _insert_ordered(int value, node* pNode)
{ // insert value at ascending order in the list
node* new = (node*)malloc(sizeof(node));
new->data = value;
new->next = NULL;
if (pNode == NULL) return new;
node* p = pNode;
node* prev = NULL; // previous node: list if forward only
while (p->next != NULL)
{
if (new->data < p->data)
{
// insert before first greater than value
if (prev == NULL)
{
// new head
new->next = p;
return new;
}; // if()
prev->next = new;
new->next = p;
return pNode; // no change in head
};
prev = p; p = p->next; // updates pointers
}; // while()
// we are at the end: new will be the last?
if (new->data < p->data)
{
if (prev == NULL)
pNode = new;
else
prev->next = new;
new->next = p;
}
else
{
p->next = new;
};
return pNode;
} // _insert_ordered()
int display_list(node* p)
{
if (p == NULL)
{
printf("empty list\n");
return 0;
};
int count = 0;
// not empty
do
{
printf("%8d ", p->data);
count++;
if (count % 5 == 0) printf("\n");
p = p->next;
} while (p != NULL);
if (count % 5 != 0) printf("\n");
printf("list has %d elements\n", count);
return count;
};
An arguably more useful Linked List structure
Consider the following
struct no
{
void* item;
struct no* next;
struct no* prev;
}; // no
typedef struct no Node;
typedef struct
{ // example, more flexible
char* name;
unsigned size;
unsigned capacity;
Node* head;
Node* tail;
} Linked_list;
This way a linked list is defined as a container of nodes.
It has even an optional name.
size is always available and up to date
a size limit can be implement as capacity
insert at the end and at the beginning does no require you to follow all other nodes, since the list encapsulates pointers to both head and tail
a node has pointers to next AND previous nodes so some data such as playlists or collections like that can be iterated more easily.
a program can have any number of lists since each one encapsulates all of this metadata.
a list can contains anything since the data is a pointer to void, void*
functions like empty() or size() can be implemented easily
all functions use a pointer to the list
Linked_list ll_one;
Linked_list many_ll[20];
Linked_list* pLL = &ll_one;
regarding:
void begin(node *head){
Changing head only changes the call stack 'head', what is needed is to change where 'head' in the caller's function points to. TO do that, the caller must pass the address of 'head'. The fact that 'head' is,itself, a pointer doesn't help with the clarity of what needs to be done,
Related
I am trying to write a recursive function to reverse a doubly linked list. This code is not complete yet but I am hit with a issue. The application is not executing completely.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct nodes
{
uint8_t x;
struct nodes *next;
struct nodes *prev;
}Node;
Node *head = NULL;
void rev_rec_dll(Node **a, Node **b)
{
//check if it is last node in the list
if((*a)->next != NULL)
{
//set next to prev and prev to next
(*a)->next = (*a)->prev;
(*a)->prev = (*b);
printf("done for node %d and moving on..\n", ((*a)->x));
//recursive call by passing next two nodes
rev_rec_dll(b, &((*b)->next));
}
else
{
printf("reached new head\r\n");
head = (*a);
}
}
void add_node(Node **h_node, uint8_t x)
{
//check if there is at least one node in the list and if not add first node
if((*h_node) == NULL)
{
*h_node = (Node *)malloc(sizeof(Node));
(*h_node)->x = x;
(*h_node)->next = NULL;
(*h_node)->prev = NULL;
}
else
{
Node *temp = *h_node;
//get the last node
while(temp->next != NULL)
{
temp = temp->next;
}
//add new node
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->x = x;
newNode->next = NULL;
newNode->prev = temp;
temp->next = newNode;
}
}
void display_nodes(Node *h_node)
{
while(h_node != NULL)
{
printf("Node: %u\n", h_node->x);
h_node = h_node->next;
}
}
int main(int argc, char **argv)
{
//add three nodes
add_node(&head, 1);
add_node(&head, 2);
add_node(&head, 3);
//display nodes
display_nodes(head);
//add three more nodes
add_node(&head, 4);
add_node(&head, 5);
add_node(&head, 6);
//display all 6 nodes
display_nodes(head);
//reverse the linked list
rev_rec_dll(&head, &(head->next));
//display reversed nodes
display_nodes(head);
return 0;
}
The output of the program is given below:
Node: 1
Node: 2
Node: 3
Node: 1
Node: 2
Node: 3
Node: 4
Node: 5
Node: 6
done for node 1 and moving on..
I want to know what is wrong in the function rev_rec_dll(). Also, I want to know if the way I am passing the arguments to this function is correct or not. If it is not correct please provide appropriate reason on why it is wrong. The arguments passed to rev_rec_dll function is current node and next node in the linked list.
The reversing logic may not be accurate but I want to know if the way the arguments are passed is correct. Why does it exit in the middle? A memory violation?
For starters it is a bad idea to declare the pointer to head node as a file scope variable and when the functions depend on the file scope variable.
Node *head = NULL;
You should move this declaration inside the function main and correspondingly rewrite your functions.
Also the structure declaration will look better if to declare it like
typedef struct Node
{
uint8_t x;
struct Node *next;
struct Node *prev;
} Node;
Otherwise the names nodes and Node will only confuse readers of the code.
There are two problems with the function. The first one is that initially the second function argument points to the data member next of the head node
rev_rec_dll(&head, &(head->next));
that is changed within the function in the compound statement of the if statement.
To make it clear consider a list that contains only two nodes
| NULL <- 1 -> 2 | <-> | 1 <- 2 -> NULL|
Inside the first recursive call of the function there are executed the following statements
(*a)->next = (*a)->prev;
(*a)->prev = (*b);
Again pay attention to that the function is called like
rev_rec_dll(&head, &(head->next));
That is the parameter b of the function points to the data member next of the head node and the first of the above statements changes the value of the data member
(*a)->next = (*a)->prev;
So now the expression *b yields data member next that now contains the value of the data member prev (in this case NULL).
In fact you have
(*a)->next = (*a)->prev;
(*a)->prev = ( *a )->next; //(*b);
because the expressions ( *a )->next and *b are equivalent due to initializations of parameters by argument expressions.
That is the both data members. next and prev, get the initial value of the data member prev and you have
| NULL <- 1 -> NULL | <- | 1 <- 2 -> NULL|
Then the function is called like
rev_rec_dll(b, &((*b)->next));
that invokes undefined behavior because the expression *b yields a null pointer.
Another problem is that in this code snippet
else
{
printf("reached new head\r\n");
head = (*a);
}
data members prev and next of the last node in the list are not changed because the control is bypassed the compound statement of the if statement
And moreover your function will invoke undefined behavior if it will
be called for an empty list.
The function should be declared with only one parameter like for example
void rev_rec_dll( Node **head );
Here is a demonstration program that shows how the recursive function that reverses the list can be implemented.
In the demonstration program there is not used a file scope pointer to the head node. In this case within a program you will be able to define multiple lists.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
typedef struct Node
{
uint8_t x;
struct Node *next;
struct Node *prev;
} Node;
void clear( Node **head )
{
while (*head)
{
Node *current = *head;
*head = ( *head )->next;
free( current );
}
}
size_t assign( Node **head, const uint8_t *a, size_t n )
{
clear( head );
size_t cnt = 0;
for ( Node *prev = NULL; n-- && ( *head = malloc( sizeof( Node ) ) ) != NULL; cnt++)
{
( *head )->x = *a++;
( *head )->next = NULL;
( *head )->prev = prev;
prev = *head;
head = &( *head )->next;
}
return cnt;
}
void rev_rec_dll( Node **head )
{
if ( *head )
{
Node *tmp = ( *head )->next;
( *head )->next = ( *head )->prev;
( *head )->prev = tmp;
if (( *head )->prev != NULL)
{
*head = ( *head )->prev;
rev_rec_dll( head );
}
}
}
void display_nodes( const Node *head )
{
for (; head != NULL; head = head->next)
{
printf( "%" PRIu8 " -> ", head->x );
}
puts( "null" );
}
int main( void )
{
Node *head = NULL;
uint8_t a[] = { 1, 2, 3, 4, 5, 6 };
assign( &head, a, sizeof( a ) / sizeof( *a ) );
display_nodes( head );
rev_rec_dll( &head );
display_nodes( head );
clear( &head );
}
The program output is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null
6 -> 5 -> 4 -> 3 -> 2 -> 1 -> null
There's no real point of using pointer to a pointer in rev_rec_dll(Node **a, Node **b), i would suggest you read into practical implications of pointers to pointers
What you can do here is just use regular pointers like so:
void rev_rec_dll(Node* a, Node* b)
{
//check if it is last node in the list
if(a->next != NULL)
{
//set next to prev and prev to next
a->next = a->prev;
a->prev = b;
printf("done for node %d and moving on..\n", a->x);
//recursive call by passing next two nodes
rev_rec_dll(b, b->next);
}
else
{
printf("reached new head\r\n");
head = a;
}
}
then in main function call it like so
rev_rec_dll(head, head->next);
also, as Vlad mentioned you shouldn't use two parameters in this function, it adds unnecessary complexity as well as makes it a bit harder to track if you pass and use NULL in the future.
also also, it's best that you learn how to use debugger now to see where things hit the fan clearly.
This is my code for insertion in the end of a circular linked list for which I am getting correct result
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void insert(int val)
{
struct node *temp;
struct node *tail;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = val;
if (head == NULL)
{
head = temp;
tail = temp;
temp->next = head;
}
else
{
tail->next = temp;
tail = temp;
tail->next = head;
}
}
void printlist()
{
struct node *temp = head;
printf("The elements of the linked list area \n ");
while (temp->next != head)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("%d ", temp->data);
printf("%d", temp->next->data);
}
int main()
{
int n, i, val;
printf("Enter how many elements in a circular likedlist you want \n");
scanf("%d",&n);
head = NULL;
for(i=0;i<n;i++)
{
// printf("Enter the value\n");
// scanf("%d,&val");
insert(i);
}
printlist();
}
for which the output is
Enter how many elements in a circular likedlist you want
10
The elements of the linked list area
0 1 2 3 4 5 6 7 8 9 0
However, for the same code when I try to take values from the user it gives me incorrect output.here in this code I just changed a part of the main function inside the for loop where I am taking input for the val instead of passing an integer in function insert
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void insert(int val)
{
struct node *temp;
struct node *tail;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = val;
if (head == NULL)
{
head = temp;
tail = temp;
temp->next = head;
}
else
{
tail->next = temp;
tail = temp;
tail->next = head;
}
}
void printlist()
{
struct node *temp = head;
printf("The elements of the linked list area \n ");
while (temp->next != head)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("%d ", temp->data);
printf("%d", temp->next->data);
}
int main()
{
int n, i, val;
printf("Enter how many elements in a circular likedlist you want \n");
scanf("%d",&n);
head = NULL;
for(i=0;i<n;i++)
{
printf("Enter the value\n");
scanf("%d,&val");
insert(val);
}
printlist();
}
For this program, the output I am getting is
Enter how many elements in a circular likedlist you want
5
Enter the value
1
The elements of the linked list area
0 0
Can anyone suggest me where my code is going wrong?
Symptoms: "It worked, then it didn't." This is the hallmark of UB. Your compiler didn't output code that affected the stack between iterative calls in your first example. The bytes used for tail during each invocation were not overwritten. In the second example ("user input"), scanf() has made use of the same region of stack (as it should), and the fortunate behaviour of the first example became unfortunate. This is why "It worked, then it didn't." Undefined behaviour has many guises...
If you want to be respected as a coder, you don't use global variables, and then compound the mistake with adding more globals. Or 'scanning' what could be millions of nodes to find the tail of a LL.
The code below declares an ordinary node, and a special header node that are compatible.
The testing in main() uses two LLs; one for some integer values, and one that grows with only the odd numbered integer values.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node_t;
typedef struct {
int data; // NB: same name & order of 1st two struct members
node_t *next; // (ditto)
node_t *tail; // head knows where its backend is
int cnt; // meta-information becomes simple to implement
int id;
} head_t;
head_t *append( head_t *ph, int val ) {
static int take_a_number = 0;
node_t *nn = (node_t *)calloc( 1, ph ? sizeof(node_t) : sizeof(head_t) );
/* omitting check */
nn->data = val;
nn->next = nn; // for now, a 'ringlet'
if( ph == NULL ) {
ph = (head_t*)nn; // notice the casting of compatible struct entities
ph->tail = nn;
ph->id = ++take_a_number;
} else {
nn->next = (node_t*)ph;
ph->tail = ph->tail->next = nn;
}
ph->cnt++;
// debug traversal showing results
printf( "list #%d - %d nodes: ", ph->id, ph->cnt );
node_t *p = (node_t*)ph;
do
printf( "%d ", p->data );
while( (p = p->next) != (node_t*)ph );
puts( "" );
return ph;
}
int main() {
int i;
// two lists. Could be 100, or an array of them...
head_t *p1 = NULL, *p2 = NULL;
for( i = 7; i <= 49; i += 7 ) { // just some arbitrary data
p1 = append( p1, i );
if( i%2 )
p2 = append( p2, i );
}
printf( "Two laps around first list: " );
node_t *pFun = (node_t*)p1;
for( i = 2*p1->cnt + 1; i; i-- )
printf( "%d ", pFun->data ), pFun = pFun->next;
puts( "" );
/* omitting `free()` of heap */
return 0;
}
Output
list #1 - 1 nodes: 7
list #2 - 1 nodes: 7
list #1 - 2 nodes: 7 14
list #1 - 3 nodes: 7 14 21
list #2 - 2 nodes: 7 21
list #1 - 4 nodes: 7 14 21 28
list #1 - 5 nodes: 7 14 21 28 35
list #2 - 3 nodes: 7 21 35
list #1 - 6 nodes: 7 14 21 28 35 42
list #1 - 7 nodes: 7 14 21 28 35 42 49
list #2 - 4 nodes: 7 21 35 49
Two laps around first list: 7 14 21 28 35 42 49 7 14 21 28 35 42 49 7
0 global variables, and traversing the LL is only done when printing. This is part of structured programming.
The easiest fix is probably to make tail a global variable like head. I also refactored insert() to reduce duplication, added error checking for malloc() and scanf(), tweaked printlist() to not print the head twice:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head;
struct node *tail;
void insert(int val) {
struct node *temp = malloc(sizeof(*temp));
if(!temp) {
printf("malloc failed\n");
exit(1);
}
temp->data = val;
if (head == NULL) {
head = temp;
} else {
tail->next = temp;
}
tail = temp;
tail->next = head;
}
void printlist() {
printf("The elements of the linked list area \n ");
for(struct node *temp = head; temp; ) {
printf("%d ", temp->data);
temp = temp->next;
if(temp == head) break;
}
printf("\n");
}
int main(void) {
printf("Enter how many elements in a circular likedlist you want \n");
int n;
if(scanf("%d", &n) != 1) {
printf("scanf failed\n");
return 1;
}
head = NULL;
for(int i=0; i<n; i++) {
insert(i);
}
printlist();
}
and it the output is now:
The elements of the linked list area
0 1 2 3 4 5 6 7 8 9
You could eliminate the head pointer (tail->next == head) if you want.
In the insert function, the else branch is dereferencing pointer variable tail that has not been initialized. (The variable tail has automatic storage class, i.e. it is a "stack" variable, so it's value is not preserved between calls to the function.) The tail variable needs to point to the last element on the list.
The function can be changed to search for the last element of the list like this:
void insert(int val)
{
struct node *temp;
struct node *tail;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = val;
if (head == NULL)
{
head = temp;
}
else
{
/* find last element */
for (tail = head; tail->next != head; tail = tail->next)
;
tail->next = temp;
}
temp->next = head;
}
(However, it probably makes more sense to store the tail statically outside the function as in Allan Wind's answer so that the function does not have to waste time finding the last element of the list each time it is called. It should also check for memory allocation failure, as in that answer.)
The printList function does not currently work if the list is empty. It will dereference head even if it is NULL, leading to undefined behavior. That can be fixed by moving the all code that accesses the elements of the list inside a if (head != NULL) { } block:
void printlist(void)
{
struct node *temp = head;
printf("The elements of the linked list are \n ");
if (head != NULL)
{
while (temp->next != head)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("%d ", temp->data);
printf("%d", temp->next->data);
}
printf("\n");
}
I have simple link list program, that would create/print it, and later on print the last 2 number from it (in reverse order)
cat link_list.c
/**
* C program to create and traverse a Linked List
*/
#include <stdio.h>
#include <stdlib.h>
/* Structure of a node */
struct node {
int data; // Data
struct node *next; // Address
}*head;
/*
* Functions to create and display list
*/
void createList(int n);
void traverseList();
void ReverseList(struct node *);
int main()
{
int n;
printf("Enter the total number of nodes: ");
scanf("%d", &n);
createList(n);
printf("\nData in the list \n");
traverseList();
ReverseList(head);
return 0;
}
/*
* Create a list of n nodes
*/
void createList(int n)
{
struct node *newNode, *temp;
int data, i;
head = (struct node *)malloc(sizeof(struct node));
// Terminate if memory not allocated
if(head == NULL)
{
printf("Unable to allocate memory.");
exit(0);
}
// Input data of node from the user
printf("Enter the data of node 1: ");
scanf("%d", &data);
head->data = data; // Link data field with data
head->next = NULL; // Link address field to NULL
// Create n - 1 nodes and add to list
temp = head;
for(i=2; i<=n; i++)
{
newNode = (struct node *)malloc(sizeof(struct node));
/* If memory is not allocated for newNode */
if(newNode == NULL)
{
printf("Unable to allocate memory.");
break;
}
printf("Enter the data of node %d: ", i);
scanf("%d", &data);
newNode->data = data; // Link data field of newNode
newNode->next = NULL; // Make sure new node points to NULL
temp->next = newNode; // Link previous node with newNode
temp = temp->next; // Make current node as previous node
}
}
/*
* Display entire list
*/
void traverseList()
{
struct node *temp;
// Return if list is empty
if(head == NULL)
{
printf("List is empty.");
return;
}
temp = head;
while(temp != NULL)
{
printf("Data = %d\n", temp->data); // Print data of current node
temp = temp->next; // Move to next node
}
}
static count=0, k=2;
ReverseList(struct node *head)
{
if (head == NULL)
return;
else {
ReverseList(head->next);
count++;
if (count <= k)
printf("Data = %d\n", head->data);
}
}
For an input 1 2 3 , it would first print 3 2 1 and then 3 2 correctly but I have confusion about the :
if (head == NULL)
return;
what exactly it returns with return;, and where head is pointing after the
ReverseList(head->next); statement ?
Lets say we have a simple three-node list like this:
1 -> 2 -> 3
When we initially call ReverseList we pass the 1 node as the head and we have this call-chain:
ReverseList(1 -> 2 -> 3 -> NULL)
ReverseList(2 -> 3 -> NULL)
ReverseList(3 -> NULL)
ReverseList(NULL)
printf(3)
printf(2)
printf(1)
For starters you forgot to specify the return type of the function in the function definition:
ReverseList(struct node *head)
{
if (head == NULL)
return;
else {
ReverseList(head->next);
count++;
if (count <= k)
printf("Data = %d\n", head->data);
}
}
You have to write:
void ReverseList(struct node *head)
As for your question:
I have confusion about the :
if (head == NULL)
return;
what exactly it returns with return;, and where head is pointing after the ReverseList(head->next); statement ?
Then as the function has the return type void and the return statement does not include an expression then the return statement returns nothing.
The function parameter head is a local variable of the function. The function does not change the pointer head declared in the file scope
struct node {
int data; // Data
struct node *next; // Address
}*head;
In the first call of the function the parameter head has the value of the global variable head due to this statement:
ReverseList(head);
If the value is not equal to NULL then the function recursively calls itself passing the value of the pointer head->next:
ReverseList(head->next);
So in the second recursive call of the function itself the value of its parameter head is equal to the value of head->next where in this expression head is the function parameter of the previous call of the function.
That is the parameter head at first gets the value of the global variable head and then the parameter is initialized sequentially by values of the data member next of the next node in the sequence.
So for the list that contains nodes with values 1, 2, 3 you have
1-st call
parameter head is equal to the global variable head
2-nd call
parameter head is equal to head->next that points to the node with the value 1
3-rd call
parameter head is equal to head->next->next that points to the node with the value 2
4-th call
parameter head is equal to head->next->next->next that points to the node with the value 3
5-th call
parameter head is equal to head->next->next->next->next and equal to NULL
Pay attention to that it is not a good idea to use static global variables within the function
static count=0, k=2;
You need to remember reinitialize them if you want to call the function one more time. It is better to make the variable k a function parameter.
The function could be defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
int push( struct node **head, int data )
{
struct node *new_node = malloc( sizeof( *new_node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
return success;
}
void display( const struct node *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
size_t display_last_n( const struct node *head, size_t n )
{
size_t i = 0;
if ( head != NULL )
{
i = display_last_n( head->next, n ) + 1;
if ( !( n < i ) )
{
if ( i != 1 ) printf( ", " );
printf( "%d", head->data );
}
}
return i;
}
void clear( struct node **head )
{
while ( *head )
{
struct node *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
int main(void)
{
struct node *head = NULL;
const int N = 10;
for ( int n = N; n--; )
{
push( &head, n );
}
display( head );
for ( size_t i = 0; i < N; i++ )
{
display_last_n( head, i + 1 );
putchar( '\n' );
}
clear( &head );
return 0;
}
The program output is:
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
9
9, 8
9, 8, 7
9, 8, 7, 6
9, 8, 7, 6, 5
9, 8, 7, 6, 5, 4
9, 8, 7, 6, 5, 4, 3
9, 8, 7, 6, 5, 4, 3, 2
9, 8, 7, 6, 5, 4, 3, 2, 1
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
I'm trying to implement a circular linked list in C, however I cant seem to print the nodes one by one. Below is the code for assigning the values and then printing them. Whenever I run it, all it prints out is "NULL". I would like to know what should i do so that it prints out "1 -> 2 -> 3 -> ...."
void tail_insert(struct Node * head, struct Node * tail, int num){
struct Node * p = (struct Node*) malloc(sizeof(struct Node));
p->info = num;
p->next = head;
if (head == NULL) {
head = p;
tail = head ;
}
else{
tail->next = p;
tail = p;
}
}
void print_list(struct Node * head)
{
struct Node * current = head;
while (current != NULL)
{
printf("%d -> ", current->info);
current = current->next;
}
printf("NULL\n");
}
int main(){
struct Node * head = NULL, * tail = NULL;
int num = 0;
int length;
int deletespace;
scanf("%d %d", &length, &deletespace);
for (int i = 1; i < length+1 ; i++){
tail_insert(head, tail, i);
}
print_list(head);
The reason you're not getting nodes printed is because of how pass by value works. When you call tail_insert, you're passing a basic pointer. Dereferencing and modifying this inside the function would modify the values pointed to by head and tail, but not carry changes to the pointers themselves outside the function.
One way of fixing this is to change the head and tail parameters to be pointers to pointers (**) and passing the addresses of those variables where you call the function in main.
The Code:
/*
* File: problem5.c
* Author: levihackwith
* Description: Write a Pop() function that is the inverse of Push(). Pop() takes a non-empty list, deletes the head node, and returns the head node's data.
*/
#include <stdio.h>
#include <stdlib.h>
struct node { // Our custom node data type
int data;
struct node *next;
};
/*
* Adds a node to a linked list.
*
* This method was taken from the Appendix of the LinkedListProblems.pdf file from Stanford University.
*/
void Push(struct node** headRef, int newData) {
struct node* newNode = malloc(sizeof (struct node)); // allocate node
newNode->data = newData;
newNode->next = (*headRef);
(*headRef) = newNode;
};
void InsertNth(struct node** headRef, int insertAt, int newData) {
struct node* newNode = malloc(sizeof (struct node)); // allocate node
struct node* current = *headRef;
int index = 0;
newNode->data = newData;
while (current != NULL) {
if (insertAt == 0 && index == 0) {
newNode->next = (*headRef);
(*headRef) = newNode;
current = *headRef;
printf("Current's data is now %d at index %d \n\n", current->data, index);
} else {
if (index == (insertAt - 1)) {
printf("I inserted %d at index %d \n", newData, insertAt);
newNode->next = current->next;
current->next = newNode;
}
}
current = current->next;
index++;
}
}
/*
* Builds a linked list of a given size.
*/
struct node* BuildList(int numNodes) {
struct node* head = NULL; // Start with the empty list
int i;
for (i = numNodes; i >= 1; i--) {
Push(&head, i); // Use Push() to add all the data
}
return (head);
};
int main(void) {
struct node* myLinkedList;
struct node* current;
int currentIndex = 0;
int valToInsert = 45;
int insertIndex = 0;
myLinkedList = BuildList(5);
current = myLinkedList;
InsertNth(&myLinkedList, insertIndex, valToInsert);
while (current != NULL) {
printf("The value at index %d is %d \n", currentIndex, current->data);
currentIndex++;
current = current->next;
}
return 0;
};
The Output
Current's data is now 45 at index 0
The value at index 0 is 1
The value at index 1 is 2
The value at index 2 is 3
The value at index 3 is 4
The value at index 4 is 5
The above output is for when the index to insert the new value at is zero. Here is the output when inserting at index 1.
I inserted 45 at index 1
The value at index 0 is 1
The value at index 1 is 45
The value at index 2 is 2
The value at index 3 is 3
The value at index 4 is 4
The value at index 5 is 5
As you can see, 0 doesn't work as expected while 1 does. What am I doing wrong?
What am I doing wrong?
You are setting up current before calling InsertNth. When you call InsertNth to insert at 0, the myLinkedList will change, so current will point to the second node.
Move current = myLinkedList; to after the InsertNth call to fix the problem:
myLinkedList = BuildList(5);
InsertNth(&myLinkedList, insertIndex, valToInsert);
current = myLinkedList;
Switch these two lines:
current = myLinkedList;
InsertNth(&myLinkedList, insertIndex, valToInsert);
In this order you are setting current to the head of the first part of the list, then adding more stuff to the head. This changes the head, but current still has its original value.