C programming, double link list copy-over issue - c

I'm having some trouble copying a single linklist over to a double-linklist. Not sure what is going on but I'm having a gdb debugging error:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x0000000100000d86 in doublify (list=0x1001008c0) at lists.c:62
62 newDlist->item = curr->item;
The one-directional link list is working,
My .h Header File:
typedef struct _node {
Item item;
link next;
} node;
typedef struct _dnode *dlink;
typedef struct _dnode {
Item item;
dlink prev;
dlink next;
} dnode;
My Code:
link newLink (Item item){
link createLink = malloc(sizeof(node));
createLink->item = item;
return createLink;
}
link fromTo (int start, int end) {
link newList = NULL;
if(start <= end ){
newList = newLink(start);
newList->next = fromTo(start+1, end);
}
return newList;
}
//Heres where it isn't able to copy the linklist item over into the new dlist.
dlink doublify (link list) {
dlink newDlist = malloc (sizeof (dnode));
link curr = list;
while(curr != NULL){
newDlist->item = curr->item;
curr = curr->next;
newDlist = newDlist->next;
}
return newDlist;
}

In your doublify function, you only allocate enough space for the first dnode in your doubly-linked list. As you walk along the singly-linked list using curr, you'll need to allocate space for a new dnode at each loop iteration, one for each element in the singly-linked list.
You receive the error because on the second iteration you're trying to access newDlist->next, which is an uninitialized memory address.
Note that while creating the doubly-linked list you'll also need to keep a tmp pointer to the previous dnode in order to set the prev/next pointers correctly.

