copy linked list in C using strdup - c

I have a linked data structure where i want to copy and save the original link. So i could edit the original link list without affecting the copied linked list. i tried the following method, and i got segmentation fault.
struct link {
char * name;
struct link *next;
};
struct list{
struct link *first;
struct link *last;
};
struct list *list_new(){
struct list *n = calloc(1, sizeof(struct list));
return n;
};
struct list* copyList(struct list*list){
struct list*new = list_new();
struct link *current = list -> first;
struct link *newCurrent = new -> first;
struct link *p;
if(current == NULL)
return NULL;
newCurrent = malloc(sizeof(struct link));
newCurrent = p;
while (current != NULL) {
p ->name = strdup((char*)current -> name);
p->next = malloc(sizeof(struct link));
p = p->next;
current = current->next;
}
return new;
}

I think you want something like:
struct list *copyList(struct list *list)
{
struct list *new = list_new();
struct link *current = list->first;
struct link *newCurrent = malloc(sizeof(struct link));
if((current == NULL) || (newCurrent == NULL) || (new == NULL))
{
if(newCurrent != NULL)
{
free(newCurrent);
}
if(new != NULL)
{
free(new);
}
return NULL;
}
else
{
new->first = newCurrent;
}
while(current != NULL)
{
newCurrent->name = strdup((char*)current -> name);
current = current->next;
if(current != NULL)
{
newCurrent->next = malloc(sizeof(struct link));
newCurrent = newCurrent->next;
}
else
{
newCurrent->next = NULL;
new->last = newCurrent;
}
}
return new;
}

The errors in copyList() are:
if(current == NULL)
return NULL;
An empty list should be allowed; the above fails to return the empty list copy.
newCurrent = malloc(sizeof(struct link));
newCurrent = p;
As BLUEPIXY wrote: allocate then overwrite by uninitialize variable. Moreover, the above is waste, since there's another malloc() in the while loop.
The undefined value of p is used in the while loop.
Corrected (still without allocation error checks):
struct list *copyList(struct list *list)
{
struct list *new = list_new();
struct link *current = list->first;
struct link *newCurrent = NULL;
struct link **p = &new->first; // where to place pointer to new node
for (; current; current = current->next, p = &newCurrent->next)
{
newCurrent = *p = malloc(sizeof **p);
newCurrent->name = strdup(current->name);
}
*p = NULL;
new->last = newCurrent;
return new;
}

Related

Adding a linked list to another linked list in C programming

I am abeginner trying to add a linked list to another linked list using c. the problem is that the program is entering an infinite loop and i don't know why.
And here's the following c code
typedef struct bookInfo
{
int code;
struct bookInfo *next;
} bookInfo;
typedef struct subscriber
{
int code;
struct bookInfo *books;
struct subscriber *next;
struct subscriber *prec;
} subscriber;
typedef bookInfo *Book;
typedef subscriber *Subscriber;
typedef Subscriber *SubscriberList;
void newBook(Book *bk, int val)
{
bookInfo *new_node = malloc(sizeof(bookInfo));
bookInfo *last = *bk;
new_node->code = val;
new_node->next = NULL;
if (*bk == NULL)
{
*bk = new_node;
}
else
{
while (last->next != NULL)
last = last->next;
last->next = new_node;
}
}
Subscriber Add_book(Subscriber S, Book Bk)
{
bookInfo *newNode = malloc(sizeof(bookInfo));
bookInfo *tmp;
newNode->next = NULL;
newNode->code = Bk->code;
if (S == NULL)
printf("\nl'abonnee est nulle");
else
{
if (S->books == NULL)
S->books = newNode;
else
{
tmp = S->books;
while (tmp != NULL)
tmp = tmp->next;
tmp->next = newNode;
printf("\nl'ajout du livre a ete effectue");
};
}
return S;
};
Hope you guys can help me and thank you. I don't know if the problem in the function newBook or what and here it's my main function
int main()
{
book_ref, sub_ref = NULL;
newSubscriber(&sub_ref);
bookInfo b1 = {20,NULL};
Add_book(sub_ref, &b1);
printf("\n%d : %d", sub_ref->code, sub_ref->books->code);
}
In your code,
while (tmp != NULL) tmp = tmp->next;
When this loop ends, tmp is NULL, so the next line will try accessing null pointer.
You should correct it as, while(tmp->next != NULL)
In order to remove the infinite loop, All i had to do was to define the pointer of books in the subscriber struct to NULL
void newBook(Book *bk, int val)
{
bookInfo *new_node = malloc(sizeof(bookInfo));
bookInfo *last = *bk;
new_node->code = val;
new_node->next = NULL;
new_node->books = NULL;
if (*bk == NULL)
{
*bk = new_node;
}
else
{
while (last->next != NULL)
last = last->next;
last->next = new_node;
}
}
Subscriber Add_book(Subscriber S, Book Bk)
{
bookInfo *newNode = malloc(sizeof(bookInfo));
bookInfo *tmp;
newNode->next = NULL;
newNode->code = Bk->code;
newNode->books = NULL;
if (S == NULL)
printf("\nl'abonnee est nulle");
else
{
if (S->books == NULL)
S->books = newNode;
else
{
tmp = S->books;
while (tmp != NULL)
tmp = tmp->next;
tmp->next = newNode;
printf("\nl'ajout du livre a ete effectue");
};
}
return S;
};
and everything worked.

