I am trying to create a dynamic array of simple linked lists. The MAX_SIZE is 5. I would like to insert
a new node, for example the character 'c', at (link[5]). For every new character, i would like to allocate a new entry at the bottom of the array.
When i execute my code, I get this output above. I think there is a problem with realloc
[0] a b NULL
[1] c NULL
[2] f e d NULL
[3] NULL
[4] NULL
but the expected output is below:
[0] a b NULL
[1] c NULL
[2] f e d NULL
[3] NULL
[4] NULL
[5] c
My code is here
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
char data;
struct Node *next;
} Node;
int push_front( Node **head, char data )
{
Node *new_node = malloc( sizeof( Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
return success;
}
void output( Node **head )
{
for( Node *current =*head; current != NULL && current->data != -1 ; current = current->next )
{
printf( "%c ", current->data );
}
printf( "%s", "NULL" );
}
void display( Node **set, int n )
{
for (int i = 0; i < n; i++){
printf("[%d] ", i);
output(&(set[i]));
printf("\n");
}
}
#define N 5
int main(void)
{
//Node * link[N] = { 0 };
Node **link;
link = calloc(N , sizeof (Node*));
for (int i = 0; i < N; i++){
link[i] = calloc(N , sizeof (Node));
link[i]->data = -1;
}
push_front( &link[0], 'b' );
push_front( &link[0], 'a' );
push_front( &link[1], 'c' );
push_front( &link[2], 'd' );
push_front( &link[2], 'e' );
push_front( &link[2], 'f' );
link = (Node **) realloc(link, (N + 1) * sizeof(Node*));
for(int i = 0; i < N + 1; i++){
link[i] = (Node *)realloc(link[i],(N + 1) * sizeof(Node));
}
push_front( &link[5], 'c' );
display(link, N);
return 0;
}
OP is doing some serious mistake while allocating memory to list and the accepted answer is not pointing out those mistakes. Hence, I am posting this answer.
I am trying to create a dynamic array of simple linked lists....
The way you are allocating memory, initially, you are creating array of array's of Node type objects.
From calloc(): [emphasis added]
void* calloc( size_t num, size_t size );
Allocates memory for an array of num objects of size and initializes all bytes in the allocated storage to zero.
So, this loop:
for (int i = 0; i < N; i++){
link[i] = calloc(N , sizeof (Node));
link[i]->data = -1;
}
will end up allocating memory for an array of N objects of size of Node type to link[i] pointer, where value of i lies in [0, 5).
The in-memory view would be something like this:
(read `n` as `next` pointer
and `:` is separator between `data` and `next` member of a node)
---- ----------------------
link[0] | | -> |-1:n|0:n|0:n|0:n|0:n| <---- array of Node type objects
| | ----------------------
| |
---- ----------------------
link[1] | | -> |-1:n|0:n|0:n|0:n|0:n| <---- array of Node type objects
| | ----------------------
| |
---- ----------------------
link[2] | | -> |-1:n|0:n|0:n|0:n|0:n| <---- array of Node type objects
| | ----------------------
| |
---- ----------------------
link[3] | | -> |-1:n|0:n|0:n|0:n|0:n| <---- array of Node type objects
| | ----------------------
| |
---- ----------------------
link[4] | | -> |-1:n|0:n|0:n|0:n|0:n| <---- array of Node type objects
| | ----------------------
| |
----
After calling push_front() on link array elements, the in-memory view would be something like this:
(read `n` as `next` pointer
and `:` is separator between `data` and `next` member of a node)
---- ----- ----- ----------------------
link[0] | | -> |a:n| -> |b:n| -> |-1:n|0:n|0:n|0:n|0:n|
| | ----- ----- ----------------------
| |
---- ----- ----------------------
link[1] | | -> |c:n| -> |-1:n|0:n|0:n|0:n|0:n|
| | ----- ----------------------
| |
---- ----- ----- ----- ----------------------
link[2] | | -> |f:n| -> |e:n| -> |d:n| -> |-1:n|0:n|0:n|0:n|0:n|
| | ----- ----- ----- ----------------------
| |
---- ----------------------
link[3] | | -> |-1:n|0:n|0:n|0:n|0:n|
| | ----------------------
| |
---- ----------------------
link[4] | | -> |-1:n|0:n|0:n|0:n|0:n|
| | ----------------------
| |
----
Here:
link = (Node **) realloc(link, (N + 1) * sizeof(Node*));
the link pointer will be reallocated the memory of new size N + 1 (assuming realloc() was success).
and, this loop:
for(int i = 0; i < N + 1; i++){
link[i] = (Node *)realloc(link[i],(N + 1) * sizeof(Node));
}
will end up reallocating link[i] pointer to memory of size N + 1 objects of Node type. You don't need to realloc() the link[i] pointers. The link[i] pointers are head of their respective linked list.
Now, you must be thinking - why printing of list giving expected output?
Because the reallocation is done by either:
a) expanding or contracting the existing area pointed to by ptr, if possible. The contents of the area remain unchanged up to the lesser of the new and old sizes. If the area is expanded, the contents of the new part of the array are undefined.
b) allocating a new memory block of size new_size bytes, copying memory area with size equal the lesser of the new and the old sizes, and freeing the old block.
So, link[i] pointers were pointing to a memory of a Node type object and realloc() will maintain the content of this memory after reallocation.
After reallocation, the in-memory view would be something like this:
(read `n` as `next` pointer, x as some garbage value
and `:` is separator between `data` and `next` member of a node)
---- ------------------------- ----- ----------------------
link[0] | | -> |a:n|x:n|x:n|x:n|x:n|x:n| |-> |b:n| -> |-1:n|0:n|0:n|0:n|0:n|
| | ---|--------------------- | ----- ----------------------
| | \----------------------/
---- ------------------------- ----------------------
link[1] | | -> |c:n|x:n|x:n|x:n|x:n|x:n| |-> |-1:n|0:n|0:n|0:n|0:n|
| | ---|--------------------- | ----------------------
| | \----------------------/
---- ------------------------- ----- ----- ----------------------
link[2] | | -> |f:n|x:n|x:n|x:n|x:n|x:n| |-> |e:n| -> |d:n| -> |-1:n|0:n|0:n|0:n|0:n|
| | ---|--------------------- | ----- ----- ----------------------
| | \----------------------/
---- --------------------------
link[3] | | -> |-1:n|0:n|0:n|0:n|0:n|x:n|
| | --------------------------
| |
---- --------------------------
link[4] | | -> |-1:n|0:n|0:n|0:n|0:n|x:n|
| | --------------------------
| |
---- -------------------------
link[5] | | -> |x:n|x:n|x:n|x:n|x:n|x:n|
| | -------------------------
| |
----
You can see the next pointers are preserved after reallocation and that's why when you are printing the list you are getting output as expected. I hope this giving you clear picture of mistakes you are making while allocating memory.
Now, after this statement
push_front( &link[5], 'c' );
the in-memory view of link[5] would be something like this:
---- ----- -------------------------
link[5] | | -> |c|n| -> |x:n|x:n|x:n|x:n|x:n|x:n|
| | ----- -------------------------
| |
----
Note that your output() may not work as expected while printing the link[5] list because the output() function for loop works on condition current != NULL && current->data != -1 and neither realloc() initialise memory to 0 (as the calloc() does) and nor you are assigning -1 to list[5]->data.
You don't need to allocate memory to link[i] pointers. The push_front() function is allocating the memory and creating a new node and adding that node in the array member list whose address passed as argument to push_front() function. Also, you should take care of freeing the list once done with them i.e. free the dynamically allocated memory before exiting.
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
#define N 5
typedef struct Node {
char data;
struct Node *next;
} Node;
int push_front (Node **head, char data) {
Node *new_node = malloc (sizeof (Node));
int success = new_node != NULL;
if (success) {
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
return success;
}
void output (Node **head) {
for (Node *current = *head; current != NULL; current = current->next) {
printf ("%c ", current->data);
}
printf ("%s", "NULL");
}
void display (Node **set, int n) {
for (int i = 0; i < n; i++) {
printf ("[%d] ", i);
output (&(set[i]));
printf ("\n");
}
}
Node ** reallocate_list (Node **list, size_t old_size, size_t new_size) {
if (old_size == new_size) {
return list;
}
Node **temp = realloc (list, new_size * sizeof(Node*));
if (temp == NULL) {
printf ("Failed to allocate memory.\n");
/* do cleanup stuff and handle the allocation failure
* the way you want. I am simply exiting on allocation failure.
*/
exit (EXIT_FAILURE);
}
if (old_size < new_size) {
/* Initialise the newly added elements in the array
*/
for(size_t i = old_size; i < new_size; i++){
list[i] = NULL;
}
}
return temp;
}
void free_list (Node **head) {
Node *current = *head;
while (current) {
Node *x = current->next;
free (current);
current = x;
}
*head = NULL;
}
void free_all_list (Node **list, size_t num_of_lists) {
for (size_t i = 0; i < num_of_lists; i++) {
free_list (&list[i]);
}
}
int main (void) {
Node **link;
link = calloc(N , sizeof (Node*));
if (link == NULL) {
printf ("Failed to allocate memory.\n");
exit (EXIT_FAILURE);
}
printf ("link array size : %d\n", N);
/* handle the push_front() return value
*/
push_front (&link[0], 'b');
push_front (&link[0], 'a');
push_front (&link[1], 'c');
push_front (&link[2], 'd');
push_front (&link[2], 'e');
push_front (&link[2], 'f');
display (link, N);
printf ("Reallocating link array, new size : %d\n", N + 1);
link = reallocate_list (link, N, N + 1);
if (link == NULL) {
printf ("Failed to allocate memory.\n");
exit (EXIT_FAILURE);
}
push_front (&link[5], 'c');
display (link, N + 1);
free_all_list (link, N + 1);
free (link);
return 0;
}
Output:
# ./a.out
link array size : 5
[0] a b NULL
[1] c NULL
[2] f e d NULL
[3] NULL
[4] NULL
Reallocating link array, new size : 6
[0] a b NULL
[1] c NULL
[2] f e d NULL
[3] NULL
[4] NULL
[5] c NULL
Related
I'm trying to implement a linked list and adding nodes to it. I encountered the following problem, when I try to free the pointer n after setting list->next to point to the same address of n, the int value inside the second node also changes to garbage value when I print it again. I want to know if inside the memory, n and list->next is stored as two separate pointers that hold the same value or it is stored as a single pointer? And if they were distinct, then why freeing n also affect list->next? Furthermore if freeing n make the second node became lost, then why I can still use the list->next->next pointer to add a third node, was list->next->next pointer also some random value that points to a random usable location ? Here is my code, sorry if my question is too vague, I'm trying my best to understand all this pointers.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
typedef struct node {
int number;
struct node *next;
} node;
int main(void) {
node a;
a.number = 1;
a.next = NULL;
node *list = NULL;
list = &a; // the first node
printf("%i \n", a.number);
node *n = malloc(sizeof(node)); // creating pointer to the second node
if (n != NULL) {
n->number = 2;
n->next = NULL;
}
list->next = n; // add the node to the list
printf("%p \n%p \n", n, list->next); // print out the address and value
printf("%i \n", list->next->number);
free(n);
printf("%p \n%p \n", n, list->next); // print out the address and value
printf("%i \n", list->next->number);
n = malloc(sizeof(node));
printf("%p \n%p \n", n, list->next);
if (n != NULL) {
n->number = 3;
n->next = NULL;
}
list->next->next = n;
printf("%i\n", (*(*(*list).next).next).number);
return 0;
}
Here is the output
1
0x5562319d62a0
0x5562319d62a0
2
0x5562319d62a0
0x5562319d62a0
1445140950
0x5562319d62a0
0x5562319d62a0
3
The assignment
list->next = n
doesn't copy the allocated memory. It just add another pointer pointing to the same memory.
If we "draw" it, before the assignment it looks something like this:
+---+ +-----------------+
| n | ---> | memory for node |
+---+ +-----------------+
Then after the assignment you have:
+---+
| n | -----------\
+---+ | +-----------------+
>--> | memory for node |
+------------+ | +-----------------+
| list->next | --/
+------------+
Then you pass n to free leading to this situation:
+---+
| n | -----------\
+---+ |
>--> ???
+------------+ |
| list->next | --/
+------------+
After the call to free, the pointer list->next is invalid. Any attempt to dereference it will lead to undefined behavior.
I'm trying to code out the functions for Doubly Linked Lists and am running into problems implementing the Delete at Position function.
It works as expected for the deletion of nodes in the first and last positions.
However, for the deletion of intermediate positions, it deletes it as expected the first time (at least on the surface, that is how it appears), the next time, however, it enters a garbage value for the intermediate position.
My Delete at Position function:
void delete_pos(struct node **p, int pos)
{
struct node *q;
q=*p;
int i=1;
while((q->next!=NULL)&&(i<pos))
{
q=q->next;
i++;
}
if(q==NULL) //empty list or invalid position
printf("Invalid Position\n");
else //position found
{
if(q->prev==NULL) //1st position
{
if(q->next==NULL) //only 1 node
*p=NULL;
else //more than 1 node
{
q->next->prev=NULL;
*p=q->next;
}
}
else if(q->next!=NULL) //intermediate position
{
printf("Yes\n"); //debugging check to make sure that it's going to the right condition
q->prev->next=q->next;
}
else //last position
q->prev->next=NULL; //
free(q);
}
}
Example of the problem I have with the output:
1<->2<->3<->4<->5<->NULL
is my Doubly Linked List.
If I call Delete at Position function and enter an intermediate value:
Enter position
2
1<->3<->4<->5<->NULL
It appears to works as expected the first time.
However, the next time I call:
Enter the position..
2
1<->6564704<->4<->5<->NULL
In another attempt it behaved weirdly as it didn't produce garbage value, it just didn't work the second time, the output:
1<->3<->4<->5<->NULL
Enter the position..
2
1<->4<->5<->NULL
Enter the position..
2
1<->4<->5<->NULL
Enter the position..
2
1<->4<->5<->NULL
My debugging attempt:
Through a print statement, I made sure that its' going into the intermediate condition :
else if(q->next!=NULL) //intermediate position
{
printf("Yes\n"); //debugging check to make sure that it's going to the right condition
q->prev->next=q->next;
}
And it was, however I cannot figure how the statement:
q->prev->next=q->next;
is wrong for intermediate position node deletion in a doubly linked list, as that is the only thing that stands out that could be going wrong.
Thank you for your time for reading this!
Whenever deleting from Linked Lists, always start from right and move towards left.
Suppose here p is the node you want to delete, then assume your list as
1-2-3-4-5
Now suppose you want to delete the node 3 then let p be that node.
Now do,
p-> right{4} -> left{3 at the moment} = p -> left{2 at the moment}
p-> left{2} -> right{3 at the moment} = p-> right{4}
p->left = NULL
p->right = NULL
With this your deletion will be done, you can additionally free the memory of p if you want to.
This might seem tricky at first so I recommend you to try it on paper, follow the 3 steps above and your deletion will work.
When deleting an intermediate node you do
q->prev->next=q->next;
which means that you make the node before q point to the node after q.
That is fine but since it is a doubly linked list you also need to make the node after q point to the node before q.
Something like:
q->prev->next=q->next;
q->next->prev=q->prev;
Further explanation:
If we draw your list like:
---------- ---------- ----------
| | | | | |
| next|------>| next|------>| next|
| NB | | Q | | NA |
|prev |<------|prev |<------|prev |
| | | | | |
---------- ---------- ----------
then you do
q->prev->next=q->next;
which change the list into
--------------
---------- / ---------- \ ----------
| | / | | \-->| |
| next|--/ | next|------>| next|
| NB | | Q | | NA |
|prev |<------|prev |<------|prev |
| | | | | |
---------- ---------- ----------
But that is only half of the pointers. You also need
q->next->prev=q->prev;
to get
--------------
---------- / ---------- \ ----------
| | / | | \-->| |
| next|--/ | next|------>| next|
| NB | | Q | | NA |
|prev |<------|prev | ---|prev |
| |<-\ | | / | |
---------- \ ---------- / ----------
---------------
Now you can delete Q to get
--------------
---------- / \ ----------
| | / \-->| |
| next|--/ | next|
| NB | | NA |
|prev | ---|prev |
| |<-\ / | |
---------- \ / ----------
---------------
The function invokes undefined behavior when initially the expression *p is a null pointer that is when the function deals with an empty list due to accessing memory using this null pointer
void delete_pos(struct node **p, int pos)
{
struct node *q;
q=*p;
int i=1;
while((q->next!=NULL)&&(i<pos))
^^^^^^^^
//...
You need to check whether the list is empty in the very beginning of the function before the while loop.
After the while loop
while((q->next!=NULL)&&(i<pos))
{
q=q->next;
i++;
}
if the list initially is not empty when the pointer q can not be equal to NULL because the next value is assigned to the pointer only when the condition q->next!=NULL is true. That means that the user can specify a non-existent position (for example a too big position) but the last node will be in any case deleted. Or the user of the function can pass a negative number as a value of the position and in this case the first node will be deleted.
The parameter that specifies the position should be declared as having an unsigned integer type for example size_t and positions should start from zero.
The function should report whether a node in a given position was successfully deleted. That is the function should be declared like
int delete_pos( struct node **p, size_t pos );
In case when the deleted node is not the head or tail node then you forgot to update the data member prev of the next node after the deleted node.
else if(q->next!=NULL) //intermediate position
{
printf("Yes\n"); //debugging check to make sure that it's going to the right condition
q->prev->next=q->next;
}
You updated only the data member next of the node before the deleted node.
The function can look the following way
int delete_pos( struct node **head, size_t pos )
{
while ( *head && pos-- )
{
head = &( *head )->next;
}
int success = *head != NULL;
if ( success )
{
struct node *current = *head;
if ( ( *head )->next != NULL )
{
( *head )->next->prev = ( *head )->prev;
}
*head = ( *head )->next;
free( current );
}
return success;
}
Here is a demonstrative program that shows the function in action.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *prev;
struct node *next;
};
size_t create( struct node **head, const int a[], size_t n )
{
while ( *head )
{
struct node *current = *head;
*head = ( *head )->next;
free( current );
}
size_t i = 0;
for ( struct node *prev = NULL;
i != n && ( *head = malloc( sizeof( **head ) ) ) != NULL;
i++ )
{
( *head )->data = a[i];
( *head )->prev = prev;
( *head )->next = NULL;
prev = *head;
head = &( *head )->next;
}
return i;
}
void display( const struct node *head )
{
const struct node *tail = NULL;
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
tail = head;
}
puts( "null" );
for ( ; tail != NULL; tail = tail->prev )
{
printf( "%d -> ", tail->data );
}
puts( "null" );
}
int delete_pos( struct node **head, size_t pos )
{
while ( *head && pos-- )
{
head = &( *head )->next;
}
int success = *head != NULL;
if ( success )
{
struct node *current = *head;
if ( ( *head )->next != NULL )
{
( *head )->next->prev = ( *head )->prev;
}
*head = ( *head )->next;
free( current );
}
return success;
}
int main(void)
{
struct node *head = NULL;
int a[] = { 1, 2, 3, 4, 5 };
create( &head, a, sizeof( a ) / sizeof( *a ) );
display( head );
putchar( '\n' );
delete_pos( &head, 0 );
display( head );
putchar( '\n' );
delete_pos( &head, 3 );
display( head );
putchar( '\n' );
delete_pos( &head, 1 );
display( head );
putchar( '\n' );
delete_pos( &head, 1 );
display( head );
putchar( '\n' );
delete_pos( &head, 0 );
display( head );
putchar( '\n' );
return 0;
}
The program output is
1 -> 2 -> 3 -> 4 -> 5 -> null
5 -> 4 -> 3 -> 2 -> 1 -> null
2 -> 3 -> 4 -> 5 -> null
5 -> 4 -> 3 -> 2 -> null
2 -> 3 -> 4 -> null
4 -> 3 -> 2 -> null
2 -> 4 -> null
4 -> 2 -> null
2 -> null
2 -> null
null
null
Currently i'm trying to store each separate line in my file into a string, and then store it in a binary search tree, but a problem occurs. For some reason when I print my BST only the last line is outputted and not the first 3. Below is my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
int count;
char* key;
struct node* left;
struct node* right;
};
struct node *newNode(char* item)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->key = item;
temp->left = NULL;
temp->right = NULL;
temp->count = 1;
return temp;
};
void printInorder(struct node* root)
{
if(root != NULL)
{
printInorder(root->left);
printf("%s \n", root->key);
printInorder(root->right);
}
}
struct node* insert(struct node* node, char* key)
{
if(node == NULL)//When tree is empty
return newNode(key);
if(strcmp(key, node->key) < 0)
node->left = insert(node->left, key);
if(strcmp(key, node->key) > 0)
node->right = insert(node->right, key);
return node;
};
int main()
{
struct node *root = NULL;
int i = 0;
char str[100];
FILE* fp;
fp = fopen("textFile.txt", "r");
if ((fp = fopen("textFile.txt","r")) == NULL)
{
printf("Could not open textFile.txt\n");
exit(1);
}
while(fgets(str, 100, fp) != NULL)
{
++i;
root = insert(root, str);
printf("%3d: %s", i, str);
}
printf("bst printed\n");
printInorder(root);
return 0;
}
textFile.txt contains
bob is working.
david is a new hire.
alice is bob's boss.
charles doesn't like bob.
And when the bst is printed the only line that is outputted is the last one
Charles doesn't like bob.
Any help would really be appreciated.
Notice that when you create a node with newNode, you store a copy of the pointer passed into it, rather than a copy of the string being pointed at. This means that every time you insert a value into the tree, it stores a pointer to the str buffer in main. In other words, after you do your first insertion, things look like this:
+------------+
| BST Node | str
+------------+ +---+---+---+---+---+...+---+
| key | ---------> | b | o | b | | i | | 0 |
+------------+ +---+---+---+---+---+...+---+
When you then read the next line of the file, you're overwriting str with the contents of that line, so the picture looks like this:
+------------+
| BST Node | str
+------------+ +---+---+---+---+---+...+---+
| key | ---------> | d | a | v | i | d | | 0 |
+------------+ +---+---+---+---+---+...+---+
Notice that your BST now acts as though it contains "david is a new hire" even though you never inserted that value. As a result, when you try inserting "david is a new hire" into the BST, nothing happens.
The same thing happens for the next few reads, until eventually you read the final line of the file, when things look like this:
+------------+
| BST Node | str
+------------+ +---+---+---+---+---+...+---+
| key | ---------> | c | h | a | r | l | | 0 |
+------------+ +---+---+---+---+---+...+---+
This is why you're only seeing the line about Charlie at the end - the BST is directing you to the single shared copy of the buffer.
To fix this, make your BST store copies of the strings passed into it, or copy the strings before storing them in the tree. For example, you might have the newNode function call strdup to get its own copy of the string to store:
struct node *newNode(char* item)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->key = strdup(item); // <--- here!
/* TODO: Error-handling! */
temp->left = NULL;
temp->right = NULL;
temp->count = 1;
return temp;
};
That should fix your issue. Just make sure to deallocate everything when you're done!
I have a function which creates a list based on a given array,
this is the function:
typedef struct Item
{
int num;
struct Item* next;
}*PItem;
int main()
{
int Arr[N] = { 3, 4, 1, 0, 8 }, i;
PItem list = NULL, tail = NULL;
CreateListFromArray(&list, &tail, Arr);
}
void CreateListFromArray(PItem* head, PItem* tail, int *Arr)
{
int i;
PItem temp;
for (i = 0; i<N; i++)
{
temp = (PItem)malloc(sizeof(struct Item));
if (temp == NULL)
{
DeleteList(head);
Error_Msg("Memmory!");
}
temp->num = Arr[i];
temp->next = NULL;
if (*head == NULL)
*head = temp;
else
(*tail)->next = temp;
*tail = temp;
}
}
I understand that if List is empty, then head's null is initialized to the first allocated temp (arr[0]). But after that, for these arrays arr[1],..,arr[N], I update only the tail, meaning that all the tails from arr[1] to arr[N] are connected. but how does the head (arr[0]) POINTS/connected to arr[1]?
I ask this because, when I try to print the list, I use temp = head, and advance head until temp is null, but when I advance head, how does it know that it has to advance to arr[1]?
Here's the full code: http://pastebin.com/VPCfMU4X
After the first iteration of the loop, head and tail point to the same element which contains arr[0]. After the second iteration, (*tail)->next (which is the same as (*head)->next) point to the new element that contains arr[1], and tail is moved up to this value. Subsequent iterations keep appending to the end of the list.
So after one iteration, you have this:
head tail
| |
v v
---------------
| 3 | NULL |
---------------
After the second iteration, you have this:
head tail
| |
v v
--------------- ---------------
| 3 | .-----|--->| 4 | NULL |
--------------- ---------------
And the third:
head tail
| |
v v
--------------- --------------- ---------------
| 3 | .-----|--->| 4 | .-----|--->| 1 | NULL |
--------------- --------------- ---------------
I have a circular doubly linked list and I want to change the direction of all the next and prev pointers. I can't really figure out what the source of the error is. When I print the reversed list, it gets the first two numbers correct but past that point the links list stops printing.
struct Link
{
TYPE value;
struct Link * next;
struct Link * prev;
};
struct CircularList
{
int size;
struct Link* sentinel;
};
static void init(struct CircularList* list)
{
list->sentinel = (struct Link *) malloc(sizeof(struct Link));
list->sentinel->next = list->sentinel;
list->sentinel->prev = list->sentinel;
list->size = 0;
}
struct CircularList* circularListCreate()
{
struct CircularList* list = malloc(sizeof(struct CircularList));
init(list);
return list;
}
void circularListAddFront(struct CircularList* list, TYPE value)
{
struct Link *newLink = (struct Link *) malloc(sizeof(struct Link));
newLink->value = value;
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next = newLink;
if(circularListIsEmpty(list)) {
list->sentinel->prev = newLink;
}
list->size++;
}
void circularListRemoveFront(struct CircularList* list)
{
struct Link *temp = list->sentinel->next;
temp->next->prev = list->sentinel;
list->sentinel->next = temp->next;
free(temp);
list->size--;
}
void circularListRemoveBack(struct CircularList* list)
{
struct Link *temp = list->sentinel->prev;
temp->prev->next = list->sentinel;
list->sentinel->prev = temp->prev;
free(temp);
list->size--;
}
void circularListReverse(struct CircularList* list)
{
struct Link *link = list->sentinel->next;
while(link != list->sentinel) {
struct Link *nextTemp = link->next;
struct Link *prevTemp = link->prev;
link->prev = link->next;
link->next = prevTemp;
link = nextTemp;
}
struct Link *temp = list->sentinel->next;
list->sentinel->next = list->sentinel->prev;
list->sentinel->prev = temp;
}
If I run the following to test this I get the output 5 4 1 2 2 1 and then terminates with no errors.
struct CircularList *deque = circularListCreate();
circularListAddBack(deque, 1);
circularListAddBack(deque, 2);
circularListAddBack(deque, 3);
circularListAddFront(deque, 4);
circularListAddFront(deque, 5);
circularListAddFront(deque, 6);
circularListRemoveFront(deque);
circularListRemoveBack(deque);
circularListPrint(deque);
circularListReverse(deque);
circularListPrint(deque);
There's a bug in your circularListAddFront function, and (though not shown) probably also in circularListAddBack:
Assume this state of the list:
p+SENTINEL+n
| A |
-----|------
Now, let's say you add 42 to the front. You first allocate a new node and set its value and pointers. Also you set the sentinel next pointer:
struct Link *newLink = (struct Link *) malloc(sizeof(struct Link));
newLink->value = value;
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next = newLink;
This leads to the following state:
p+SENTINEL+n
| A |
-----| |
| |
------ |
| | |
p+42+n |
A |
| |
---------
Which is not fine, because the prev pointer of the sentinel still points to itself. You fix that directly after that:
if(circularListIsEmpty(list)) {
list->sentinel->prev = newLink;
}
list->size++;
This gives the desired result:
p+SENTINEL+n
--| A |
| | |
| ------ |
| | | |
| p+42+n |
| A |
| | |
--------------
This is fine. Now let's add a 21 to the glorious list:
----------
| |
| V
| p+SENTINEL+n
| --| A |
| | | |
| | ------ |
| | | | |
| | p+42+n |
| | A |
| | | |
| -----| |
| | |
| p+21+n |
--| A |
| |
-----------
That's the state right before that if, and it has the same issue as before: There's one prev pointer wrong, this time it's not sentinels but the one of node 42: It should point to its previous node, which is now 21, and not to the sentinel.
Since the if is not taken, the sate remains. You don't notice it until reversing the list because you don't use the prev pointers until then.
To fix that, get rid of the if and correct the logic unconditionally:
When you insert a new node to the front ("after the sentinel"), then you need to change the prev pointer of the node that was at the front before and point it to the new node:
newLink->next = list->sentinel->next;
newLink->prev = list->sentinel;
list->sentinel->next->prev = newLink; // ADDITION
list->sentinel->next = newLink;
The code for reversing the list seems fine, though. And for now, I'm done with "line art ASCII graphics" :D