Linked List of Ordered Linked Lists - c

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 view 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;
}
}

The problem is you never assign the lsnext node pointer. You will want to make sure you set this pointer equal to "lists" prior to resetting your start pointer. And you shouldn't need the following line of code:
start=start->lsnext;
That fixes your crashing issue that you mention, however the source code has other errors. Running your application through GDB will be invaluable in ensuring your pointer values are what you think they should be at each step, as well as a source code formatter to ensure readability, making it easier to tell which code belongs inside which blocks.

Related

Printing extra 0 and not removing front nodes in linked list implementation in C

My code has two separate (although likely connected) problems, one of which being that when I print out the linked list (regardless of if I push nodes to the front or to the back), it prints an additional 0 at the start of the linked list. I saw a similar post about this, but the implementation of the push method was different, as it didn't take head as an argument, so I've defined head in the main() method with:
struct node *head = NULL;
and my linked list instantiation looks like
struct node *temp, *ptr;
temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL) {
exit(0);
}
temp->next=NULL;
if(head==NULL) {
head=temp;
} else {
ptr=head;
while(ptr->next!=NULL) {
ptr=ptr->next;
}
ptr->next=temp;
ptr->data=NULL;
}
The issue I'm having is that I'm not sure whether or not the issue is in the print method, my push front method or my linked list instantiation.
The relevant code is:
case PUSH_FRONT: ; // push onto front of list
struct node *temp1;
temp1=(struct node*)malloc(sizeof(struct node));
if(temp1==NULL) {
break;
}
temp1->next=NULL;
temp1->data=val;
if(head==NULL) {
head=temp1;
} else {
temp1->next=head;
head=temp1;
}
break;
case PRINT_LIST: ; // print list
printf("Elements: ");
struct node *ptr4;
ptr4=(struct node*)malloc(sizeof(struct node));
if(head==NULL) {
break;
} else {
ptr4=head;
while(ptr4) {
printf("%d",ptr4->data);
printf(" ");
ptr4=ptr4->next;
}
printf("\n");
free(ptr4);
}
break;
My other issue (although I'm still convinced that this issue lies elsewhere) is that my pop front method does absolutely nothing, which I'm guessing has to do with the initial instantiation of the linked list. The relevant code is:
case POP_FRONT: ; // remove from front of list
// If list is empty, do nothing.
struct node *ptr2;
ptr2=(struct node *)malloc(sizeof(struct node));
if(ptr2==NULL) {
break;
}
if(head==NULL) {
break;
} else if(head->next==NULL) {
ptr2=head;
head=head->next;
free(ptr2);
}
break;
You should post code someone could download and compile. And when
needed a data file or a description of the problem. Code fragments are
not good.
I believe that the data component of your list is just an int by looking at the code at the label PRINT_LIST
here goes what I think
a list is a collection of nodes. In java a list is even called a collection. In C++ lists are called containers. When you write code for a linked list as if it is a node you will have more work and less results.
as a direct consequence of using a node as a list you have 3 pointers here just to manage the list, in the instantiation code: head, temp and ptr, It is too much. Imagine if there where 3 lists...
a list with pointers only to one direction is harder to program and much less useful than one with pointers to next and previous nodes. If it is your decision may be you should reconsider. If the space of the additional pointer is not a concern, it is hard to justify not to use 2 pointers. Imagine a list for a library, a path,, a playlist, all the classic examples: it is very handful to be able to navigate in both directions.
the use of a switch() is uncommon. Why not just use functions?
back to your code
struct node *temp, *ptr;
temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL) {
exit(0);
}
temp->next=NULL;
if(head==NULL) {
head=temp;
} else {
ptr=head;
while(ptr->next!=NULL) {
ptr=ptr->next;
}
ptr->next=temp;
ptr->data=NULL;
}
here you write ptr->data = NULL; and we may think that data is a pointer, but in the list label you wrote
ptr4=head;
while(ptr4) {
printf("%d",ptr4->data);
printf(" ");
ptr4=ptr4->next;
}
printf("\n");
free(ptr4);
and data is just an int as you are using %d in the printf(). Well, the NULL in instantiation is, well, a zero.
And that NULL is the 0 you are complaining about.
This code seems to be much more complex and hard to read than it may need to be.
Let me show an alternative
about the declaration
You may write the node struct like
typedef struct _nd
{
int data;
struct _nd* next;
} node;
So you can use node in the declaration and not have to repeat struct at all times. Also it is useful to have a convention for typedef, like using first letter uppercase to help in readability
As I said before a list is a collection of nodes, it is NOT just a node --- with a pointer inside --- and each node has a payload, some data, usually a pointer. As an example consider
an alternate example of list structs
typedef struct _nda
{
int data;
struct _nda* next;
} Node;
struct _the_list
{
char* name;
unsigned size;
unsigned limit;
Node* head;
Node* tail;
};
typedef struct _the_list List;
Here the list is, well, List. And each list has head, tail, size, limit and even a name. I kept data as an int but is is not good: you really want it as a pointer, maybe (void*).
Why? Because in this way you can reuse the code everywhere with no change.
How to use a List like this?
Using functions like these possible prototypes
List* _create(const char*);
int _define_max(List* l, const unsigned);
List* _delete(List*);
int _empty(List*);
int _get_max(List*);
List* _insert_begin(int, List*);
List* _insert_end(int, List*);
int _insert_your_way(List*, int(*)(int,int));
int _print(List*);
int _print_your_way(List*, int(*)(int,int));
List* _remove(int, List*);
int _size(List*);
I will post a running example below just to have something you can test or ask about case you need. But it is the usual. Only these two functions are less usual, but more useful:
int _insert_your_way(List*, int(*F)(int,int));
int _print_your_way(List*, int(*F)(int,int));
Here you can pass a function like in the qsort() function, and the node is inserted at the position, using the function F() to compare the nodes. The effect is that you can have the nodes inserted (or listed) in any order, with no change in the list code, just by providing different functions to the print or insert function. C does that, C++ does that, everybody does that, so we can too :)
code for instantiating such a list
List* _create(const char* name)
{
List* one = (List*)malloc(sizeof(List));
one->name = (char*)malloc(1 + strlen(name));
strcpy(one->name, name);
one->size = 0;
one->limit = 0;
one->head = NULL;
one->tail = NULL;
return one;
}; // criar()
You may find that writing this way makes easier to maintain or read the code. And the List as a container is much more expressive: metadata about the list in included in the list. No need for ptr, head, temp, size or other controls hanging loose in main()
To create a list you can just write, like in the example
List* first = _create("The First List");
inserting nodes at the beggining
List* _insert_begin(int value, List* l)
{
if (l == NULL) return l; //no list
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and stuff data in
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value; // data comes in
nd->next = l->head; // depois vem o que estava na frente
l->head = nd; // nd fim
l->size = l->size + 1;
// if it is the first node
if (l->size == 1)l->tail = nd;
return l;
};
As I told you this is just a toy, an example. In practice you will use a void* in order to have a generic code. I am using an int as data here, as you did. To insert a few nodes in the list created above you just write
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
And you can have even an array of lists and all goes well. No external variables to look after. And each list has size updated, head, tail...
printing nodes
print is also easy and can be more expressive, since we have metadata with limits, size, head, tail and even the name for each list.
sample program
int main(void)
{
List* first = _create("The First List");
_print(first);
_define_max(first,300);
_print(first);
// insert 5,4,3,2,1 at the beggining
for(int i = 5; i>0; i-=1 ) _insert_begin(i, first);
// list again
_print(first);
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
// list again
_print(first);
printf("empty(): %d size()= %d\n",
_empty(first),
_size(first) );
first = _delete(first);
_print(first);
return 0;
}
This code just
create a list and prints the nodes
set the optional limit to 300 nodes
list the nodes
insert 5,4,3,2,1 at the beginning
list the nodes
insert 6,7,8,9,10 at the tail
list the nodes
call a few functions on the list
deletes all data
output
List 'The First List' with 0 elements [MAX not defined yet]
List 'The First List' with 0 of 300 MAX elements
List 'The First List' with 5 of 300 MAX elements
First: 1
Last: 5
Elements
1
2
3
4
5
End of list
List 'The First List' with 10 of 300 MAX elements
First: 1
Last: 10
Elements
1
2
3
4
5
6
7
8
9
10
End of list
empty(): 0 size()= 10
Deleting 'The First List'
List not created!
the code (with almost no testing)
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct _nda
{
int data;
struct _nda* next;
} Node;
struct _the_list
{
char* name;
unsigned size;
unsigned limit;
Node* head;
Node* tail;
};
typedef struct _the_list List;
List* _create(const char*);
int _define_max(List* l, const unsigned);
List* _delete(List*);
int _empty(List*);
int _get_max(List*);
List* _insert_begin(int, List*);
List* _insert_end(int, List*);
int _insert_your_way(List*, int(*)(void*));
int _print(List*);
int _print_your_way(List*, int(*)(void*));
List* _remove(int, List*);
int _size(List*);
int main(void)
{
List* first = _create("The First List");
_print(first);
_define_max(first,300);
_print(first);
// insert 5,4,3,2,1 at the beggining
for(int i = 5; i>0; i-=1 ) _insert_begin(i, first);
// list again
_print(first);
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
// list again
_print(first);
printf("empty(): %d size()= %d\n",
_empty(first),
_size(first) );
first = _delete(first);
_print(first);
return 0;
}
List* _create(const char* name)
{
List* one = (List*)malloc(sizeof(List));
one->name = (char*)malloc(1 + strlen(name));
strcpy(one->name, name);
one->size = 0;
one->limit = 0;
one->head = NULL;
one->tail = NULL;
return one;
}; // criar()
int _define_max(List* l, const unsigned m)
{
if (l == NULL) return -1;
// new value can not be less than present size
if (l->size > m) return -2;
l->limit = m;
return m;
};
List* _delete(List* l)
{
if (l == NULL) return NULL;
printf("Deleting '%s'\n", l->name);
free(l->name);
if (l->size == 0)
{
free(l);
return NULL; // empty
}; // if()
Node* node = l->head;
do
{
Node* p = node->next;
free(node);
node = p;
} while (node != NULL);
return NULL;
};
int _empty(List* L)
{
if (L == NULL) return -1;
return (L->size == 0);
};
int _get_max(List* L)
{
if (L == NULL) return -1;
return (int)L->limit;
};
List* _insert_begin(int value, List* l)
{
if (l == NULL) return l; //no list
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and stuff data in
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value; // data comes in
nd->next = l->head; // depois vem o que estava na frente
l->head = nd; // nd fim
l->size = l->size + 1;
// if it is the first node
if (l->size == 1)l->tail = nd;
return l;
};
List* _insert_end(int value, List* l)
{
if (l == NULL) return l;
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and insert at the end
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value;
// first one?
if (l->size == 0)
{
l->head = nd;
nd->next = NULL;
}
else
{
nd->next = NULL; // no one after this
(l->tail)->next = nd;
}; // if()
l->tail = nd; // nd is tail now
l->size = l->size + 1;
// of this is the first node
if (l->size == 1)l->head = nd;
return l;
};
int _insert_your_way(List* L, int(*F)(void*))
{
return 0;
};
int _print(List* l)
{
if (l == NULL)
{
printf("List not created!\n");
return -1;
};
if (l->limit > 0)
{
printf("\nList '%s' with %d of %d MAX elements\n",
l->name,
l->size,
l->limit
);
}
else
{
printf("\nList '%s' with %d elements [MAX not defined yet]\n",
l->name,
l->size
);
}
if (l->size < 1) return 0;
// assume data as just an int
Node* p = l->head;
printf("\n First:%10d\n", l->head->data);
printf(" Last:%10d\n", l->tail->data);
printf("\nElements\n\n");
do
{
printf("%10d \n", p->data);
p = p->next;
} while (p != NULL);
printf("\nEnd of list\n\n");
return 0;
}; // _print()
int _print_your_way(List* L, int(*F)(void*))
{
return 0;
};
List* _remove(int value, List* L)
{
return NULL;
};
int _size(List* L)
{
if (L == NULL) return -1;
return (int)L->size;
};
It was extracted for a larger example, for WIndows. Compiled just under gcc 9.3 on Ubuntu on Windows WSL