making a copy of a single linked liked list

So what im trying to do is copying a linked list that, i made and to do so i know i need to transverse the list.
The problem is if i make a 1st copy it works but if i make a copy of the copy or another copy it gives segmentation fault and i dont understand why.
Program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node {
int v;
struct Node* next;
}link;
link* insert(link* head,int data)
{
link* x;
if (head == NULL)
{
link *new = (link*) malloc(sizeof(struct Node));
new->v = data;
new->next = NULL;
return new;
}
for(x = head; x->next != NULL; x = x->next);
link *new = (link*) malloc(sizeof(struct Node));
new->v = data;
new->next = NULL;
x->next = new;
return head;
}
void print_lst(link* head)
{
link* t;
for (t = head; t != NULL; t = t->next)
printf("* %d\n",t->v);
}
link* copy_lst(const link* head)
{
const link* x;
link *copy;
if (head == NULL)
{
return NULL;
}
for(x = head; x->next != NULL; x = x->next)
{
copy->v = x->v;
copy->next = x->next;
}
return copy;
}
int main()
{
link *head = NULL;
head = insert(head,5);
head = insert(head,6);
link *head2 = NULL;
head2 = copy_lst(head);
print_lst(head2);
link *head3 = copy_lst(head2);
return 0;
}

Linked list reverse function leads to infinite printing loop

