C clone linked list - c

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
}

Related

second stack inside reverse function with pointers warning

I have the following stack implementation using doubly linked list, and I want to use a second stack inside the reverse function but I get errors. how to do that, let's say I want to return s2.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* prev;
struct Node* next;
} Node;
//---------------------Stack---------------------
typedef struct Stack {
int size;
Node* head;
Node* tail;
int top;
} Stack;
const Stack stack_init = { .size = 0, .head = NULL, .tail = NULL, .top = -1 };
Node* create_node(int elm) {
Node* node = malloc(sizeof * node);
if (!node) return node;
node->data = elm;
node->prev = NULL;
node->next = NULL;
return node;
}
int is_empty_s(Stack *s) {
return s->tail == NULL;
}
void push(Stack *s, int elm) {
Node* updated_head = create_node(elm);
if (!s->head) {
s->head = updated_head;
s->tail = s->head;
} else {
updated_head->next = s->head;
s->head->prev = updated_head;
s->head = updated_head;
}
s->size++;
s->top = s->head->data;
}
int pop(Stack *s) {
if (!is_empty_s(s)) {
Node* node = s->head;
int elm = node->data;
s->head = s->head->next;
if (s->head) {
s->head->prev = NULL;
s->top = s->head->data;
}
else {
s->tail = NULL;
s->top = -1;
}
s->size--;
free(node);
return elm;
}
}
Stack* reverse_s(Stack *s) { // iterative: using another stack, queue
Stack *s2 = stack_init;
while (s->tail) {
push(s2, pop(s));
}
return s2;
}
int main() {
Stack s1 = stack_init;
// Queue queue1 = queue_init; { .size = 0, .head = NULL, .tail = NULL, .front = -1 };
push(&s1, 5);
push(&s1, 4);
return 0;
}
As you can see the reverse function is not yet completed, I am new to C and this syntax I don't know how to handle it.
In reverse_s, s2 is of type pointer-to-Stack. stack_init has the structure type Stack. The assignment of a Stack value to a Stack * variable is incompatible.
A few options for reverse_s:
Return a Stack structure.
Stack reverse_s(Stack *s) {
Stack s2 = stack_init;
while (s->tail)
push(&s2, pop(s));
return s2;
}
Return a pointer-to-Stack, dynamically allocating memory for the structure.
Stack *reverse_s(Stack *s) {
Stack *s2 = malloc(sizeof *s2);
*s2 = stack_init;
while (s->tail)
push(s2, pop(s));
return s2;
}
Modify the original structure.
void reverse_s(Stack *s) {
Stack s2 = stack_init;
while (s->tail)
push(&s2, pop(s));
memcpy(s, &s2, sizeof *s);
}

segmentation fault testing linked list