Merge double linked list in C language

Merge the two linked list in C language.
I tried to merge the two sorted double linked list. When I ran my code with different inputs, sometime the code just crushed with EXC_BAD_ACCESS error. I can't figure out why, the code seemed perfect for me and I use the similar way to merge two single linked list, it worked.
Can someone explain? Thanks!
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
struct Node* prior;
struct Node* next;
int value;
}Node,*list;
list create_list()
{
list head = (list)malloc(sizeof(Node));
if(!head) exit(-1);
list tail;
tail=head;
printf("Please enter the length of double linked list:\n");
int len;
scanf("%d",&len);
for(int i=0;i<len;i++)
{
list new = (list)malloc(sizeof(Node));
printf("Please enter the value of node:\n");
int val;
scanf("%d",&val);
new->value=val;
tail->next = new;
new->prior=tail;
tail=new;
}
return head;
}
list merge_list(list a, list b)
{
if(a==NULL||b==NULL) exit(-1);
list p=(list)malloc(sizeof(Node));
list l=p;
while(a&&b)
{
if(a->value<=b->value)
{
p->next = a;
a->prior=p;
p=a;
a=a->next;
}
else
{
p->next = b;
b->prior=p;
p=b;
b=b->next;
}
}
if(a!=NULL)
{
p->next=a;
a->prior=p;
}
if(b!=NULL)
{
p->next=b;
b->prior=p;
}
return l;
}
int main() {
list l = create_list();
l=l->next;
list m = create_list();
m=m->next;
list n =merge_list(l,m);
n=n->next;
while(n)
{
printf("%d\n",n->value);
n=n->next;
}
return 0;
}
The problem is that in create_list you do not initialize new->next with NULL.
From this error it makes no sense in merge_list to compare pointers with NULL.
The most important bug (i.e. no initialization of new->next) has already been addressed by the answer from #alinsoar.
However, there are other bugs in your code that a) cause memory leaks and b) cause the linked list to be incorrect.
In main you have:
list l = create_list();
l=l->next; // Why ......
Why do you "throw away" the first element like that? That's a memory leak! And further it means that l->prio is not NULL as it should be!
I know it's because your create_list inserted a phony node in the start. But don't just fix it by throwing the node away. Fix the function instead.
Do something like this:
list create_list()
{
list head = NULL; // Do not use malloc here - just assign NULL
list tail = NULL;
printf("Please enter the length of double linked list:\n");
int len;
scanf("%d",&len);
for(int i=0;i<len;i++)
{
list new = malloc(sizeof(Node)); // do not cast malloc
new->next = NULL; // set the next pointer
printf("Please enter the value of node:\n");
int val;
scanf("%d",&val);
new->value=val;
// Add the node to the end
new->prior=tail;
if (tail)
{
tail->next = new;
}
else
{
// First element so update head
head = new;
}
tail=new;
}
return head;
}
With this code you don't get an extra element in the start and you can delete the code l=l->next; in main. Similar changes applies to merge_list but I'll leave that to you as an exercise.
In the end your mainshould only be:
int main() {
list l = create_list();
list m = create_list();
list n =merge_list(l,m);
while(n) {
printf("%d\n",n->value);
n=n->next;
}
return 0;
}