The problem happens on the second iteration of the while loop. When you assign newDlist to the 'next' item, the 'next' field might contain any value. The thing is that malloc simply gives you a pointer to a data region where any values might be (it doesn't clean it or init in some way).
You simply need to allocate a new node on each iteration and setup the pointers appropriately. Here is one of the ways how that can be done.
dlink prevNode = NULL;
// Insert the first item (if present) to simplify the loop
if ( curr != NULL )
{
dlink newDlist = malloc(sizeof(dnode));
newDlist->item = curr->item;
newDlist->next = NULL;
newDlist->prev = NULL;
prevNode = newDlist;
curr = curr->next;
}
while ( curr != NULL )
{
dlink newDlist = malloc(sizeof(dnode));
newDlist->item = curr->item;
prevNode->next = newDlist;
newDlist->prev = prevNode;
newDlist->next = NULL;
prevNode = newDlist;
curr = curr->next;
}

Maksim has a good answer that helped me, but to simplify the answer if you have...
void DisplayList(topNode* nodeType) {
node* ptrNode = nodeType;
while (ptrNode->next != NULL) {
// DO WORK
}
}
...then you need to change it to...
void DisplayList(topNode* nodeType) {
node* ptrNode = new node; // THIS IS THE KEY...ALLOCATE THE MEMORY
if (ptrNode == NULL)
cout << "Could not allocate memory -- exiting application!" << endl;
else {
ptrNode = nodeType; // THEN COPY THE TOP NODE POINTER
while (ptrNode->next != NULL) {
// DO WORK
}
}
}
I ran into this same problem in my class, so maybe this will save someone some effort in the future!

Related

removing elements & memory management in linked lists in c

there! I've been working on data structures & algorithms. One thing that has been bothering me a lot, is linked list.
I've check a lot of linked list code samples, but one thing that I have noticed in every single one of them, is how they create node structs & make the user link them together.
So I started searching ways of creating linked lists in different languages & porting them to C. I found a tutorial that worked with Java. After porting the code, insertion was working fine, but removing gives me seg faults.
I think it's working this way, since in Java, we have garbage collectors & the fact that after malloc() you need to free() the memory, but no matter, how much I thought about it, I couldn't wrap my head, to where I should put free(). So the struct is memory unsafe as well.
So my real problem is were I should use free() in this code(maybe the seg fault is for a completely different reason, who knows).
#include <stdlib.h>
struct node {int value; struct node* next;};
typedef struct {struct node* first; struct node* last;} linkedList;
void initializeLinkedList(linkedList* list)
{
list->first = list->last = NULL;
}
// O(1)
void addLastLinkedList(linkedList* list, int element)
{
// create a new node
struct node* insertionNode = malloc(sizeof(struct node));
insertionNode->value = element;
// check if the linked list is empty
if (list->first==NULL) list->first = list->last = insertionNode;
else
{
// make last node point to this node
list->last->next = insertionNode;
// make the last node, this node
list->last = insertionNode;
}
}
// O(1)
void addFirstLinkedList(linkedList* list, int element)
{
// create a new node
struct node* insertionNode = malloc(sizeof(struct node));
insertionNode->value = element;
// check if the linked list is empty
if (list->first==NULL) list->first = list->last = insertionNode;
else
{
// make node point to the first node
insertionNode->next = list->first;
// make it the first node
list->first = insertionNode;
}
}
// O(n)
int removeLastLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if (list->first==list->last) list->first = list->last = NULL;
// get the last to second node
struct node* currentNode = list->first;
while (currentNode != NULL)
{
if (currentNode->next == list->last) break;
currentNode = currentNode->next;
}
// set the last node to the second to last node
list->last = currentNode;
list->last->next = NULL;
}
// O(1)
int removeFirstLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if (list->first==list->last) list->first = list->last = NULL;
// get the second node
struct node* secondNode = list->first->next;
// remove the pointer of first node
list->first->next = NULL;
// make the second node, the first node
list->first = secondNode;
return 0;
}
Within the both functions addLastLinkedList and addFirstLinkedList you forgot to initialize to NULL the data member next of the new node. Add statement
insertionNode->next = NULL;
The function removeLastLinkedList invokes undefined behavior when the list contains only one node because after this if statement
if (list->first==list->last) list->first = list->last = NULL;
the control is passed further to this code snippet
struct node* currentNode = list->first;
//...
// set the last node to the second to last node
list->last = currentNode;
list->last->next = NULL;
where there is used the null pointer list->last to access data member next.
Also the function produces a memory leak because the removed node is not freed.
And the function returns nothing if the list was not empty.
At least rewrite the function like
int removeLastLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if ( list->first == list->last )
{
free( list->first );
list->first = list->last = NULL;
}
else
{
// get the last to second node
struct node *currentNode = list->first;
while ( currentNode->next != list->last )
{
currentNode = currentNode->next;
}
free( currentNode->next );
// set the last node to the second to last node
list->last = currentNode;
list->last->next = NULL;
}
return 0;
}
Similar problems exist in the function removeFirstLinkedList
Rewrite the function like
int removeFirstLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if ( list->first == list->last )
{
free( list->first );
list->first = list->last = NULL;
}
else
{
// get the second node
struct node *secondNode = list->first->next;
free( list->first );
// make the second node, the first node
list->first = secondNode;
}
return 0;
}
Here is ANOTHER brief example of the four non-trivial functions in your OP.
While it is apparent that the code (and comments) is struggling to get things happening correctly, the long variable and function names make it difficult to read. This "less verbose" version may bring some clarity to seeing/thinking about what operations are being performed and in what sequence.
The first two functions below deal with the "head" of the linked list. They are somewhat easier and "set the mood" before reading the second two functions that deal with the "tail".
// Use typedefs and short conventional names
typedef struct node {
int value;
struct node *next;
} node_t;
typedef struct {
node_t *first;
node_t *last;
} ll_t;
// Short names!
void LLprepend( ll_t *p, int element ) {
node_t *nn = calloc( 1, sizeof *nn ); // omitting verification
nn->value = element;
nn->next = p->first; // Always
p->first = nn;
if( p->last == NULL ) // first node on list
p->last = nn;
}
int LLtrimhead( ll_t *p ) {
if( p->first == NULL )
return -1;
node_t *pDel = p->first; // target node being removed
p->first = p->first->next; // advance ptr (may be NULL)
free( pDel ); // <<===
if( p->first == NULL ) // list now empty??
p->last = NULL;
return 0;
}
// Short names!
void LLappend( ll_t *p, int element ) {
// calloc initializes all bytes to NULL
node_t *nn = calloc( 1, sizeof *nn ); // omitting verification
nn->value = element; // store data
if( p->last == NULL )
p->first = p->last = nn; // first node on list
else
p->last = p->last->next = nn; // appended & adjusted
}
int LLtrimtail( ll_t *p ) {
if( p->last == NULL )
return -1;
node_t *pPen = p->first; // "Penultimate" node
// traverse to penultimate node
while( pPen->next && pPen->next->next )
pPen = pPen->next;
if( pPen == p->first ) { // Only 1 node on list
free( pPen ); // <<===
p->first = p->last = NULL;
return 0;
}
free( pPen->next ); // <<===
p->last = pPen; // last becomes what was 2nd last
return 0;
}

why free function causes infinite loop?

