C Copying a linked list with two pointers - c

This is for a school project and I need to finish a function to copy a linked list of employees that looks like this
typedef struct TEmployee
{
struct TEmployee * m_Next;
struct TEmployee * m_Bak;
char * m_Name;
} TEMPLOYEE;
this is my function for copying
TEMPLOYEE * cloneList(TEMPLOYEE * src)
{
TEMPLOYEE* current = src;
TEMPLOYEE* newList = NULL;
TEMPLOYEE* tail = NULL;
while(current != NULL)
{
if(newList==NULL)
{
newList = (TEMPLOYEE*)malloc(sizeof(TEMPLOYEE));
newList -> m_Name = current -> m_Name;
newList -> m_Next = NULL;
newList -> m_Bak = NULL;
tail = newList;
}
else
{
tail -> m_Next = (TEMPLOYEE*)malloc(sizeof(TEMPLOYEE));
tail = tail -> m_Next;
tail -> m_Name = current -> m_Name;
tail -> m_Next = NULL;
tail -> m_Bak = current -> m_Bak;
}
current = current -> m_Next;
}
return newList;
}
this works fine but it doesn't copy the m_Bak properly so when I try this assert the m_Next and m_Bak should be the same but aren't
assert ( b && ! strcmp ( b -> m_Name, "Maria" ) && b -> m_Bak == b -> m_Next );
Any help is appreciated.

This line
tail -> m_Bak = current -> m_Bak;
is wrong as it makes the new list point back to the current list.
You rather need:
else
{
tail -> m_Next = (TEMPLOYEE*)malloc(sizeof(TEMPLOYEE));
tail -> m_Next -> m_Bak = tail; // New line
tail = tail -> m_Next;
tail -> m_Name = current -> m_Name;
tail -> m_Next = NULL;
// tail -> m_Bak = current -> m_Bak; Delete this line
}
Notice that your code does not copy the names so both lists will point to the same name object. If you want to do a real copy of the names take a look at strdup
Also notice:
You don't need to cast the value returned by malloc. However, you should check if malloc returned NULL

this is my solution:
typedef struct TEmployee
{
struct TEmployee * m_Next;
struct TEmployee * m_Bak;
char * m_Name;
} TEMPLOYEE;
void *Malloc(size_t size)
{
void *ptr = NULL;
if ((ptr = malloc(size)) == NULL)
{
perror("alloc");
exit(1);
}
return ptr;
}
TEMPLOYEE *cloneList(TEMPLOYEE *src)
{
TEMPLOYEE *newList = (TEMPLOYEE *)Malloc(sizeof(TEMPLOYEE));
newList->m_Bak = NULL;
TEMPLOYEE *copy = newList;
TEMPLOYEE *current = src;
while (current != NULL)
{
newList->m_Name = strdup(current->m_Name); // need free
newList->m_Next = NULL;
if (current = current->m_Next)
{
newList->m_Next = (TEMPLOYEE *)Malloc(sizeof(TEMPLOYEE));
newList->m_Next->m_Bak = newList;
newList = newList->m_Next;
}
}
return copy;
}
Hope I understand your issue correctly...

Related

Segmentation fault after value assignment to pointer in C

There is code:
void pop(int id, List *head) {
List **previous = head;
List **current = (*previous) -> next;
if(head -> next == NULL && (*head).id == id) {
free(head);
} //if only 1 node in List
while((**current).id != id) {
*previous = head -> next;
*current = previous;
}
(*previous) -> next = (*current) -> next;
free(*current);
}
The program falls with segmentation fault on third stroke List **current = (*previous) -> next (I checked it with printfs).
CLion debuggers says Exception: EXC_BAD_ACCESS (code=1, address=0x113d349e2)
If I do printf("address = %d\n", &((*previous) -> next)); it gives me the address.
void delete_worker_by_id(int id, List *head) {
List **previous = &head;
List *current = (*previous) -> next;
if(head -> next == NULL && (*head).id == id) {
free(head);
head = NULL;
} //if only 1 node in List
while((*current).id != id) {
*previous = current;
current = current -> next;
}
if((*current).id == id) {
(*previous) -> next = current -> next;
current -> next = NULL;
free(current);
return;
}
puts("No worker with this id");
}

C Not sure what to free properly