Link Linked Lists in C

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.

linked linked insertion function

Hello I am trying to create n number of lists. Each list is ordered linked list with a new instance. However, I also need a combined ordered linked list. Following is the code for the same. When it comes to each independent list I do not have any problems. However, when I am trying to insert every node into a globally declared linked list nodes, I am getting error(The input crashes with iteration of one node value.) Please have a look at the function and call highlighted to make things clear where I am exactly getting the error. Please make a note of global declarations. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
struct node{
int number;
struct node*next;
};
typedef struct node NODE;
NODE*createlist(int),*rel_strt,*new_entry[100];
NODE *start1=NULL,*rear1,*m1,*temp11;
NODE *insert_in_end(NODE*node1);
int i,num,n2,j,v,u;
int main() {
v=0;u=0;
printf("\n Enter the number of lists:");
scanf("%d",&n2);
for(j=0;j<n2;j++) {
printf("\n\n Enter the number of inputs to the list %d: \n ",j+1);
scanf("%d",&num);
new_entry[v]=createlist(num);
display(new_entry[v]);
v++;
}
printf("\nThe final List is:");
display(start1);
return 0;
}
NODE*insert_in_end(NODE *node11) { //problem in this function
int inf1=node11->number;
if(start1==NULL) {
start1=rear1=node11;
} else {
m1=start1;
if(m1->number>inf1) {
node11->next=m1;
start1=node11;
} else {
while(m1->next) {
if(m1->next->number < inf1)
m1=m1->next;
else
break;
}
temp11=m1->next;
m1->next=node11;
node11->next=temp11;
}
}
return start1;
}
void display(NODE*nodex) {
while(nodex!=NULL) {
printf("%d ->",nodex->number);
nodex=nodex->next;
}
}
NODE *createlist(int n1) {
NODE *node1,*start,*rear,*m,*temp1;
start=NULL;
for(i=0;i<n1;i++) {
node1=(NODE*) malloc(sizeof(NODE));
int inf;
printf("Enter node value %d:",i+1);
scanf("%d",&inf);
node1->number=inf;
node1->next=NULL;
insert_in_end(node1); // error during second fuction call check function definition
if(start==NULL) {
start=rear=node1;
} else {
m=start;
if(m->number>inf) {
node1->next=m;
start=node1;
} else {
while(m->next) {
if(m->next->number < inf)
m=m->next;
else
break;
}
temp1=m->next;
m->next=node1;
node1->next=temp1;
}
}
}
return start;
}
I suggest you define a function insertValue that would make it much more convenient for you. It will also make your code much more readable.
The function is below and you should see that it is very close to what you have.
// Returns the new start of the list after inserting value in increasing order
Node* insertValue(Node * list, int value)
{
Node *newNode, *m;
newNode = malloc(sizeof(NODE));
newNode->number = value; // added this
newNode->next = NULL; // added this
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;
}
Your main function should now iterate over reading the numbers for the different short lists as below. As you see, variable names are more explicit than yours. They are limited to the minimum and there are no global variables.
int main(int argc, char* argv[])
{
NODE *globalList = NULL, *lists[100];
int nbrOfLists, listNo, nbrOfVal, valNo, val;
printf("\n Enter the number of lists:");
scanf("%d", &nbrOfLists);
if(nbrOfLists < 0 || nbrOfLists > 100)
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[listNo] = 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[listNo] = insertValue(lists[listNo], val);
globalList = insertValue(globalList, val);
}
display(lists[listNo]);
}
display(globalList);
return 0;
}
Your display function is correct. I provide it below, but it's the same as yours. The problem you encountered was because I forgot to initialize the fields of the node after I malloc it.
void display(NODE * list)
{
while(list)
{
printf("%d ->", list->number);
list = list->next;
}
}