I created a program in c which :
Creates a simple linked list in c in which I store letters
Print the content of every node
delete the last node
Print the content of the list again
The problem is with the "delete_last" function because prints in terminal an infinite loop (I believe that the problem is invoked when I use free funtion.)
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
char xar;
struct node *next;
}Node;
void insert_list(Node **head , int len)
{
char x;
Node **list;
Node *node1 , *node2;
node1=(Node*)malloc(sizeof(Node));
printf("Give 5 characters : ");
x=getchar();
node1->xar = x;
node1->next=NULL;
list=&node1;
int i=0;
for(i=1 ; i < len ; i++)
{ x=getchar();
node2 = (node*)malloc(sizeof(node));
node2->xar = x;
node2->next = NULL;
(*list) -> next = node2;
list = &(*list) -> next ;
}
*head=node1;
}
void print_list(Node *head)
{
Node**lpp;
for(lpp=&head ; *lpp!=NULL ; lpp=&(*lpp)->next)
{
printf("\n the chars are %c" , (*lpp)->xar);
}
}
void delete_last(Node *head)
{
Node **lpp;
lpp=&head;
while((*lpp)->next!=NULL)
{
lpp=&(*lpp)->next;
}
free(*lpp);
}
int main()
{
Node *kefali ;
kefali = NULL;
insert_list(&kefali , 5);
print_list(kefali);
printf("\n");
delete_last(kefali);
print_list(kefali);
return 0;
}
You mustn't access to freed objects.
In the delete_last functon, you called free() for one of the nodes, but you didn't update any pointers there. This will have the following call of print_list access a freed object, invoking undefined behavior.
You should add
*lpp = NULL;
after
free(*lpp);
To get the freed node out of the list.
Note that this won't work for removing the first (only) element in the list because the head is passed as a copy. You should change the function to accept a pointer to the head pointer to enable it remove the first element.
Your delete_last lacks a way of telling that the last element was deleted. Either pass a pointer to head or return a new head.
Further, it's way to complicated. Using lpp as pointer to pointer is not necessary - it only complicates the code. Keep it simple.
Here is an example which returns the new head.
Node* delete_last(Node *head)
{
if (head == NULL) return NULL; // empty list
if (head->next == NULL)
{
// Only one element...
free(head);
return NULL;
}
Node *prev = head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
return head;
}
and call it like:
head = delete_last(head);
Here is an example which takes a pointer to head.
Node* delete_last(Node **head)
{
if (head == NULL) exit(1); // illegal call
if (*head == NULL) return NULL; // empty list
if ((*head)->next == NULL)
{
// Only one element...
free(*head);
*head = NULL;
return;
}
Node *prev = *head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
}
and call it like:
delete_last(&head);
You do not update the previous node (you need to keep track on it when iterating)
This makes no sense as you take reference to the local variable head and it does not change the the head of list when last element is deleted.
Node **lpp;
lpp=&head;
To prevent double-pointer function returns the head. Assign it when called. If return value is NULL the last element was deleted
Node *delete_last(Node *head)
{
Node *lpp = NULL, *prev;
if(head)
{
lpp=head -> next;
prev = head;
while(lpp->next)
{
prev = lpp;
lpp = lpp -> next;
}
if(prev == head && lpp == NULL)
{
free(head);
head = NULL; //empty list
}
else
{
free(lpp);
prev -> next = NULL;
}
}
free(lpp);
return head;
}
You can also use double pointer to modify the head when needed:
void delete_last(Node **head)
{
Node *lpp = NULL;
if(head && *head)
{
if(!(*head) -> next)
{
free(*head);
*head = NULL;
}
else
{
lpp = *head;
while(lpp -> next -> next)
{
lpp = lpp -> next;
}
free(lpp -> next);
lpp -> next = NULL;
}
}
}

Uninitialized local variable error

