C Creating a linked list with next and previous pointer - c

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.

Related

C clone linked list

I would like to ask how to modify the cloneList function to work properly?
I always want to add a new element to the top of the list. I want Peter still at the top of the cloned list. I can't change the function header
typedef struct TEmployee
{
struct TEmployee *m_Next;
struct TEmployee *m_Bak;
char *m_Name;
} TEMPLOYEE;
TEMPLOYEE *newEmployee (const char *name, TEMPLOYEE *next)
{
TEMPLOYEE *n = (TEMPLOYEE*) malloc(sizeof(*next));
n->m_Name = (char*) malloc(sizeof(char)*100);
strcpy(n->m_Name, name);
n->m_Bak = NULL;
n->m_Next = next;
return n;
}
TEMPLOYEE *cloneList(TEMPLOYEE *src)
{
TEMPLOYEE *x;
x = NULL;
TEMPLOYEE *tmp = src;
while(tmp)
{
x = newEmployee(tmp->m_Name, x);
x->m_Bak = tmp->m_Bak;
tmp = tmp->m_Next;
}
return x;
}
int main ()
{
TEMPLOYEE *a, *b;
a = NULL;
b = NULL;
a = newEmployee("Peter",a);
a = newEmployee("John",a);
...
b = clone(a);
}
Modify your cloneList function as below, so that you can get head node as return value.
TEMPLOYEE *cloneList(TEMPLOYEE *src)
{
TEMPLOYEE *x;
x = NULL;
int nCtr=0;
TEMPLOYEE *head=NULL;
TEMPLOYEE *tmp = src;
while(tmp)
{
x = newEmployee(tmp->m_Name, tmp->m_Next); //note the change
x->m_Bak = tmp->m_Bak;
if(nCtr == 0)
head = x;
tmp = tmp->m_Next;
nCtr++;
}
return head; //return the first node
}

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

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

Resources