C - how to modify an array of pointers inside of a function

I'm trying to implement a hash table in C, and almost have it. I'm implementing collision resolution via chaining using a linked list in each array slot, and I'd like to be able to chain inside a function call.
Now, the problem is that in order for the modifications to be permanent I believe that I need an additional level of indirection. This is a problem in that when I try to traverse the list the previous element is overwritten by the next (see my comment inside the insert() function). I've tried to pass this array with an additional level of indirection specified a few different ways but I get compiler warnings and seg faults.
This may seem simple to some of you, but it's had me scratching my head for quite some time now, and this scenario (passing array of pointers for modification) is treated nowhere in my text and I can't seem to find this exact question asked (although it may be in a form I don't recognize). I'm not necessarily looking for a 'quick fix' to my code, but I want to understand what is the best practice to accomplish what I'm looking to do.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//#include "list.c"
struct node{
int key;
struct node* next;
};
void createTable(struct node *table[], int numEls, int numSlots);
int hash(int key, int numSlots);
void insert(struct node *table[], int key, int slot, int numSlots);
void display(struct node *table[], int numEls);
int main(void){
srand(time(NULL));
int numEls, numSlots;
printf("Please enter the desired number of slots in the hash table: ");
scanf("%d", &numSlots);
struct node *table[numSlots];
printf("\nPlease enter the desired number of elements: ");
scanf("%d", &numEls);
printf("\nYour load factor will be %f", (float)numEls/numSlots);
createTable(table, numEls, numSlots);
}
void createTable(struct node *table[], int numEls, int numSlots){
for(int i = 0; i < numSlots; i++)
table[i] = NULL;
for(int j = 0; j < numEls; j++){
for(int k = 0; k < 99999999; k++){}//give the rand function time
int el = rand()%100;
insert(table, el, hash(rand()%100, numSlots), numSlots);
}
display(table, numSlots);
}
int hash(int key, int numSlots){
return((int)(pow(key, 2.819)) % numSlots);
}
void insert(struct node *table[], int key_, int slot, int numSlots){
printf("\nInserting %d into slot %d", key_, slot);
fflush(stdout);
struct node* new = malloc(sizeof(struct node));
(new)->key = key_;
(new)->next = NULL;
struct node** temp = &(table[slot]);
if((*temp) == NULL){
printf(" (*temp) == NULL");
(*temp) = new;
}
else{
printf(" %d", (*temp)->key);
while((*temp)->next != NULL){
printf(" %d", (*temp)->next->key);
(*temp) = (*temp)->next; //head is overwritten with head->next
}
(*temp)->next = new;
printf(" %d", (*temp)->next->key);
}
}
void display(struct node *table[], int numSlots){
for(int i = 0; i < numSlots; i++){
printf("\nSlot %d:", i);
struct node* temp = table[i];
while(temp != NULL){
printf(" %d", temp->key);
temp = temp->next;
}
}
}
In the line with the comment, you are overwriting the pointer to the head (inside the outermost array) with the next element in the linked list, which was probably not your intent.
The correction is to walk down the list of pointers until you found the last pointer, without modifying the main data structure during the walk.
Here is a corrected version of insert().
void insert(struct node *table[], int key_, int slot, int numSlots){
printf("\nInserting %d into slot %d", key_, slot);
fflush(stdout);
struct node* new = malloc(sizeof(struct node));
new->key = key_;
new->next = NULL;
// Here we make a copy of the pointer to the head node in the linked list.
// This way, we never overwrite the original copy which lives in the array itself.
struct node* head = table[slot];
if(head == NULL){
printf(" head == NULL");
table[slot] = new;
}
else{
while(head->next != NULL) {
head = head->next; //head is overwritten with head->next
}
head->next = new;
}
}
This isn't an answer but is too big for a comment... can you explain what this code is meant to be doing?
while((*temp)->next != NULL)
{
printf(" %d", (*temp)->next->key);
(*temp) = (*temp)->next; //head is overwritten with head->next
}
(*temp)->next = new;
I would expect that you want to append the new node at the end of the linked list of existing nodes in this slot. But this code actually updates the head to point to the last node in the list , just like your comment says (leaking memory - the earlier nodes in the list are now unreachable). Then it makes the last node (which is now the only node in the list) point to new.
So your "list" only ever has length 1 or 2, and it leaks memory each time you try to put a third entry in.
It seems to me that there is nothing wrong with your passing of table (which is a list of heads of linked lists) but the problem is that the code that maintains the list for which those are heads, is not right.

Resources