I was writing a C code to reverse a link list. I got into one problem.
If I do not make my next pointer NULL my reverse function works fine, but if I make it null the linked list always keeps printing in the while loop.
Below is the correct program, which works fine.
But if I make *next = NULL, the display function will keep printing in the while loop.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
} *head;
/*************************************************************/
/* */
/* create - Function to create Nodes and add them at last */
/* */
/*************************************************************/
int create(int data)
{
struct node *temp,*ptr = NULL;
//int data = 0;
ptr = head;
//Printf(" Enter the Data for Node : ");
//scanf(" %d ", data);
temp = (struct node *)malloc(sizeof(struct node));
if (ptr == NULL) {
// this is the first node
temp->next = NULL;
temp->data = data;
head = temp;
} else {
// this is not the first node
while (ptr != NULL) {
if (ptr->next == NULL) {
temp->next = NULL;
temp->data = data;
ptr->next = temp;
break;
}
ptr = ptr->next;
}
}
return 0;
}
/*************************************************************/
/* */
/* create_in_front - Function to add Node in Front */
/* */
/*************************************************************/
int create_in_front(int data)
{
struct node *temp,*ptr = NULL;
ptr = head;
temp = (struct node *)malloc(sizeof(struct node));
if (ptr == NULL) {
// this is the first node
temp->next = NULL;
temp->data = data;
head = temp;
} else {
// this is not the first node
temp->next = ptr->next;
temp->data = data;
head = temp;
}
return 0;
}
/*************************************************************/
/* */
/* create_in_between - Function to add Node in between nodes*/
/* */
/*************************************************************/
int create_in_between(int data,int pos)
{
struct node *temp, *ptr = NULL;
int i = 0;
ptr = head;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
for (i = 0; i < pos; i++) {
if (i == pos-1) {
temp->next = ptr->next;
ptr->next = temp;
}
ptr = ptr->next;
}
return 0;
}
/*************************************************************/
/* */
/* delete_in_between - Function to add Node in between nodes*/
/* */
/*************************************************************/
delete_in_between(int pos)
{
struct node *ptr, *prev = NULL;
ptr = head;
int i = 0;
for (i = 0; i < pos; i++) {
if (i == pos-1) {
prev = ptr->next;
free(ptr);
break;
}
prev = ptr;
ptr = ptr->next;
}
return 0;
}
/*************************************************************/
/* */
/* reverse - Function to reverse link list */
/* */
/*************************************************************/
int reverse()
{
struct node *prev = NULL;
struct node *curr = head;
struct node *next = NULL;
curr = head;
while (curr != NULL) {
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
head = prev;
return 0;
}
/*************************************************************/
/* */
/* display - Function to diplay link list */
/* */
/*************************************************************/
// Function to display Link List
int display()
{
struct node *temp = head;
while (temp != NULL) {
printf("%d->",temp->data);
temp = temp->next;
}
return 0;
}
int main()
{
create(10);
create(20);
create(30);
create(40);
create(50);
create_in_front(34);
create_in_between(55,2);
//delete_in_between(4);
reverse();
display();
return 0;
}
Let me know the logic behind this.
Function create_in_front() is bogus: temp->next = ptr->next; should be changed to temp->next = ptr;
create_in_between() does not handle the case of pos==0.
delete_in_between() is completely dysfunctional: the node is frees but its predecessor still points to it.
reverse() seems correct to me, it could be simplified this way:
int reverse() {
struct node *prev = NULL;
struct node *curr = head;
while (curr != NULL) {
struct node *next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
head = prev;
return 0;
}
The problem seems unrelated to your modifying the reverse() function, maybe a side effect of bugs in the other functions.
Your reverse() function seems correct, but the rest of the code is somewhat overcomplicated. Try something like this:
void create(int data) {
struct node *temp = malloc(sizeof(struct node));
if (temp != NULL) {
temp->next = NULL;
temp->data = data;
if (head == NULL) { // this is the first node
head = temp;
} else {
// this is not the first node
struct node *last = head;
while (last->next)
last = last->next;
last->next = temp;
}
}
}
void create_in_front(int data) {
struct node *temp = malloc(sizeof(struct node));
if (temp != NULL) {
temp->next = head;
temp->data = data;
head = temp;
}
}

Pointers and struct

This is my problem...i've got this code(creating a list)
typedef struct node
{
int pid;
int runtime;
struct node *next;
}job;
int main()
//code
job *first = NULL;
job *last = NULL;
job *newnode;
//code
//from here
if( first == NULL )
{
first = last = newnode;
newnode->next = NULL;
}
else
{
last->next = newnode;
last = last->next;
}
// to here
So i wanted to do the part between from here to here in a function(so it would look better)
And i did this..i created a function
void funct(job ** pfirst, job **plast, job*newnode);
in main instead of the strong part i use:
funct(&first, &last, newnode);
and the function was like this
void funct(job ** pfirst, job **plast, job*newnode)
{
if(*pfirst == NULL)
{
*pfirst = *plast = newnode;
newnode->next = NULL;
}
else
{
*plast->next = newnode;//<----
*plast = *plast->next;//<----
}
}
The error is in the arrow and sais not part of a struct..
-> has higher precedence over *(Dereference) operator so you need parenthesis () around list to overwrite precedence. Correct it like:
(*last)->next = newnode;
*last->next = newnode; is wrong because it same as *(last->next) = newnode; and list has no member next
In addition to solutions mentioned here your 2nd code has logical error.. you should be checking for if(*pfirst == NULL) and not if(*pfirst != NULL)
void funct(job ** pfirst, job **plast, job*newnode)
{
if((*pfirst) == NULL)
{
*pfirst = *plast = newnode;
newnode->next = NULL;
}
else
{
(*plast)->next = newnode;//<----
*plast = (*plast)->next;//<----
}
}
Also considering you are creating List it will be better use (Remember you can do it even without last pointer).. this approach makes it easy to create more than One list Or Array Of List
typedef struct node
{
int pid;
int runtime;
struct node *next;
}job;
typedef struct List
{
job *first = NULL;
job *last = NULL;
}joblist;
and then something like
int main()
//code
joblist *list= NULL;
job *newnode;
//code
//from here
if( list== NULL )
{
list = malloc(sizeof (*list ));
list->first =list->last=newnode;
newnode->next = NULL;
}
else
{
list->last->next = newnode;
list->last = list->last->next;
}

Write a C program to create a copy of a linked list

I want to write a copy_list function that creates a linked list(the function result) with new nodes that contain the same data as the linked list referenced by the single argument of copy_list.But my copy_list function doesn't work.It goes into infinite loop,While loop doesn't quit.
My structures
typedef struct name_node_s {
char name[11];
struct name_node_s *restp;
}name_node_t;
typedef struct {
name_node_t *headp;
int size;
}name_list_t;
My copy_list function:
name_node_t *copy_list(name_node_t *head){
name_node_t *current = head;
name_node_t *newList = NULL;
name_node_t *tail = NULL;
while (current != NULL){
if (newList == NULL) {
newList = malloc(sizeof(name_node_t));
strcpy(newList->name, current->name);
newList->restp = NULL;
tail = newList;
}
else {
tail->restp = malloc(sizeof(name_node_t));
tail = tail->restp;
strcpy(tail->name, current->name);
tail->restp = NULL;
}
current = current->restp;
}
return(newList);
}
Rest of code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct name_node_s {
char name[11];
struct name_node_s *restp;
}name_node_t;
typedef struct {
name_node_t *headp;
int size;
}name_list_t;
name_node_t* presidents(void);
void insertAfter(name_node_t* mynode,name_node_t* newNode);
//void delete_last(name_node_t** headRef);
//void ListDelete(name_list_t* listP, char pname[]);
void lastDelete(name_list_t* listP);
void place_first(name_node_t **headRef, char pname[]);
name_node_t *copy_list(name_node_t *head);
int main(void)
{
name_list_t list;
name_list_t list_two;
//name_node_t *np, *qp;
list.headp = presidents();
name_node_t *new_node;
new_node = malloc(sizeof(name_node_t));
strcpy(new_node->name, "Eisenhower");
insertAfter(list.headp->restp, new_node);
lastDelete(&list);
place_first(&list.headp, "Mustafa");
printf("%s %s %s %s", list.headp->name, list.headp->restp->name, list.headp->restp->restp->name, list.headp->restp->restp->restp->name);
list_two.headp = copy_list(list.headp);
printf("%s %s %s %s", list_two.headp->name, list.headp->restp->name, list.headp->restp->restp->name, list.headp->restp->restp->restp->name);
return(0);
}
name_node_t* presidents(void)
{
name_node_t* head = NULL;
name_node_t* second = NULL;
name_node_t* third = NULL;
head = malloc(sizeof(name_node_t));
second = malloc(sizeof(name_node_t));
third = malloc (sizeof(name_node_t));
strcpy(head->name, "Washington");
head->restp = second;
strcpy(second->name, "Roosevelt");
second->restp = third;
strcpy(third->name, "Kennedy");
third->restp = NULL;
return(head);
}
void insertAfter(name_node_t* mynode,name_node_t* newNode)
{
newNode->restp = mynode->restp;
mynode->restp = newNode;
}
void ListDelete(name_list_t* listP, char pname[]){
name_node_t *to_freep, *cur_nodep;
if(strcmp(listP->headp->name, pname)){
to_freep = listP->headp;
listP->headp = to_freep->restp;
--(listP->size);
}
else {
for (cur_nodep = listP->headp;
cur_nodep->restp != NULL && !strcmp(cur_nodep->restp->name, pname);
cur_nodep = cur_nodep->restp) {
if( cur_nodep->restp != NULL && strcmp(cur_nodep->restp->name, pname)) {
to_freep = cur_nodep->restp;
cur_nodep->restp = to_freep->restp;
free(to_freep);
--(listP->size);
}
}
}
}
void lastDelete(name_list_t* listP){
name_node_t *to_freep, *cur_nodep;
for (cur_nodep = listP->headp;
cur_nodep->restp != NULL;
cur_nodep = cur_nodep->restp) {}
to_freep = cur_nodep;
cur_nodep->restp = to_freep->restp;
free(to_freep);
--(listP->size);
}
void place_first(name_node_t **headRef, char pname[]) {
name_node_t *newNode = malloc(sizeof(name_node_t));
strcpy(newNode->name, pname);
newNode->restp = *headRef;
*headRef = newNode;
}
/*name_node_t *copy_list(name_node_t *head) {
name_node_t *current = head;
name_node_t *newList = NULL;
name_node_t **lastPtr;
lastPtr = &newList;
while (current != NULL) {
printf("**");
place_first(lastPtr, current->name);
lastPtr = &((*lastPtr)->restp);
current = current->restp;
}
return(newList);
}*/
/*name_node_t *copy_list(name_node_t *head) {
if (head == NULL)
return NULL;
else {
name_node_t *newList = malloc(sizeof(name_list_t));
strcpy(newList->name, head->name);
newList->restp = copy_list(head->restp);
return(newList);
}
}*/
/name_node_t *copy_list(name_node_t *head){
name_node_t *current = head;
name_node_t *newList = NULL;
name_node_t *tail = NULL;
while (current != NULL){
if (newList == NULL) {
newList = malloc(sizeof(name_node_t));
strcpy(newList->name, current->name);
newList->restp = NULL;
tail = newList;
}
else {
tail->restp = malloc(sizeof(name_node_t));
tail = tail->restp;
strcpy(tail->name, current->name);
tail->restp = NULL;
}
current = current->restp;
}
return(newList);
}
In lastDelete(), this loop:
for (cur_nodep = listP->headp;
cur_nodep->restp != NULL;
cur_nodep = cur_nodep->restp) {}
... stops at the last node in the list. Afterwards you never set restp to NULL in the second-to-last element. You only work on the last one as to_freep and cur_nodep point to the same element.
This may be easier to do recursively, since singly-linked lists are recursive structures:
A copy of NULL is just NULL.
A copy of a name_node_t is a freshly malloc'd name_node_t with the same name as the original and a copy of the original's restp as its restp.
It's been a long time since I wrote C++. Still:
Doesn't look like there's anything in copy_list that should make it go into an infinite loop.
The logic has:
while (current!=null) current = current->next;
Perhaps copy_list is being passed in a bad list? (i.e A list where the last element does not have restp == null).
In main you are calling:
insertAfter(....);
lastDelete(....);
...
copy_list(....);
So the problem could be in insertAfter or lastDelete ... or ...
Check lastDelete:
name_node_t *to_freep, *cur_nodep;
for (cur_nodep = listP->headp;
cur_nodep->restp != NULL;
cur_nodep = cur_nodep->restp) {}
to_freep = cur_nodep;
cur_nodep->restp = to_freep->restp;
free(to_freep); //what if listP->headp was null? i.e. list had size 0?
--(listP->size);
Plenty of issues
What if you're passed a list with 0 elements?
What if you're passed a list with 1 element?
In any case after you free "to_freep", the node prior to "to_freep" does not have it's restp set to null. So the second last node, now points to a deleted node! This means the list never terminates.
A better lastDelete: (just an algo, can't remember the syntax anymore...)
if (head == null) return; //do nothing
if (head->next == null)
{
listP->head = null;
listP->size = 0;
return;
}
node* prev = head;
head = head->next;
while (head->next != null)
{
prev = head;
head = head->next;
}
//now prev points to a 2nd last node
//head points to last node
free(head);
prev->restp = null;

Resources