Here is the function which getting me into troubles and I actually can't understand why.
This function supposes to removes all the odd elements from a given linked-list and also returns an address of a new linked list of the odd elements removed.
typedef struct node {
int data;
struct node* next;
} Node;
Node* removeOddValues(Node **source)
{
Node *curr = *source;
Node *even;
Node *even_curr;
Node *odd;
Node *odd_curr;
Node *next;
even->next=NULL;
odd->next=NULL;
even_curr = even;
odd_curr = odd;
while(curr)
{
next = curr->next;
curr->next = NULL;
if(curr->data % 2!=0)// odd//
odd_curr = odd_curr->next = curr;//node add to last//
else //even//
even_curr = even_curr->next = curr;
curr = next;
}
*source= even->next;//update source//
return odd->next; //the new list of odd elements removed//
}
When I try to compile it, I get the following error:
warning C4700: uninitialized local variable 'even' used
warning C4700: uninitialized local variable 'odd' used
Two things:
First, you get warnings (and your program contains undefined behaviour and would probably crash) because you access/dereference uninitialised variables:
Node *even;
Node *odd;
even->next=NULL; // even has not been initialised
odd->next=NULL; // odd has not been initialised
Second, your code does not "remember" the roots of the new lists, i.e. you manage odd_curr and even_curr, each pointing to the last node of the respective list, but you do not have something like odd_root and even_root.
The following code shows how this could work. The logic for appending a node at the end while additionally considering a root node is the same for both lists, odd and even, and therefore factored out into a separate function:
void appendNode(Node **root, Node** lastNode, Node *curr) {
if (!*root) { // root not yet assigned?
*root = curr;
*lastNode = curr;
} else {
(*lastNode)->next = curr; // append curr after lastNode
*lastNode = curr; // let curr become the lastNode
}
(*lastNode)->next = NULL; // terminate the list at lastNode
}
Node* removeOddValues(Node **source)
{
Node *curr = *source;
Node *evenRoot = NULL;
Node *oddRoot = NULL;
Node *evenLast = NULL;
Node *oddLast = NULL;
while(curr)
{
Node *next = curr->next;
if(curr->data % 2!=0) {
appendNode(&oddRoot, &oddLast, curr);
}
else {
appendNode(&evenRoot, &evenLast, curr);
}
curr = next;
}
*source= evenRoot;
return oddRoot;
}
curr = next;
Gives you the first warning, because next is not initialized.
odd_curr = odd;
Gives you the second warning, because odd is not initialized.
You should consider using malloc to allocate structures, because you are just allocating pointers, not the actual nodes. You can start learning more about linked lists from this interactive guide. Even if you somehow fix these two warnings, it still won't work.
The simplest case, using only two variables. The even nodes stay in the original list; the odd nodes are removed from the chain and returned as a linked list.
#include <stdio.h>
struct llist {
struct llist * next;
int data;
};
struct llist *chop_odds(struct llist **source)
{
struct llist *odd = NULL;
struct llist **target = &odd;
while ( *source) {
if((*source)->data %2) { /* odd */
*target = *source; // steal the pointer
*source = (*source)->next; // source skips this node
target = &(*target)->next; // advance target
}
else source = &(*source)->next; /* even */
}
*target = NULL;
return odd;
}

Insert into linked lists

