C Not sure what to free properly - c

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.

Related

Adding to head of linked list

Student *addToHead(Student *node, int data) {
Student *temp;
temp = createNode(data);
temp->nextPtr = node;
return temp;
}
This code does not insert to the head of a linked list I have no clue why.
I am not using a dummy node at the start of the linked list.
Here is my entire main function:
int main(void) {
Student *test = initList();
int searchTest = 0;
test = addToHead(test, 3);
test = addToHead(test, 2);
test = addToHead(test, 1);
test = addToTail(test, 4);
test = addToTail(test, 5);
printList(test);
searchTest = searchAge(test, 4);
printf("%d\n", searchTest);
test = freeList(test);
}
Here is what is being output:
4
5
0
Free was successful
The tail is being correctly inserted but not the head.
Here is the code for tail
Student *addToTail(Student *node, int data) {
Student *temp;
temp = createNode(data);
temp->age = data;
if (node == NULL) {
node = temp;
} else {
while (node->nextPtr != NULL) {
node = node->nextPtr;
}
node->nextPtr = temp;
}
return node;
}
The problem is not the function addToHead. The problem is the function addToTail that you did not show.
It can look for example the following way
Student *addToTail(Student *node, int data){
Student *temp = createNode(data);
if ( node == NULL )
{
temp->nextPtr = node;
node = temp;
}
else
{
Student *tail = node;
while ( tail->nextPtr != NULL ) tail = tail->nextPtr;
// Uncomment the line below if createNode does not set the data member nextPtr to NULL
// temp->nextPtr = NULL
tail->nextPtr = temp;
}
return node;
}
Edit: After you appended your answer with the definition of the function addToTail it is obvious that I was right saying that this function is wrong.
Within the function you are changing the head node
while(node->nextPtr!=NULL){
node=node->nextPtr;
}
that you are returning from the function.
How do you call this function? The caller should do
head = addToHead(head, 3)
for example.
What you want is more like
Student *addToHead(Student **head, int data) {
Student *tmp = NULL;
tmp = createNode(data);
tmp->nextPtr = *head;
*head = tmp;
return tmp;
}
And then call it with
addToHead(&listHead, 42);
Or keep your version and call it with :
listHead = addToHead(listHead, 42);

C Copying a linked list with two pointers

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...

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