I have a school homework for a linked list, this is all my functions and I need to finish the free function but I'm quite new to C so not really sure what exactly do I have to free
here is my code:
typedef struct TEmployee
{
struct TEmployee * m_Next;
struct TEmployee * m_Bak;
char * m_Name;
} TEMPLOYEE;
#endif /* __PROGTEST__ */
TEMPLOYEE * newEmployee(const char * name, TEMPLOYEE * next)
{
TEMPLOYEE* head = NULL;
head = (TEMPLOYEE *)malloc(sizeof(TEMPLOYEE));
if(head==NULL)
{
return NULL;
}
head -> m_Name = strdup(name);
head -> m_Next = next;
head -> m_Bak = NULL;
return head;
}
int getEmpPos(TEMPLOYEE *list, TEMPLOYEE *el){
int pos = 0;
TEMPLOYEE *listPos = list;
while(listPos != NULL){
if(listPos == el)
return pos;
listPos = listPos->m_Next;
pos++;
}
return -1;
}
TEMPLOYEE* getEmpAtPos(TEMPLOYEE* list, int pos)
{
TEMPLOYEE *toReturn = list;
for(int i = 0; i < pos; i++){
toReturn = toReturn->m_Next;
}
return toReturn;
}
TEMPLOYEE * cloneList(TEMPLOYEE * src)
{
TEMPLOYEE* current = src;
TEMPLOYEE* newList = NULL;
TEMPLOYEE* tail = NULL;
while(current != NULL)
{
if(newList==NULL)
{
newList = (TEMPLOYEE*)malloc(sizeof(TEMPLOYEE));
newList -> m_Name = (char *)malloc(1 + strlen(current -> m_Name));
strcpy(newList -> m_Name, current -> m_Name);
newList -> m_Next = NULL;
newList -> m_Bak = NULL;
tail = newList;
}
else
{
tail -> m_Next = (TEMPLOYEE*)malloc(sizeof(TEMPLOYEE));
tail = tail -> m_Next;
tail -> m_Name = (char *)malloc(1 + strlen(current -> m_Name));
strcpy(tail -> m_Name, current -> m_Name);
tail -> m_Next = NULL;
}
current = current -> m_Next;
}
// Clone backups
current = src;
tail = newList;
while(current != NULL){
if(current -> m_Bak)
{
tail -> m_Bak = getEmpAtPos(newList, getEmpPos(src, current->m_Bak));
}
else
{
tail -> m_Bak = NULL;
}
tail = tail -> m_Next;
current = current -> m_Next;
}
return newList;
}
and this is my free function but this way it only frees some things but not others
void freeList(TEMPLOYEE * src)
{
TEMPLOYEE* tmp;
while(src != NULL)
{
tmp = src;
src = src -> m_Next;
free(tmp);
}
}
Any help is greatly appreciated
There are only two functions that allocate memory that needs to be freed.
The newEmployee function creates a string with strdup that must be freed, as well as the TEMPLOYEE object itself.
The other function that allocates memory is cloneList, however it only clones a list. If we can first figure out how to properly free one list, we only need to make sure we free all cloned lists as well to ensure we free memory allocated in cloneList.
To properly free the list, we need to free each TEMPLOYEE object and the m_Name that it holds. Your free list function can be modified like so:
void freeList(TEMPLOYEE * src)
{
TEMPLOYEE *next = src;
while (next != NULL) {
TEMPLOYEE *prev = next;
next = prev->m_Next;
free(prev->m_Name);
free(prev);
}
}
As long as you call this on all lists, including those created by cloneList, all memory should be freed.

C Creating a linked list with next and previous pointer

This is homework for school. I have a struct Employee that looks like this
typedef struct TEmployee
{
struct TEmployee * m_Next;
struct TEmployee * m_Bak;
char * m_Name;
} TEMPLOYEE;
and a function to add a new employee that currently looks like this but I'm not sure how to make the m_Bak point to the previous employee
TEMPLOYEE * newEmployee(const char * name, TEMPLOYEE * next)
{
TEMPLOYEE* head = NULL;
head = malloc(sizeof(TEMPLOYEE));
if(head==NULL)
{
return NULL;
}
head -> m_Name = strdup(name);
head -> m_Next = next;
head -> m_Bak = NULL;
return head;
}
Any help is appreciated.
If I understood correctly, try this:
TEMPLOYEE *newEmployee(const char *name, TEMPLOYEE *next)
{
TEMPLOYEE *carry = (TEMPLOYEE *)malloc(sizeof(TEMPLOYEE));
carry->m_Next = NULL;
carry->m_Bak = NULL;
carry->m_Name = (char *)malloc(sizeof(char) * strlen(name) + 1); // +1 for \0
strcpy(carry->m_Name, name);
if (next == NULL)
{
return carry;
}
else
{
carry->m_Next = next;
return carry;
}
}
When your *next is NULL it creates new start. When you add new Employee it prepends it to the start.

copy linked list in C using strdup

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

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