Lets say I have some linked lists already available and I want to store first node of each individual list into another list so that I can recall this list to display the original lists. I think we have to use two different structures. I am already successful in retaining original lists and displaying them using Array of first nodes of individual lists but I want to create a linked list of individual list to implement same. It has the expected output but as I said I want to use linked list instead of array of nodes.
Now this is how I am trying to solve the problem to replace the array of linked lists to linked list of first nodes, I am getting crashes whenever I try to debug code. Please help me.
#include <stdio.h>
#include <stdlib.h>
struct node{
int number;
struct node*next;
};
typedef struct node Node;
Node* insertValue(Node * list, int value);
void display(Node*);
struct list_of_nodes {
Node *list;
struct list_of_nodes *next;
};
typedef struct list_of_nodes ListNode;
ListNode* insertNode(ListNode* head,Node* node);
int main()
{
ListNode *head=NULL;
Node *globalList = NULL, *lists[100];
int nbrOfLists, listNo, nbrOfVal, valNo, val,i=0,k;
CHECKER:
printf("\n\n Enter the number of lists (1 to 100):");
scanf("%d", &nbrOfLists);
if(nbrOfLists <= 0 || nbrOfLists > 100) //handling exceptional cases
{
printf("\n \n Number of Lists should be between 1 to 100"); // since array of node pointers contains 100 elements
goto CHECKER;
}
for(listNo = 0; listNo < nbrOfLists; listNo++)
{
printf("\n\n Enter the number of inputs to the list %d: \n ",listNo+1);
scanf("%d", &nbrOfVal);
lists[listNo] = NULL;
for(valNo = 0; valNo < nbrOfVal; valNo++) // to enter values in each individual list
{
printf("Enter node value %d:", valNo+1);
scanf("%d", &val);
// Here we insert the value in both lists
lists[listNo]= insertValue(lists[listNo], val); // original list has to be retained so storing in array lists
globalList = insertValue(globalList, val); // inserting node in combined list. This prevents an extra loop and merges the list elements into one.
}
head=insertNode(head,lists[listNo]); // CRASHING HERE
printf("\n The list %d is: ",listNo+1);
display(lists[listNo]); // display each list after input
}
printf("\n\n\n THE FINAL LIST IS: ");
display(globalList); //display combined list
printf("\n\n THE LISTS WERE: ");
while(i<nbrOfLists){ //original lists displayed
k=i+1;
printf("\n\n The list %d is: ",k);
display(lists[i]);
i++;
}
printf("\n\n");
return 0;
}
ListNode* insertNode(ListNode* head, Node* node){
ListNode *newNode, *m;
newNode = malloc(sizeof(ListNode));
newNode->list=node;
if(newNode == NULL)
{
newNode->next=NULL; // inserting first node
return newNode;
}
m = head;
while(m->next) // checking for right position in ordered list for new node
{
m = m->next;
}
newNode->next = m->next; // inserting new node
m->next = newNode;
return head;
}
Node* insertValue(Node * list, int value) // function to insert node in ordered manner into list
{
Node *newNode, *m;
newNode = malloc(sizeof(Node));
newNode->number=value;
if(list == NULL)
{
newNode->next=NULL; // inserting first node
return newNode;
}
if(value < list->number)
{
newNode->next = list; // inserting in end
return newNode;
}
m = list;
while(m->next) // checking for right position in ordered list for new node
{
if(value < m->next->number)
break;
m = m->next;
}
newNode->next = m->next; // inserting new node
m->next = newNode;
return list;
}
void display(Node*nodex){ // display node values in list
printf("%d ->",nodex->number);
nodex=nodex->next;
if(nodex)
return display(nodex);
else
return 0;
}
Here is the code which shows expected results but with Array of nodes:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct node{
int number;
struct node*next;
};
typedef struct node Node;
Node* insertValue(Node *list, int value);
void display(Node*);
int main()
{
Node *globalList = NULL, *lists[100];
int nbrOfLists, listNo, nbrOfVal, valNo, val, i = 0, k;
CHECKER:
printf("\n\n Enter the number of lists (1 to 100):");
scanf("%d", &nbrOfLists);
if(nbrOfLists <= 0 || nbrOfLists > 100) //handling exceptional cases
{
printf("\n \n Number of Lists should be between 1 to 100"); // since array of node pointers contains 100 elements
goto CHECKER;
}
for(listNo = 0; listNo < nbrOfLists; listNo++)
{
printf("\n\n Enter the number of inputs to the list %d: \n ", listNo + 1);
scanf("%d", &nbrOfVal);
lists[listNo] = NULL;
for(valNo = 0; valNo < nbrOfVal; valNo++) // to enter values in each individual list
{
printf("Enter node value %d:", valNo + 1);
scanf("%d", &val);
// Here we insert the value in both lists
lists[listNo] = insertValue(lists[listNo], val); // original list has to be retained so storing in array lists
globalList = insertValue(globalList, val); // inserting node in combined list. This prevents an extra loop and merges the list elements into one.
}
printf("\n The list %d is: ", listNo + 1);
display(lists[listNo]); // display each list after input
}
printf("\n\n\n THE FINAL LIST IS: ");
display(globalList); //display combined list
printf("\n\n THE LISTS WERE: ");
while(i < nbrOfLists){ //original lists displayed
k = i + 1;
printf("\n\n The list %d is: ", k);
display(lists[i]);
i++;
}
printf("\n\n");
return 0;
}
Node* insertValue(Node *list, int value) // function to insert node in ordered manner into list
{
Node *newNode, *m;
newNode = malloc(sizeof(Node));
newNode->number = value;
if(list == NULL)
{
newNode->next = NULL; // inserting first node
return newNode;
}
if(value < list->number)
{
newNode->next = list; // inserting in end
return newNode;
}
m = list;
while(m->next) // checking for right position in ordered list for new node
{
if(value < m->next->number)
break;
m = m->next;
}
newNode->next = m->next; // inserting new node
m->next = newNode;
return list;
}
void display(Node *nodex){ // display node values in list
printf("%d ->", nodex->number);
nodex = nodex->next;
if(nodex)
return display(nodex);
else
return 0;
}
Please let me know if you do not understood the problem.
After considerable discussion in chat, I ended up using this code which is closely related to the last version in the question:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int number;
struct node *next;
};
typedef struct node Node;
Node *insertValue(Node *list, int value);
void display(Node *);
struct list_of_nodes
{
Node *list;
struct list_of_nodes *next;
};
typedef struct list_of_nodes ListNode;
ListNode *insertNode(ListNode *head, Node *node);
int main(void)
{
ListNode *head = NULL;
Node *globalList = NULL, *lists[100];
int nbrOfLists, listNo, nbrOfVal, valNo, val, i = 0, k;
CHECKER:
printf("\n\n Enter the number of lists (1 to 100):");
scanf("%d", &nbrOfLists);
if (nbrOfLists <= 0 || nbrOfLists > 100)
{
printf("\n \n Number of Lists should be between 1 to 100");
goto CHECKER;
}
for (listNo = 0; listNo < nbrOfLists; listNo++)
{
printf("\n\n Enter the number of inputs to the list %d: \n ", listNo + 1);
scanf("%d", &nbrOfVal);
lists[listNo] = NULL;
for (valNo = 0; valNo < nbrOfVal; valNo++)
{
printf("Enter node value %d:", valNo + 1);
scanf("%d", &val);
lists[listNo] = insertValue(lists[listNo], val);
globalList = insertValue(globalList, val);
}
head = insertNode(head, lists[listNo]);
printf("\n The list %d is: ", listNo + 1);
display(lists[listNo]);
}
printf("\n\n\n THE FINAL LIST IS: ");
display(globalList);
printf("\n\n THE LISTS WERE: ");
while (i < nbrOfLists)
{
k = i + 1;
printf("\n\n The list %d is: ", k);
display(lists[i]);
i++;
}
printf("\n\n");
return 0;
}
ListNode *insertNode(ListNode *head, Node *node)
{
ListNode *newNode, *m;
newNode = malloc(sizeof(ListNode));
newNode->list = node;
newNode->next = NULL;
if (newNode == NULL)
{
fprintf(stderr, "Out of memory in %s\n", __func__);
exit(1);
}
if (head == NULL)
return newNode;
m = head;
while (m->next)
{
m = m->next;
}
newNode->next = m->next;
m->next = newNode;
return head;
}
Node *insertValue(Node *list, int value)
{
Node *newNode, *m;
newNode = malloc(sizeof(Node));
newNode->number = value;
newNode->next = NULL;
if (list == NULL)
return newNode;
if (value < list->number)
{
newNode->next = list;
return newNode;
}
m = list;
while (m->next)
{
if (value < m->next->number)
break;
m = m->next;
}
newNode->next = m->next;
m->next = newNode;
return list;
}
void display(Node *nodex)
{
printf("%d ->", nodex->number);
nodex = nodex->next;
if (nodex)
display(nodex);
}
With a sample data file (ll7.data):
3
6 26 22 83 96 89 69
10 87 33 5 36 85 34 0 25 57 99
5 49 44 27 75 82
I compiled ll7.c above using:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror ll7.c -o ll7
$
And ran it under valgrind which noted that the code leaks like a sieve (because there isn't a free in sight), but otherwise gave it a clean bill of health.
$ valgrind --suppressions=suppressions ./ll7 < ll7.data
==7696== Memcheck, a memory error detector
==7696== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7696== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info
==7696== Command: ./ll7
==7696==
--7696-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option
--7696-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times)
--7696-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times)
Enter the number of lists (1 to 100):
Enter the number of inputs to the list 1:
Enter node value 1:Enter node value 2:Enter node value 3:Enter node value 4:Enter node value 5:Enter node value 6:
The list 1 is: 22 ->26 ->69 ->83 ->89 ->96 ->
Enter the number of inputs to the list 2:
Enter node value 1:Enter node value 2:Enter node value 3:Enter node value 4:Enter node value 5:Enter node value 6:Enter node value 7:Enter node value 8:Enter node value 9:Enter node value 10:
The list 2 is: 0 ->5 ->25 ->33 ->34 ->36 ->57 ->85 ->87 ->99 ->
Enter the number of inputs to the list 3:
Enter node value 1:Enter node value 2:Enter node value 3:Enter node value 4:Enter node value 5:
The list 3 is: 27 ->44 ->49 ->75 ->82 ->
THE FINAL LIST IS: 0 ->5 ->22 ->25 ->26 ->27 ->33 ->34 ->36 ->44 ->49 ->57 ->69 ->75 ->82 ->83 ->85 ->87 ->89 ->96 ->99 ->
THE LISTS WERE:
The list 1 is: 22 ->26 ->69 ->83 ->89 ->96 ->
The list 2 is: 0 ->5 ->25 ->33 ->34 ->36 ->57 ->85 ->87 ->99 ->
The list 3 is: 27 ->44 ->49 ->75 ->82 ->
==7696==
==7696== HEAP SUMMARY:
==7696== in use at exit: 43,752 bytes in 471 blocks
==7696== total heap usage: 551 allocs, 80 frees, 49,880 bytes allocated
==7696==
==7696== LEAK SUMMARY:
==7696== definitely lost: 32 bytes in 2 blocks
==7696== indirectly lost: 688 bytes in 43 blocks
==7696== possibly lost: 0 bytes in 0 blocks
==7696== still reachable: 29,998 bytes in 310 blocks
==7696== suppressed: 13,034 bytes in 116 blocks
==7696== Rerun with --leak-check=full to see details of leaked memory
==7696==
==7696== For counts of detected and suppressed errors, rerun with: -v
==7696== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$
The prompting output isn't really wanted when the input comes from a file, and that's why the numbers aren't seen, too. When you type at the terminal, the terminal driver echoes what you type to the screen. When the data comes from a file, you don't see the characters as they're read.
The suppressions file lists and suppresses a variety of leaks from the Mac OS X 10.10.3 Yosemite runtime system. That's why there's so much memory in use, too; the runtime system uses a lot of memory.
Were it all my code, there'd be a lot that would be done differently. There is a lot of error checking that should be added and refactorization (especially 'extract function') that could/should be done, but those changes were not made to preserve some semblance to the code posted in the question.
Update: Just about 5 minutes before I finished this,
a new version of the code was posted
that seems to do what I recommended, but the new function was not quite right.
Here is one problem:
ListNode* insertNode(ListNode* head, Node* node){
// ... other code here ...
m = head;
while(m->next)
The first time insertNode is called, head is a null pointer
(which it should be, because the list of lists is still empty at that time).
So this sets m to a null pointer, and then attempts to access m->next ... oops!
I see this comment:
// checking for right position in ordered list for new node
Why? What is the "right position"? It appears that the "right position" is
the end of the list of lists; but what is wrong with the beginning?
If you absolutely must have the list of lists come out in the same order in
which the lists were input, then a simpler and more efficient design is to
insert each new list at the start of the list of lists, and when you are
all done, reverse the list of lists.
But you could also just adapt the code from insertValue a little more
carefully. Compare this code of insertValue:
newNode = malloc(sizeof(Node));
newNode->number=value;
if(list == NULL)
to this code of insertNode:
newNode = malloc(sizeof(ListNode));
newNode->list=node;
if(newNode == NULL)
Do you see the difference? In insertValue the if tests the pointer that was passed into the function; in insertNode the if tests the pointer that you have just assigned by newNode = malloc(sizeof(ListNode)).
Of course if(newNode == NULL) will never execute the body of the if
(unless something has already gone badly wrong).
What you need is to test if(head == NULL) so that you can handle
that case correctly.
The rest of this refers to the older version of the question.
Among other things that probably aren't doing what they're supposed to,
this piece of code has multiple serious flaws:
if(valNo==0){ // FOR EVERY FIRST NODE IN INDIVIDUAL LIST, I AM TRYING TO INSERT IT INTO LIST OF FIRST NODES
head->list=malloc(sizeof(Nodex));
head->list=lists[listNo];
head=head->next;
}
OK, first major flaw, you are trying to add the new list to the list of lists
before the list is complete. Until the list is complete, you don't know
what node will end up at the head of that list. The first node you insert
into the list could end up anywhere in the completed list.
That is not what you want to put in your list of lists.
One thing you should change in the code, therefore, is to move those lines
(the ones I copied) out of the inner for loop where they are now;
put them after the end of that loop instead
(and of course delete the if(valNo==0);
these lines should execute unconditionally).
Next thing, you never allocated a Nodex for head to point to,
so head->list will always be an access error.
Next thing, head->list=lists[listNo] overwrites the pointer you just
set with head->list=malloc(sizeof(Nodex)); the memory you allocated
with malloc(sizeof(Nodex)) is immediately leaked. (It was allocated using
the size of the wrong type anyway, since list was supposed to point to a
Node rather than a Nodex, although the Nodex is probably at least
large enough so you could get away with that mistake.)
Finally: head=head->next;??? Since head is the only Nodex* that you
declared at the start of the main() function, if there were ever a
legitimate Nodex in your list, after head=head->next
there would be nothing pointing to that Nodex any more, at least
nothing that you can find in your program. So if you succeeded in putting
anything in the list of lists, that step would essentially throw it away
(it would become a memory leak).
What you probably should do, for your sanity, is write a function
Nodex* insertList(Nodex* list_list, Node* value_list)
that inserts the head pointer of a list, value_list,
into your list of lists, analogously to the way
Node* insertValue(Node * list, int value) inserts a number into a list,
except that you probably don't need to make insertList keep its list
"sorted", so insertList should be considerably simpler than insertValue.
(In fact it will be so simple that you may be tempted to just write
the code of that function inline in your main function. I suggest you
resist the temptation; writing the code inline did not work for you on
the first attempt, and making even very simple functions to do well-defined
things is a good practice.)
Related
The nodes get inserted when I insert them in order on the console
How do I make sure that I take care of all boundary conditions? For example, what if the user enters a position greater than the size of the list? Also, I get a segmentation fault when I try to insert after a node but it works just fine before a node. Here's a picture to help explain my problem better
Also, I get a segmentation fault when I try to insert after a node but it works just fine before a node.
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *next;
};
struct Node *head = NULL;
struct Node *insert(int x,int pos)
{
if(head == NULL)
{
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = head;
head = temp;
return head;
}
else
{
int len = 0;
struct Node *temp = head;
while(temp!=NULL)
{
++len;
temp = temp->next;
}
if(pos == 1)
{
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = head;
head = temp;
return head;
}
else
{
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
temp->next = NULL;
struct Node *temp1 = head;
for(int i = 2; i<pos; i++)
{
temp1 = temp1->next;
}
temp->next = temp1->next;
temp1->next= temp;
}
}
}
void print()
{
struct Node *temp = head;
while(temp!=NULL)
{
printf("%d ",temp->data);
temp = temp->next;
}
printf("\n");
}
int main()
{
int n,i,x,pos;
printf("How many elements?\n");
scanf("%d",&n);
for(i = 0; i<n; i++)
{
printf("enter the value and the position: \n");
scanf("%d %d",&x,&pos);
insert(x,pos);
print();
}
printf("Linked list is: \n");
print();
}
Output 1
How many elements?
3
enter the value and the position:
3 2
List is: 3
enter the value and the position:
4 3
Segmentation fault (core dumped)
Output 2
How many elements?
3
enter the value and the position:
3 2
List is: 3
enter the value and the position:
4 1
List is: 4 3
enter the value and the position:
5 3
List is: 4 3 5
Linked list is:
4 3 5
You are making your insert much harder than it needs to be. You simply need to iterate with 2 conditions (1) pos times or less, and (2) while the next pointer is not NULL. You can greatly simplify the insert by iterating using both the address of and a pointer to the next node. You maintain the current node using the address and your pointer always points to the next node. When you have iterated pos times or your next pointer is NULL you insert your node. See Linus on Understand Pointers
Further, you are not making use of any return, from insert(), so your function prototype should simply be void insert (int x, int pos). While you should avoid using a global pointer to your list, for your purposes of this limited example, that is fine. Know that your list should normally be declared in the scope it is needed and a pointer (or pointer to pointer) to the beginning of the list should be passed as a parameter to make the list available to any function that operates on it rather than it being global.
Putting the pieces together, your insert() function reduces to:
void insert (int x, int pos)
{
struct Node **ppn = &head, /* pointer to pointer to node */
*pn = head, /* pointer to node */
*node = malloc (sizeof *node); /* allocate for new node */
if (!node) { /* validate allocation */
perror ("malloc-node");
exit (EXIT_FAILURE);
}
node->data = x; /* initialize members values */
node->next = NULL;
while (pos-- && pn) { /* iterate pos times && while pn != NULL */
ppn = &pn->next;
pn = pn->next;
}
node->next = pn; /* set next to pointer to node */
*ppn = node; /* set node at address to node */
}
Adding that to the remainder of your example, your complete example would be:
#include<stdio.h>
#include<stdlib.h>
struct Node {
int data;
struct Node *next;
};
struct Node *head = NULL;
void insert (int x, int pos)
{
struct Node **ppn = &head, /* pointer to pointer to node */
*pn = head, /* pointer to node */
*node = malloc (sizeof *node); /* allocate for new node */
if (!node) { /* validate allocation */
perror ("malloc-node");
exit (EXIT_FAILURE);
}
node->data = x; /* initialize members values */
node->next = NULL;
while (pos-- && pn) { /* iterate pos times && while pn != NULL */
ppn = &pn->next;
pn = pn->next;
}
node->next = pn; /* set next to pointer to node */
*ppn = node; /* set node at address to node */
}
/** print all nodes in list */
void print (void)
{
if (!head) {
puts ("list-empty");
return;
}
for (struct Node *n = head; n; n = n->next)
printf (" %d", n->data);
putchar ('\n');
}
/** delete all nodes in list */
void del_list (void)
{
struct Node *n = head;
while (n) {
struct Node *victim = n;
n = n->next;
free (victim);
}
}
int main()
{
int n,i,x,pos;
printf ("How many elements?\n");
if (scanf ("%d",&n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
for (i = 0; i < n; i++)
{
printf ("enter the value and the position: \n");
if(scanf("%d %d",&x, &pos) == 2) {
insert (x, pos);
fputs ("list is: ", stdout);
print();
}
}
puts ("\nLinked list is:");
print();
del_list(); /* free all memory allocated to list */
}
(note: a del_list() function was added to free() the memory associated with your list.)
Example Use/Output
Continuing with your example where you were SegFaulting, you can now complete your inserts, e.g.:
$ ./bin/llatpos
How many elements?
3
enter the value and the position:
3 2
list is: 3
enter the value and the position:
4 3
list is: 3 4
enter the value and the position:
1 0
list is: 1 3 4
Linked list is:
1 3 4
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llatpos
==16615== Memcheck, a memory error detector
==16615== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16615== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16615== Command: ./bin/llatpos
==16615==
How many elements?
3
enter the value and the position:
3 2
list is: 3
enter the value and the position:
4 3
list is: 3 4
enter the value and the position:
1 0
list is: 1 3 4
Linked list is:
1 3 4
==16615==
==16615== HEAP SUMMARY:
==16615== in use at exit: 0 bytes in 0 blocks
==16615== total heap usage: 5 allocs, 5 frees, 2,096 bytes allocated
==16615==
==16615== All heap blocks were freed -- no leaks are possible
==16615==
==16615== For counts of detected and suppressed errors, rerun with: -v
==16615== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
For starters indices in C (for example for arrays) start from 0.
So you should also use the value pf the position in the list that starts from 0.
Logically if the given position is greater than or equal to the number of nodes in the list the new value should be appended to the list.
Nowhere in the function insert you are using the size of the list. So this code snippet
int len = 0;
struct Node *temp = head;
while(temp!=NULL)
{
++len;
temp = temp->next;
}
does not make sense.
If the position is greater than the size of the list then this code snippet
for(int i = 2; i<pos; i++)
{
temp1 = temp1->next;
}
can invoke undefined behavior because inside the loop the variable temp1 can be set to NULL.
Also if the position equal to 2 then the node head is not updated.
The function has a non-void return type but returns nothing.
The function insert can be written much simpler as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
struct Node *head = NULL;
int insert( int data, size_t pos )
{
struct Node *temp = malloc( sizeof( struct Node ) );
int success = temp != NULL;
if ( success )
{
temp->data = data;
struct Node **current = &head;
while ( pos-- != 0 && *current != NULL )
{
current = &( *current )->next;
}
temp->next = *current;
*current = temp;
}
return success;
}
void print()
{
for ( const struct Node *current = head; current != NULL; current = current->next )
{
printf( "%d -> ", current->data );
}
puts( "NULL" );
}
int main(void)
{
/*
insert( 3, 2 );
printf( "Linked list is: " );
print();
insert( 4, 3 );
printf( "Linked list is: " );
print();
*/
insert( 3, 3 );
printf( "Linked list is: " );
print();
insert( 1, 0 );
printf( "Linked list is: " );
print();
insert( 2, 1 );
printf( "Linked list is: " );
print();
insert( 4, 3 );
printf( "Linked list is: " );
print();
insert( 5, 10 );
printf( "Linked list is: " );
print();
return 0;
}
The program output is
Linked list is: 3 -> NULL
Linked list is: 1 -> 3 -> NULL
Linked list is: 1 -> 2 -> 3 -> NULL
Linked list is: 1 -> 2 -> 3 -> 4 -> NULL
Linked list is: 1 -> 2 -> 3 -> 4 -> 5 -> NULL
I'm pretty new to C programming.
I have an assignment in which we are supposed to create a doubly linked list of integers, and write some functions to manipulate them. We are being asked to prevent memory leaks, but I'm not really sure how to do that.
I have to malloc a bunch of times in order to create and store nodes when making the linked list, and I'm pretty sure it's not a good idea to malloc enough space for a node and then free the pointer to it in the same place.
Therefore, my best guess is that I should free all nodes in the main function, when I will have printed their contents to the screen and they are no longer needed. I tried to implement a kill function that takes as input a reference head to the first node in the list, and which iterates over the nodes, freeing them as they go.
I went as far as installing valgrind to try and see if there were any memory leaks, and it looks like there are still some. I have no idea where they are coming from or how to fix the issue.
Here is the whole code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node{
int data;
struct Node *next;
struct Node *previous;
}Node;
void print_dll(Node *head){
Node *curr = head;
while(curr != NULL){
printf("%d\t", curr->data);
curr = curr->next;
}
puts(" ");
}
Node* create_dll_from_array(int array [], int arrSize){
//this is a function that creates a doubly linked list
//with the contents of the array
Node* current = (Node *) malloc (sizeof(Node * ));
current->data = array[arrSize-1];
current -> next = NULL;
for(int i = 2; i <= arrSize; i++){
//create a new node
Node * temp = (Node*)malloc(sizeof(Node*));
//I would like the dll to be in the same order as the array, I guess it isn't strictly necessary
temp ->data = array[arrSize-i];
temp -> next = current;
current-> previous = temp;
//now make temp the current
current = temp;
}
current-> previous = NULL;
return current;
}
void insert_after(Node* head, int valueToInsertAfter, int valueToInsert ){
if(head != NULL){
Node * current = head;
while(current-> data != valueToInsertAfter){
//this while loop brings 'current' to the end of the list if
//the searched value is not there
if(current-> next != NULL){
current = current->next;
}else{
break;
}
}
//after exiting this loop, the current pointer is pointing
//either to the last element of the dll or to the element
//we need to insert after
Node *new = (Node *) malloc (sizeof(Node *));
new->data = valueToInsert;
new->next = current->next;
new->previous = current;
if(current->next != NULL){
(current->next)->previous = new;
}
current->next = new;
}
}
void delete_element(Node* head, int valueToBeDeleted){
//work in progress
}
void kill(Node *head){
//this is my attempt at freeing all the nodes in the doubly linked list
Node *current;
while(head!=NULL){
current = head;
head = head->next;
free(head);
}
}
int main(){
int array [5] = {11, 2, 7, 22, 4};
Node *head;
/*Question 1*/
//creates a doubly linked list from the array below
head = create_dll_from_array(array, 5); ///size of the array is 5
/* Question 2 */
// print_dll(head);
/*Question 3*/
// to insert 13 after the first appearance of 7
insert_after(head, 7, 13);
print_dll(head);
//to insert 29 after first appearance of 21
insert_after(head, 21, 29);
print_dll(head);
/*Question 6*/
//create a function to free the whole list
kill(head);
return 0;
}
The main function here is given to us by the prof, we have to build out function around it.
I don't know why this is still appearing to lead to memory leaks, and if I', being honest, I don't really know where else they could occur. As far as I know, I need to keep all the memory until almost the last minute.
Please help, I'm pretty lost here.
Thank you!
There are two problems:
Need to change all malloc (sizeof(Node*)) to malloc (sizeof(Node))
Need to change free(header) to free(current) in the kill function.
The modified code is as follows
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
struct Node *previous;
} Node;
void print_dll(Node *head)
{
Node *curr = head;
while(curr != NULL) {
printf("%d\t", curr->data);
curr = curr->next;
}
puts(" ");
}
Node *create_dll_from_array(int array [], int arrSize)
{
//this is a function that creates a doubly linked list
//with the contents of the array
Node *current = (Node *) malloc (sizeof(Node));
current->data = array[arrSize - 1];
current -> next = NULL;
for(int i = 2; i <= arrSize; i++) {
//create a new node
Node *temp = (Node *)malloc(sizeof(Node));
//I would like the dll to be in the same order as the array, I guess it isn't strictly necessary
temp ->data = array[arrSize - i];
temp -> next = current;
current-> previous = temp;
//now make temp the current
current = temp;
}
current-> previous = NULL;
return current;
}
void insert_after(Node *head, int valueToInsertAfter, int valueToInsert )
{
if(head != NULL) {
Node *current = head;
while(current-> data != valueToInsertAfter) {
//this while loop brings 'current' to the end of the list if
//the searched value is not there
if(current-> next != NULL) {
current = current->next;
} else {
break;
}
}
//after exiting this loop, the current pointer is pointing
//either to the last element of the dll or to the element
//we need to insert after
Node *new = (Node *) malloc (sizeof(Node));
new->data = valueToInsert;
new->next = current->next;
new->previous = current;
if(current->next != NULL) {
(current->next)->previous = new;
}
current->next = new;
}
}
void delete_element(Node *head, int valueToBeDeleted)
{
//work in progress
}
void kill(Node *head)
{
//this is my attempt at freeing all the nodes in the doubly linked list
Node *current;
while(head != NULL) {
current = head;
head = head->next;
free(current);
}
}
int main()
{
int array [5] = {11, 2, 7, 22, 4};
Node *head;
/*Question 1*/
//creates a doubly linked list from the array below
head = create_dll_from_array(array, 5); ///size of the array is 5
/* Question 2 */
// print_dll(head);
/*Question 3*/
// to insert 13 after the first appearance of 7
insert_after(head, 7, 13);
print_dll(head);
//to insert 29 after first appearance of 21
insert_after(head, 21, 29);
print_dll(head);
/*Question 6*/
//create a function to free the whole list
kill(head);
return 0;
}
Change sizeof(Node * ) to sizeof(Node) due to malloc reserving you memory for which the pointer points to and it needs the correct amount of needed memory (which is not a pointer but the object itself).
i <= arrSize might be an overflow, since the size usually is given as amount of memory cells. So you might consider using i < arrSize
The first while loop in the insert_after might point to invalid memory after the array
Node *new = is ugly syntax, since new is a keyword in C++. Please never do that, since that will break any code, which is being used in C++.
You dont need a temporary element in kill(). You can instead going until head points to NULL.
delete_element needs the same array checks as insert_after
Probably you need to debug the whole thing pasting one function after the other to get it properly working. No guarantee for correctness, since that was abit hard to read without comments and all.
The best way to find memory leaks is using valgrind (or a similar tool) in run time.
Valgrind will identify any memory leak or violation you ran through.
to run valgrind in linux environment, all you need to do is:
# valgrind --leak-check=full ./my_program
In you case it gave mainy theses errors:
==28583== Invalid read of size 8
==28583== at 0x400871: kill (aaa.c:77)
==28583== by 0x40092D: main (aaa.c:103)
==28583== Address 0x5204188 is 0 bytes after a block of size 8 alloc'd
==28583== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28583== by 0x40073A: create_dll_from_array (aaa.c:29)
==28583== by 0x4008D9: main (aaa.c:87)
this error means the allocation size was too small. as mentioned in another answers it is because you allocate enough memory for a pointer and not for the struct.
I am trying to implement linked list in C and I have two different functions that are supposed to insert elements in the beginning and at nth position. My program crashes when it goes to the part where it starts executing the function to insert at nth position. Can someone please point out my mistake. Also the compiler tends to skip the last scanf statement (marked in the comments).
/****************************************************************
*Date: 12/30/2016
*This program adds an element to the beginning and nth position
*of a linked list and then displays the elements in the list
*****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct node
{
int data;//Refers to the data part of the linked list
struct node* next;//Refers to the pointer which points to the next element
};
/*************************************************************************************
Description : This function is used to print the elements in the linked list
Input : Pointer to the beginning of the linked list
Output : N/A
*************************************************************************************/
void PrintElements(struct node *start)
{
if(start==NULL)//If the list is empty
printf("List is empty");
else
{
while(start!=NULL)
{
printf("%d ",start->data);
start=start->next;
}
}
}
/*************************************************************************************
Description : This function is used to insert elements in the beginning of the
linked list
Input : Element to be inserted
Output : N/A
*************************************************************************************/
struct node* InsertElementInTheBeginning(struct node *start, int x)
{
struct node *new_node=(struct node*)malloc(sizeof(struct node));
if(new_node==NULL)
{
printf("Memory allocation failed");
return start;
}
new_node->data=x;
new_node->next=start;
start=new_node;
return new_node;
}
/*************************************************************************************
Description : This function is used to insert elements in the nth position of the
linked list
Input : Element and position to be inserted, pointer to beginning of linked
list
Output : N/A
*************************************************************************************/
struct node* InsertElementAtN(struct node *start,int x, int n)//Here the starting position for the linked list is assumed to be 1
{
int i;
struct node* new_node=(struct node*)malloc(sizeof(struct node));
if(new_node==NULL)
{
printf("Memory allocation failed");
return start;
}
new_node->data=x;
new_node->next=NULL;
if(n==1)
{
new_node->next=start;
start=new_node;
return start;
}
struct node *ptr;
ptr=start;
for(i=0;i<n-2;i++)
{
ptr=ptr->next;
}
new_node->next=ptr->next;
ptr->next=new_node;
return start;
}
int main()
{
int x, n;
struct node *HEAD;
struct node *ptr;
HEAD=NULL; //Assigning HEAD to null when there are no elements in the list
ptr=NULL;
printf("\n\rEnter numbers to be inserted into the list\n Press q to quit\n");
while(scanf("%d",&x)==1)
{
HEAD=InsertElementInTheBeginning(HEAD,x);
PrintElements(HEAD);
printf("\n\rEnter numbers to be inserted into the list\n Press q to quit\n");
}
printf("\n\rEnter the number and position to be inserted");
scanf("%d %d",&x,&n);//The compiler always skips this scanf no clue why
HEAD=InsertElementAtN(HEAD, x, n);
PrintElements(HEAD);
//Freeing dynamic memory
while(HEAD!=NULL)
{
ptr=HEAD;
HEAD=ptr->next;
free(ptr);
}
return 0;
}
I've always found something like this to be easier for me to understand (I'm assuming your positions must be 1 or more based on your code, unlike the usual C convention of 0 or more):
struct node *insertValueAt(struct node *head, int value, int position) {
struct node *current;
if (head == NULL || position == 1)
return insertBefore(head, value);
for (current = head; position > 1 && current->next != NULL; position--)
current = current->next;
current->next = insertBefore(current->next, value);
return head;
}
Note that I used the name insertBefore, but your InsertElementAtTheBeginning does the same thing. The key to inserting a node N between to existing nodes A and B is to make A->next point to N that is returned from InsertElementAtTheBeginning(B, value).
Another thing to note is the unconditional insertion before a NULL node (i.e. at the beginning of an empty list or at the end of the list), regardless of the value of position because you can't insert an item at position 10 if you only have fewer than 4 items.
Add a getchar() after the first while loop in the main(). For explanation please check C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf.
you should check that ptr->next is not NULL.
for(i=0;i<n-2;i++)
{
if (ptr->next == NULL) return NULL;
ptr=ptr->next;
}
I am trying to create an (ordered) linked list of (ordered) linked lists. The list-of-list links are carried by the first nodes of its member lists. I am trying to achieve this via the following code, but my program crashes right after I try to insert the second node into the list of lists.
Here's a schematic of the data structure I am trying to construct:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct node{
int number;
struct node*next;
struct node*lsnext;
};
typedef struct node Node;
Node* insertValue(Node * list, int value);
void display(Node*);
Node* insertArr(Node * list, int value);
int main()
{
Node *globalList = NULL, *lists,*start,*save;
int nbrOfLists, listNo, nbrOfVal, valNo, val;
printf("\n Enter the number of lists:");
scanf("%d", &nbrOfLists);
if(nbrOfLists < 0)
return -1;
for(listNo = 0; listNo < nbrOfLists; listNo++)
{
printf("\n\n Enter the number of inputs to the list %d: \n ",listNo+1);
scanf("%d", &nbrOfVal);
lists = NULL;
for(valNo = 0; valNo < nbrOfVal; valNo++)
{
printf("Enter node value %d:", valNo+1);
scanf("%d", &val);
// Here we insert the value in both lists
lists= insertValue(lists, val);
globalList = insertValue(globalList, val);
}
start=lists;
if(listNo==0){
save=start;
}
start=start->lsnext;
printf("\n The list %d is: ",listNo+1);
display(lists);
}
printf("\n\n The final list is: ");
display(globalList);
printf("The first list is");
display(save);
printf("The second list is");
display(save->lsnext); // CRASHES HERE
return 0;
}
Node* insertValue(Node * list, int value)
{
Node *newNode, *m;
newNode = malloc(sizeof(Node));
newNode->number=value;
if(list == NULL)
{
newNode->next=NULL;
return newNode;
}
if(value < list->number)
{
newNode->next = list;
return newNode;
}
m = list;
while(m->next)
{
if(value < m->next->number)
break;
m = m->next;
}
newNode->next = m->next;
m->next = newNode;
return list;
}
void display(Node*nodex){
while(nodex)
{
printf("%d ->",nodex->number);
nodex=nodex->next;
}
}
What is causing my error?
Your insertArr() function is wrong. Even its signature is wrong. Instead of linking together the first nodes of existing lists, it creates a perpendicular list of separate nodes. Note in particular that it accepts a value where it needs instead to accept the head node of a list.
Moreover, even the circumstances under which you call that function are wrong. You seem to try to link the initial head nodes of each list, but the head node may change as you add values. You must wait until you have a full list before you know what its final head node is; only then can you link that list into your list of lists.
Edit: I had first asserted that your problem was failure to initialize the lsnext members of your nodes. That would be correct if your insertArr() function were actually accepting nodes created by insertValue() as its second argument, as it should, but it is not correct for the code presented. The actual problem is a consequence of the issue described in my first paragraph, that insertArr() creates a separate list of separate nodes. In particular, those separate nodes do not have their next pointers initialized.
I've been smashing my head here to see if I could find a solution but after few infinite loops, here's the code I'd like to be reviewed:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TREE_STRING 100
typedef struct Node {
char val;
struct Node *next;
} node;
node *create_list(char *list_string) {
node *momentary=NULL, *new=NULL, *head;
int i;
for(i=0; i<strlen(list_string); i++) {
new = (node *)malloc(sizeof(node));
new->val = list_string[i];
new->next = NULL;
if (!momentary) head = new;
else momentary->next = new;
momentary = new;
}
return head;
}
int print_list(node *head) {
node *momentary;
if(!head) return -1;
for(momentary=head; momentary!=NULL; momentary=momentary->next)
printf("%c ", momentary->val);
printf("\n");
return 0;
}
node *find_biggest(node *head) {
node *momentary=NULL, *biggest=head;
if (head==NULL) return NULL;
for (momentary=head; momentary!=NULL; momentary=momentary->next) {
if (momentary->val > biggest->val) biggest = momentary;
}
return biggest;
}
void insert_after_biggest(node **head, node **biggest, char val) {
node *p = *head, *temp=NULL;
*head = p->next;
if(*head!=NULL){
if(p->val==(*biggest)->val){
temp=p;
p->next=temp;
p->val=temp->val;
p->next=NULL;
*biggest=p;
p->next=(*biggest);
p->val=(*biggest)->val;
//*biggest=p;
p->next=NULL;
//temp=p;
p->next=temp;
p->val=temp->val;
}
else if(p->val<(*biggest)->val){
*head = p->next;
}
}
}
int main () {
node *head=NULL, *biggest=NULL;
int menu_choice;
char c, val, list_string[MAX_TREE_STRING];
setbuf(stdout, NULL);
do {
menu_choice = 0;
printf("\n1 Create list \n2 Print");
printf("\n3 Insert after biggest");
printf("\n4 exit\n");
scanf("%d", &menu_choice);
switch (menu_choice) {
case 1:
if (head) {
printf("List exist.\n");
break;
}
printf("Enter list as digits without spaces: ");
scanf(" %s", list_string);
head = create_list(list_string);
break;
case 2:
print_list(head);
break;
case 3:
scanf(" %c", &val);
insert_after_biggest(&head, &biggest, val);
break;
case 4:
break;
default:
while((c=getchar())!='\n' && c!=EOF);
}
} while(menu_choice!=4);
return 0;
}
Now the task here is:
Write a function "insert_after_biggest" so that the new elements are
put behind the element with the highest value and complexity of the
function must be O (1). In other words, the function "find_biggest"
that has complexity of O (n) can be called only if the "biggest" has
not yet been defined. If the list has no elements , it still needs to
be first.
Here's a console example to have clearer picture:
1|<-Insert into linked list option|
Enter list as digits without spaces: 683 |<-Prompt and entered value|
3 |<-Option(the function)|
2 |<-Number to be inserted|
2 |<-Print option|
6 8 2 3|<-Output|
3 |<-Option|
8 |<-Number to be inserted|
2 |<-Print option|
8 |<-Output|
I've been typing this code myself and I have no idea anymore how to look at this.
I would humbly ask if someone can help me to solve this, the code compiles but executing the option 3 in the console only makes it run in infinite loop, resulting in crashing the console.
The specific: how to solve it (step by step) and how it should look like(the done code, possibly included here?).
Thank you.
If you can assume that
1) You don't need to remove elements
You merely need to keep an extra pointer that points to the node with the largest value at all times. It's nice that you are allowed to scan the list for the largest if you've never called
insert_after_biggest, but that's not even necessary. Call that node max, and the pointer to max p_max.
For each insertion
a) The value you're about to insert is larger than the value held by max, in which case you insert the new value, and change p_max = p_new.
n_new->next = p_max;
p_max = p_new;
b) The value you're about to insert is larger than the value held buy max, in which case simply insert and leave p_max unchanged.
For insert_after_max
you explicitly do
p_new->next = p_max->next;
p_max->next = p_new;
Or if the new value is larger then do as described above.
Since you don't have to scan the list to insert, the complexity of insertion is O(1)