I am trying to build and test a linked list in C. But I can't seem to figure out why I am getting segmentation fault from running the test (test_linked_list.c). The problem seems to be from the list_delete function when running gdb, but I can't find where the problem is. Why is this wrong?
linkedlist.c:
#include <stdio.h>
#include <string.h>
#include "linked_list.h"
void list_init(list_t *h) {
*h = NULL;
}
int list_size(const list_t *h) {
node_t *p = *h;
int r = 0;
do {
r += 1;
p = p->next;
} while (p);
return r;
}
int list_empty(const list_t *h) {
return (*h == NULL);
}
void list_insert(list_t *h, node_t *n) {
n->next = *h;
*h = n;
}
node_t *list_find(const list_t *h, int id) {
node_t *p = *h;
while (p) {
if (p->id == id)
return p;
p = p->next;
}
}
node_t *list_find_before(const list_t *h, int id) {
node_t *p = *h;
while (p && p->next) {
if (p->next->id == id)
return p;
p = p->next;
}
return NULL;
}
node_t *list_delete(list_t *h, int id) {
node_t *r = NULL;
if (*h && (*h)->id == id) {
r = *h;
*h = NULL;
return r;
}
// Here we have a syntax bug
node_t *p = list_find_before(h, id);
if (p) {
r = p->next;
p->next = p->next->next;
r->next = NULL;
}
return r;
}
void print_list(const list_t *h) {
node_t *p = *h;
while (p) {
printf("%d: %s says %s\n", p->id, p->name, p->msg);
p = p->next;
}
}
test_linked_list.c:
#include <stdlib.h>
#include "linked_list.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
void test_delete_one() {
list_t h;
list_init(&h);
node_t n;
n.id = 0;
strcpy(n.name, "hello");
strcpy(n.msg, "world");
list_insert(&h, &n);
node_t *f = list_delete(&h, 0);
assert(f == &n);
}
void test_delete() {
list_t h;
list_init(&h);
node_t n[3];
int i;
for (i = 0; i < 3; i++) {
n[i].id = i;
list_insert(&h, &n[i]);
}
list_delete(&h, 1);
assert(list_size(&h) == 2);
}
void core_dump_test() {
int size = 0;
list_t h;
list_init(&h);
size = list_size(&h);
printf("list size is: %d\n", size);
}
int main() {
test_delete();
test_delete_one();
core_dump_test();
printf("Pass\n");
}
There are wrong several functions.
For example list_size
int list_size(const list_t *h) {
node_t *p = *h;
int r = 0;
do {
r += 1;
p = p->next;
} while (p);
return r;
}
can invoke undefined behavior for an empty list.
Or another example. The function list_find
node_t *list_find(const list_t *h, int id) {
node_t *p = *h;
while (p) {
if (p->id == id) return p;
p = p->next;
}
}
returns nothin in case when a specified value is not found in the list.
Or the function list_find_before
node_t *list_find_before(const list_t *h, int id) {
node_t *p = *h;
while (p && p->next) {
if (p->next->id == id) return p;
p = p->next;
}
return NULL;
}
ignores the first node of the list.
And so on.
As for the function list_delete when even in its beginning it has a bug setting *h to NULL
node_t *list_delete(list_t *h, int id) {
node_t *r = NULL;
if (*h && (*h)->id == id) {
r = *h;
*h = NULL;
return r;
}
//...
Pay attention to that nodes must be allocated dynamically. Otherwise your list does not make sense.
The reason you get a segmentation fault in core_dump_test() is list_size cannot handle an empty list: it reads p->next without checking for p != NULL. As a rule of thumb, you should avoid do/while loops as they tend to hide bugs efficiently.
Here is a modified version:
int list_size(const list_t *h) {
int r = 0;
for (const node_t *p = *h; p; p = p->next) {
r += 1;
}
return r;
}
Here are modified versions of other functions with problems:
list_find has a missing return statement:
node_t *list_find(const list_t *h, int id) {
for (const node_t *p = *h; p; p = p->next) {
if (p->id == id)
return p;
}
return NULL; // was missing
}
list_delete truncates the list if the matching node is the first one. Also the syntax bug comes from your compiler rejecting the c99 syntax.
node_t *list_delete(list_t *h, int id) {
node_t *p;
node_t *r = *h;
if (r && r->id == id) {
*h = r->next;
r->next = NULL;
return r;
}
p = list_find_before(h, id);
if (p) {
r = p->next;
p->next = r->next;
r->next = NULL;
return r;
}
return NULL; // no matching node
}

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.

Linked lists and arrays

I have to make linked lists that contain all the non zero values from an array and print it out. However, my code is printing out the same value for how many non zero elements there are in the array.
The creation of the linked list and printing of the linked list are two separate functions.
The addLink function creates the linked list
void addlink(DataPtr *start, int element, double value) {
Data last = *start;
Data newPtr;
newPtr = malloc(sizeof(Data));
newPtr->element = element;
newPtr->usage = value;
newPtr->next = NULL;
if(*start == NULL) {
*start = newPtr;
return;
newPtr->element = element;
newPtr->usage = value;
newPtr->next = NULL;
}
while(last->next != NULL) {
last = last->nextPtr;
last->next = newPtr;
return;
}
}
The print function prints the linked list
void print(Data *start) {
Data current = *start;
while(current != NULL) {
printf("%d ", current->element);
printf("%.3lf", current->value);
current = current->next;
}
printf("\n");
}
This is how i call it in my main
for(k = 0; k < 50; k++) {
if(values[k] != 0) {
value = values[k];
addlink(&start,k,value);
print(&start);
}
}
struct data{
int element;
double value;
struct data *next;
};
typedef struct data Data;
typedef Data *DataPtr;
DataPtr start = NULL;
Here is correct implementation of your list:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
typedef struct data {
int element;
double value;
struct data *next;
} data_t;
void print(data_t *start);
void addlink(data_t **start, int element, double value);
int main()
{
int values[50] = { 0 };
int value = 0;
int k;
data_t *start = NULL;
//Give values some value
values[0] = 100;
values[1] = 250;
for(k = 0; k < 50; k++)
{
if(values[k] != 0)
{
value = values[k];
addlink(&start,k,value);
print(start);
}
}
}
void addlink(data_t **start, int element, double value)
{
data_t *newPtr;
newPtr = malloc(sizeof(data_t));
newPtr->element = element;
newPtr->value = value;
*start = newPtr;
}
void print(data_t *start)
{
data_t *current = start;
while(current != NULL)
{
printf("%d ", current->element);
printf("%f", current->value);
current = current->next;
}
printf("\n");
}
Your DataPtr idea, is no good. The "data_t" implementation is generally what you will see when seeing linked lists. It is easiest implemented this way.
If you are trying to implement a list that adds the newest data_t to the end of the list...
Check out http://www.learn-c.org/en/Linked_lists for further explanation.
A correct function implementation can look the following way
int addlink( DataPtr *start, int element, double value )
{
DataPtr newPtr = malloc(sizeof(Data));
int success = newPtr != NULL;
if ( success )
{
newPtr->element = element;
newPtr->value = value;
newPtr->next = NULL;
while ( *start != NULL ) start = &( *start )->next;
*start = newPtr;
}
return success;
}
If you want to add new elements at the beginning of the list then the function can look like
int addlink( DataPtr *start, int element, double value )
{
DataPtr newPtr = malloc(sizeof(Data));
int success = newPtr != NULL;
if ( success )
{
newPtr->element = element;
newPtr->value = value;
newPtr->next = *start;
*start = newPtr;
}
return success;
}
As for showed by you the function implementation then it shall not even compile. For example in this code snippet
Data last = *start;
Data newPtr;
newPtr = malloc(sizeof(Data));
the expression *start has the type DataPtr while the initialized variable last has the type Data. The same problem exists for the variable newPtr.
The function print can look like
void print( DataPtr *start )
{
for ( DataPtr current = *start; current != NULL; current = current->next )
{
printf("%d ", current->element);
printf("%.3lf", current->value);
}
printf("\n");
}
And it is called like
print( &start );

how to make a struct with void * data?

i have this struct :
struct node
{
int data;
struct node *next;
};
so the following strcut has an int data , i want the function to accept CopyFunction which is baisicly a pointer to a function that accepts void* and returns void* , i want my function to get a copy of the data in the first node connected to a copy f the second data , now i want the data to be not only int i want to use this function on any data so i used CopyFunction to be pointer to a function that as i saied accepts void* ... how can i use this in the function bellow .. for example if i want to change the struct to be :
struct node
{
Element data;
struct node *next;
};
typedef void* Element;
typedef Element (*copy_function) (Element);
struct node * concatLists( struct node *head1, struct node *head2, int cmp( struct node *),copy_function CopyFunction)
{
struct node *head = NULL;
struct node **current = &head;
for ( ; head1 != NULL; head1 = head1->next )
{
if ( cmp( head1 ) )
{
*current = malloc( sizeof( struct node ) );
( *current )->data = CopyFunction(head1->data);
( *current )->next = NULL;
current = &( *current )->next;
}
}
for ( ; head2 != NULL; head2 = head2->next )
{
if ( cmp( head2 ) )
{
*current = malloc( sizeof( struct node ) );
( *current )->data = CopyFunction(head2->data);
( *current )->next = NULL;
current = &( *current )->next;
}
}
and then if i have a int struct i can just use this function with a copy function for int like this :
static void* copyInt(void* num){
int* newInt=malloc(sizeof(*newInt));
*newInt=*(int*)num;
return newInt;
}
also i think it is better if i change and without using always struct node * i want to have maybe: typedef struct node_t* Node;
concatLists(..., (copy_function)copyInt)
Providing all the "methods" (cmp and CopyFunction) as parameters gets silly fast. Why not create a List "object" that holds not just a pointer to the head and tail, but the "methods" to genericize the list too.
cmp is probably a compare function (which means it should take two arguments), which means you are probably trying to merge sorted lists. Well, here's code that uses a generic list implementation to do just that. (I figured I might as well make malloc and free plugable as well.)
#include <stdio.h>
#include <stdlib.h>
// -----
// ListNode type declarations.
typedef struct ListNode {
void* data;
struct ListNode* prev;
struct ListNode* next;
} ListNode;
// -----
// ListType type declarations.
typedef void* (* Allocator )(size_t);
typedef void (* Deallocator )(void*);
typedef void (* FreeFunction )(void*);
typedef int (* CmpFunction )(void*, void*);
typedef void* (* CopyFunction )(void*);
typedef struct {
Allocator malloc;
Deallocator free;
FreeFunction free_data;
CmpFunction cmp;
CopyFunction copy;
} ListType;
// -----
// List type declarations.
typedef struct {
const ListType* list_type;
ListNode* head;
ListNode* tail;
} List;
typedef void (*ListVisitor)(void*);
// -----
// ListDataInt definitions.
static void* ListDataInt_new(int i) {
int* ip = malloc(sizeof(int));
*ip = i;
return ip;
}
static void ListDataInt_free_data(int* ip) {
free(ip);
}
static int ListDataInt_cmp(const int* ap, const int* bp) {
if (*ap < *bp) return -1;
if (*ap > *bp) return +1;
return 0;
}
static int* ListDataInt_copy(const int* orig_ptr) {
int* new_ptr = malloc(sizeof(int));
*new_ptr = *orig_ptr;
return new_ptr;
}
static const ListType ListDataInt_list_type = {
malloc,
free,
(FreeFunction)ListDataInt_free_data,
(CmpFunction)ListDataInt_cmp,
(CopyFunction)ListDataInt_copy
};
// -----
// ListNode definitions.
static ListNode* ListNode_new(List* list, void* data) {
const ListType* list_type = list->list_type;
ListNode* node = list_type->malloc(sizeof(ListNode));
node->data = data;
node->prev = NULL;
node->next = NULL;
return node;
}
static void ListNode_free(List* list, ListNode* node) {
const ListType* list_type = list->list_type;
list_type->free_data(node->data);
list_type->free(node);
}
// -----
// List definitions.
static List* List_new(const ListType* list_type) {
List* list = list_type->malloc(sizeof(List));
list->list_type = list_type;
list->head = NULL;
list->tail = NULL;
return list;
}
static void List_free(List* list) {
ListNode* next = list->head;
while (next != NULL) {
ListNode* node = next;
next = node->next;
ListNode_free(list, node);
}
list->list_type->free(list);
}
static void List_push(List* list, ListNode* node) {
if (list->tail == NULL) {
list->head = list->tail = node;
} else {
list->tail->next = node;
node->prev = list->tail;
list->tail = node;
}
}
static void List_push_data(List* list, void* data) {
List_push(list, ListNode_new(list, data));
}
static void List_visit(List* list, ListVisitor visitor) {
for (ListNode* node = list->head; node != NULL; node = node->next) {
visitor(node->data);
}
}
// -----
// Main program.
static List* merge_sorted_lists(List* list1, List* list2) {
const ListType* list_type = list1->list_type;
List* new_list = List_new(list_type);
ListNode* src1 = list1->head;
ListNode* src2 = list2->head;
while (src1 != NULL && src2 != NULL) {
int cmp = list_type->cmp(src1->data, src2->data);
if (cmp <= 0) {
List_push(new_list, ListNode_new(new_list, list_type->copy(src1->data)));
src1 = src1->next;
}
if (cmp >= 0) {
List_push(new_list, ListNode_new(new_list, list_type->copy(src2->data)));
src2 = src2->next;
}
}
while (src1 != NULL) {
List_push(new_list, ListNode_new(new_list, list_type->copy(src1->data)));
src1 = src1->next;
}
while (src2 != NULL) {
List_push(new_list, ListNode_new(new_list, list_type->copy(src2->data)));
src2 = src2->next;
}
return new_list;
}
static void dumper(const int* ip) {
printf("%d\n", *ip);
}
int main(void) {
List* sorted_int_list1 = List_new(&ListDataInt_list_type);
List_push_data(sorted_int_list1, ListDataInt_new(4));
List_push_data(sorted_int_list1, ListDataInt_new(6));
List_push_data(sorted_int_list1, ListDataInt_new(8));
List* sorted_int_list2 = List_new(&ListDataInt_list_type);
List_push_data(sorted_int_list2, ListDataInt_new(5));
List_push_data(sorted_int_list2, ListDataInt_new(7));
List_push_data(sorted_int_list2, ListDataInt_new(9));
List* merged_sorted_int_list =
merge_sorted_lists(sorted_int_list1, sorted_int_list2);
List_visit(merged_sorted_int_list, (ListVisitor)dumper);
List_free(sorted_int_list1);
List_free(sorted_int_list2);
List_free(merged_sorted_int_list);
return 0;
}
Test:
$ gcc -Wall -Wextra -pedantic --std=c99 -o a a.c && a
4
5
6
7
8
9

Resources