I'm still learning linked lists and have been trying to create a method to insert into a linked list.
I just want to know if this is the correct way of inserting? Also, how would I print the entire linked list, so it prints something like abc.
Here's what I have:
struct node {
char value;
struct node *next;
};
typedef struct node item;
void main() {
InsertChar('a');
InsertChar('b');
InsertChar('c');
}
void InsertChar(char s) {
item *curr, *head;
head = NULL;
curr = (item *)malloc(sizeof(item));
curr->value = s;
curr->next = head;
head = curr;
while(curr) {
printf("%c\n", curr->value);
curr = curr->next;
}
}
First of all, your function InsertChar is overwriting the value of head each time (head = curr), so you'll end up with a list of one item.
You need to declare something that will store head.
struct list
{
struct node *head;
};
Now you can easily print your list by going through each node.
void PrintList(struct list* list)
{
struct node *curr = list->head;
while (curr != NULL)
{
printf("%c\n", curr->value);
curr = curr->next;
}
}
Now you need to modify InsertChar so that the last item in the list (how will you find it?) points to your new item. I'll leave that to you :)
As you may have noticed, you have no means to access the list (if there was any) from outside InsertChar(). You don't use a global variable, nor do you input or output it.
A better implementation:
item * InsertChar(item ** phead, char s) {
item * curr;
// First, allocate a new item and fill it.
curr = malloc(sizeof(item)); // no need to cast here
if (curr) { // only if malloc() succeeds
curr->value = s;
curr->next = *phead;
*phead = curr;
}
return curr;
}
// InsertChar() is only supposed to insert, not to print.
void PrintList(item * head) {
item * curr = head;
while(curr) {
printf("%c", curr->value); // omit the line break as you want abc
curr = curr->next;
}
printf("\n"); // now the line break
return;
// alternative implementation for while loop:
for(curr=head; curr; curr=curr->next) {
printf("%c\n", curr->value);
}
}
void FreeList(item * head) {
item * curr = head;
while(curr) {
item * next = curr->next; // read it out before freeing.
free(curr);
curr = next;
}
}
so that you can do now
int main() {
item * list = NULL; // empty for now, no contents.
char success = 1;
success = success && InsertChar(&list, 'a');
success = success && InsertChar(&list, 'b');
success = success && InsertChar(&list, 'c');
if (!success) {
printf("Oops?");
FreeList(list);
return 1;
}
PrintList(list);
FreeList(list); // clean up.
}
Oops? I didn't test it, but it seems to me that it prints "cba". Why does it so? Well, InsertChar() puts everything to the start.
How to get around of this?
Either we can create an AppendChar() function. But this bears the danger that we into the trap of Schlemiel the Painter's algorithm: to start searching for the right place always from the start. Thus, I'll point out another approach:
int main() {
item * list = NULL; // empty for now, no contents.
item * cursor = InsertChar(&list, 'a');
if (!cursor) goto error;
// cursor now contains our first entry.
// We put the next one to cursor->next:
cursor = InsertChar(&cursor->next, 'b');
if (!cursor) goto error;
cursor = InsertChar(&cursor->next, 'c');
if (!cursor) goto error;
PrintList(list);
FreeList(list); // clean up.
return 0;
error:
printf("Oops?");
FreeList(list);
return 1;
}
I am not sure if I am right (didn't test it), but this should be the way to go.
If you are one of these who were taught that goto is evil under all circumstances, feel free to implement the error handling in a different way.

Pointer to struct incrementation

was implementing a singular linked list in C.
struct node
{
int data;
struct node *next;
};
struct list_el {
int val;
struct list_el * next;
};
typedef struct list_el item;
void main() {
item * curr, * head,*track;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next=0;
if(head!=NULL)
head->next = curr;
head = curr;
}
curr = curr-10;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ;
}
}
As there are 10 elements in the list, so to make the pointer point to the first element, I tried decreasing curr (pointer to struct) by 10, but this got me half way through the list, the values printed were 5,6,7,8,9,10.
The size of the struct is 4, whereas the size of the pointer is 2, it seems the pointer is decreased by 2*10=20 bytes instead of 40, is this normal? (as I read that pointer increments/decrements according to the size of its type)
You cannot use pointer arithmetic on a linked list: the items are allocated separately (with malloc) and so they will not be necessarily adjacent in memory. That approach would only work with an array.
There are several problems.
First of all, the following insertion code isn't correct:
if(head!=NULL) head->next = curr;
head = curr;
Basically, the element pointed to by head is irrevocably lost.
Secondly, the behaviour of the following code is undefined:
curr = curr-10;
You cannot move across several malloc()ed blocks using pointer arithmetic.
Once you fix the insertion logic, it will become possible to traverse the list like so:
for (curr = head; curr != NULL; curr = curr->next) {
....
}
Your code curr = curr-10 will not bring you back to the head of the linklist.
As Viruzzo pointed out in a comment, you cannot use pointer arithmetic on elements of a linked list. As the word "linked" implies, there are only pointers linking the items together, they're not required to be located at adjacent addresses.
The pointer arithmetic will simply decrease the pointer by a fixed number of bytes, it will not follow pointers. Your list, being singly-linked, doesn't even have previous-element pointers to follow.
curr = curr-10; is wrong. It does not perform the operation that you think it does!
To print the contents of your linked list, you need to start from the head and go through each and every node until you hit NULL (assuming its not a circular list).
void display()
{
NODE * current = head;
if (current == NULL) {
printf("Empty list \n");
return;
}
while(current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
return;
}
And to add new node in the front, you can use the following code snippet.
void addfront(int data)
{
NODE *newnode = NULL;
if ((newnode = malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("Couldn't allocate space for new element \n");
return;
}
if (head == NULL) {
// empty list
head = newnode;
tail = newnode;
} else {
newnode->next = head;
head = newnode;
}
return;
}
To add new node at the rear, you can use the following code snippet.
void addrear(int data)
{
NODE * newnode = NULL;
if ((newnode = (NODE *) malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("unalbe to allocate memory to the new element - %d \n", data);
return;
}
if (tail == NULL) {
assert(head == NULL && tail == NULL);
head = tail = newnode;
} else {
tail->next = newnode;
tail = newnode;
}
return;
}
All the above mentioned code snippet assumes, you have head and tail as global variables.
Hope this helps!

Resources