Linked list using typedef - c

#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int value;
struct node* next;
} node;
void print(node* list);
int main()
{
node* n1;
node* n2;
n1 = (node *) malloc(sizeof(node));
n2 = (node *) malloc(sizeof(node));
n1->value = 4;
n1->next = n2;
n2->value = 5;
n2->next = NULL;
print(n1);
return 0;
}
void print(node* list)
{
node* p;
p = list;
while (p != NULL)
{
printf("%d ", p->value);
p = p->next;
}
}
The code works but my compiler (gcc) gives a warning that n1->next = n2 is (assignment from incompatible pointer type)
What does it mean? and how do I avoid it?

typedef struct {...} node declares node to be a type alias for a struct without a tag. In C, two otherwise identical structs with different tags are not the same structure. (Furthermore, two declarations of structs without tags are different structs.) The declaration does not declare struct node at all. So struct node* next; refers to a different, incomplete struct. (It's ok that its incomplete, because you only use it as a pointer.)
Here's a a better way of doing it. (Changing node to Node is just my style; I find it easier when type names are easily distinguishable from variable names.) Note the predeclaration of the typedef, which allows its use inside the later struct definition. (It's still incomplete when its used inside the definition, but that's OK because it's a pointer.)
I also changed the malloc calls to use the type of the variable being defined rather than the typename, which is generally better style. (And I removed the unnecessary casts; if you plan to use C++, you should change the malloc to a new rather than adding a C-style cast.)
#include <stdio.h>
#include <stdlib.h>
typedef struct Node Node;
struct Node {
int value;
Node* next;
};
void print(Node* list);
int main()
{
Node* n1 = malloc(sizeof *n1);
Node* n2 = malloc(sizeof *n2);
n1->value = 4;
n1->next = n2;
n2->value = 5;
n2->next = NULL;
print(n1);
return 0;
}
void print(Node* list)
{
Node* p;
p = list;
while (p != NULL)
{
printf("%d ", p->value);
p = p->next;
}
}
(Live on coliru)

Related

debug an array of linked lists in c

I'm having a trouble in my project, at first I made one linked list and it worked properly but then I had to edit it and make it an array of linked list, but it just stores in a wrong way I guess, here is my code, what's wrong with it?
#include <stdio.h>
#include <stdlib.h>
struct node
{
int coeff;
int power;
struct node* Next;
};
void Insert(int X,int Y, struct node* L, struct node* P)
{
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->coeff = X;
temp->power = Y;
temp->Next = P->Next;
P->Next = temp;
}
void PrintList(struct node* L)
{
struct node* P = L;
printf("%d %d ",P->coeff,P->power);
printf("\n");
P=P->Next;
}
int main()
{
struct node* head[3] ;
for(int q =0 ; q!= 3 ; q++)
{
head[q] = malloc(sizeof(struct node));
}
Insert(1,2,head[0],&head[0]);
Insert(2,3,head[0],&head[0]);
Insert(1,2,head[1],&head[1]);
Insert(2,2,head[1],&head[1]);
for(int i=0 ;i!=3;i++){
PrintList(head[i]);
}
return 0;
}
In a LinkedList there is only 1 head. You have allocated 3 different heads and are trying to add nodes to these heads. So the following answer assumes you intend to have 3 different LinkedLists with each list's head in an array.
The memory from malloc() in this line
head[q] = malloc(sizeof(struct node));
was uninitialized. Using calloc() appeared more prudent here. So,
head[q] = calloc(sizeof(struct node), 1); //Initialize everything to 0
Next, one of the arguments in your Insert() was redundant and also didn't go with your calling code. It is of the signature
void Insert(int ,int , struct node* , struct node*)
but you're invoking it with
void Insert(int ,int , struct node* , struct node**)
Dropping the last argument should be fine, I guess, in this case since you aren't modifying the incoming struct node* pointer but its contents instead. In case you were changing the struct node* to point to something else within the Insert() function (e.g. P = temp; etc.), then passing in a struct node** would have more meaning. So, changing your code to
void Insert(int X,int Y, struct node* P)
{
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->coeff = X;
temp->power = Y;
temp->Next = P->Next;
P->Next = temp;
}
And the calling code to
Insert(2,3,head[0]);
Insert(1,2,head[0]);
Insert(1,2,head[1]);
Insert(2,2,head[1]);
Next, changing your PrintList to actually traverse the LinkedList:
void PrintList(struct node* L)
{
struct node* P = L;
while(P) {
printf("%d %d\n",P->coeff,P->power);
P=P->Next;
}
}
Apart from that, I just added some logging to better clarify the LinkedList being printed.
for(int i=0 ;i!=3;i++){
printf("Printing list %d:\n", i);
PrintList(head[i]);
printf("*****\n");
}
This gives the output:
Printing list 0:
0 0
1 2
2 3
*****
Printing list 1:
0 0
2 2
1 2
*****
Printing list 2:
0 0
*****
Obviously, all the head of the LinkedLists are 0 initialized and hence show up as 0 0. They could be initialized as deemed fit, or could be dropped from the PrintList() function altogether, depending on your program's expectations.
When working on a C project you should always enable compiler warnings. If you do the compiler will issue a warning like
warning: passing argument 4 of ‘Insert’ from incompatible pointer type [-Wincompatible-pointer-types]
This is just the first problem in your code. You also have uninitialized fields in the nodes you allocate in the main function.
Instead of having a function which modifies the list, it is more flexible to define a function which adds a new node to a list and returns the new list. Below is an alternative approach which also uses convenience macro functions for allocating memory and calculating the length of an array. The code also hides the pointer behind a type definition and defines a function which frees a list.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN(array) ((int) (sizeof (array) / sizeof (array)[0]))
#define NEW_ARRAY(pointer, length) \
{ \
(pointer) = malloc(((size_t) length) * sizeof (pointer)[0]); \
if ((pointer) == NULL) { \
fprintf(stderr, "Allocating memory with malloc failed: %s\n", strerror(errno)); \
exit(EXIT_FAILURE); \
} \
}
#define NEW(pointer) NEW_ARRAY((pointer), 1)
typedef struct node *List;
struct node {
int coeff;
int power;
struct node *next;
};
List NewList(int coeff, int power, List next)
{
List node;
NEW(node);
node->coeff = coeff;
node->power = power;
node->next = next;
return node;
}
void FreeList(List list)
{
if (list != NULL) {
FreeList(list->next);
free(list);
}
}
void PrintList(List list)
{
while (list != NULL) {
printf("%d %d\n", list->coeff, list->power);
list = list->next;
}
}
int main(void)
{
List head[3] ;
head[0] = NewList(1, 2, NewList(2, 3, NULL));
head[1] = NewList(1, 2, NewList(2, 2, NULL));
head[2] = NULL;
for (int i = 0; i < LEN(head); i++) {
PrintList(head[i]);
FreeList(head[i]);
}
return 0;
}

Converting array to a generic list in C

I have created a new struct that represents a linked list and two functions listDestroy and arr2list. The second function gets a generic array and converts it into a list. The code:
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(List* list, void freeElement(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
if (length == 0 || !copyElement || !freeElement) {
return NULL;
}
struct List* head = (struct List*) malloc(sizeof(struct List));
if (head == NULL) {
return NULL;
}
List* current_node = head;
for(int i = 0; i < length; i++) {
current_node->value = copyElement(array[i]);
struct List* new_node = (struct List*) malloc(sizeof(struct List));
if (new_node == NULL) {
listDestroy(head, freeElement);
return NULL;
}
current_node->next = new_node;
current_node = new_node;
}
return head;
}
I think that I have a problem with the copyElement(array[i]);. I want to pass a generic array of elements to arr2list but I'm not sure if void* array[] is the right way. If I change it to be void* array I get an error for array[i]. What is the right way to make it work? Is it possible to also show a working example?
The last node of the list ends up with a NULL next and a garbled value. I don't think this is what you wanted. Try this loop:
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = malloc(sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = copyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
This uses a pointer to pointer so that we can update head or next depending on where we are in the loop without an extra if condition. Note that the allocaction of head is inside the loop now, so we always allocate exactly as many nodes as we need.
void* array[] is completely valid in this scenario, although I don't see the point of copyElement.
Perhaps just remove it and use array[i] instead?
I'd also like to point out a few mistakes that you may want to fix in your code:
Don't cast the result of malloc and use sizeof(*var) instead of sizeof(type). They're unneeded and may cause issues later on if you change the type of head. So, change this (and any later occurrences):
struct List* head = (struct List*) malloc(sizeof(struct List));
to this:
struct List* head = malloc(sizeof(*head));
Consider returning struct List * from arr2list. Change this:
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
to this:
struct List* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
Also, use either struct List * or List *. Inconsistencies may make it hard to understand your code.
It may be clearer if you pass function pointers to your functions instead of just functions. So, instead of doing this:
returntype func(params),
do this:
returntype (*func)(params),
You may also want to change malloc calls to calloc calls. calloc zeroes out memory, which can help in debugging. Change:
malloc(...)
to:
calloc(1, ...)
Here's an example combining code fixes from Joshua's post and mine:
list.c:
#include <stdlib.h>
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(struct List* list, void (*freeElement)(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
struct List* arr2list(void* array[], int length, void (*freeElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
if (length == 0 || !freeElement) {
return NULL;
}
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = array[i];
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
test.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.c"
void free_element(void *el)
{
free(el);
}
int main(void)
{
List *list;
int ctr;
void *array[4];
for(ctr = 0; ctr < 4; ctr++)
{
/* Don't usually pass sizeof(type) to malloc(),
* but these are extenuating circumstances. */
array[ctr] = malloc(sizeof(int));
if(!array[ctr]) return 1;
*(int *)array[ctr] = ctr * 4;
}
list = arr2list(array, sizeof(array)/sizeof(array[0]), free_element);
while(list)
{
printf("%d\n", *(int *)list->value);
list = list->next;
}
listDestroy(list, free_element);
return 0;
}
Output:
0
4
8
12
One last note: you may consider creating a header file that defines these structures and functions (and remove the structure from list.c). Here's an example:
#ifndef LIST_H
#define LIST_H 1
typedef struct List { // Remove this from list.c
struct List* next;
void *value;
} List;
void listDestroy(struct List*, void (*)(void*));
struct List* arr2list(void* [], int, void (*)(void*));
#endif

Assignment between pointers work only inside main, not in procedure body

I'm getting a segmentation fault error, if I try to make a copy between pointers to a struct, inside a procedure body.
If I instead, make the copy between pointers within the main() body, everything works correctly.
Code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *father, *lchild, *rchild;
} node;
typedef struct node Node;
// Prototypes
Node* insertRoot(int val, Node* N);
int main(){
Node * A = NULL;
Node * b = insertRoot(10, A);
//A = b; // If I do the assignment here it works correctly.
printf("A->value = %d \n\n" , A->value); //Segmentation fault!
return 0;
}
Node* insertRoot(int val, Node* N){
Node* temp = malloc(sizeof(Node));
temp->value = val;
temp->father = NULL;
temp->lchild = NULL;
temp->rchild = NULL;
N = temp; // If I do the assignment here instead, it won't work.
return temp;
};
You are not assigning any value to A inside insertRoot, you are assigning to N which is a copy of A. That leaves the value A=NULL unchanged.

Segmentation fault while trying to insert node into a linked list

I started learning C programming a few days ago through the book, Programming in C, and I have prior knowledge of java. Inserting a node into a linked list is very easy in java, but I thought if I could do the same in C.
So, I came up with this program,
#include "node.h"
void insertEntry(struct node* root, struct node* after)
{
struct node* first = root;
while(first != (struct node*) 0)
{
if(first->value == after->value)
{
struct node ins;
ins.value = 3456;
ins.next = first->next;
first->next = &ins;
}
first = first->next;
}
}
int main(void)
{
struct node n1, n2, n3;
struct node* list_pointer = &n1;
n1.value = 100;
n1.next = &n2;
n2.value = 200;
n2.next = &n3;
n3.value = 300;
n3.next = (struct node*) 0;
void insertEntry(struct node* root, struct node* after);
while (list_pointer != (struct node*) 0)
{
printf("%i\n", list_pointer->value);
list_pointer = list_pointer->next;
}
printf("\n");
list_pointer = &n1;
insertEntry(list_pointer, &n2);
while (list_pointer != (struct node*) 0)
{
printf("%i\n", list_pointer->value);
list_pointer = list_pointer->next;
}
return 0;
}
node.h
#include <stdio.h>
struct node
{
int value;
struct node* next;
};
Basically, this program takes pointer to the first element of the linked list and the pointer to the element after which it is to be inserted, and inserts a new node after this node.
But when I run this, my program crashes and I cannot find where or why this error occurs.
I looked over to the code in java and tried to implement the same in C.
Thank you.
Here's your problem:
{
struct node ins; // You create an object in the stack
ins.value = 3456;
ins.next = first->next;
first->next = &ins; // You reference your object
} // Your object is popped out of the stack and ceases to exist
// Any access to first->next past this block may cause segfault
In order to avoid this, you could create ins with malloc(), but beware: this isn't java and you have to keep track of all objects you allocated in the heap yourself.
The main problem is you insert a node that is allocated on the stack -- it's invalid as soon as the function is left. To allocate new memory, you need malloc() (don't forget to free() when done, there is no garbage collection).
A few side notes:
It's utterly pointless to cast 0 when used as a pointer to any specific pointer type ... 0 is 0.
You don't need the root node for inserting, so why pass it in the first place?
declaring a prototype inside of a function (in that case: main) doesn't make too much sense ... it will work without because the function you want to call is already defined in the same file.
#include headers where they are needed! node.h doesn't need stdio, the main program does.
A version of roughly your program that would work:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct node
{
int value;
struct node *next;
};
struct node *insertEntry(struct node* after, int val)
{
assert(after); /* not NULL */
struct node *new = malloc(sizeof(struct node));
new->value = val;
new->next = after->next;
after->next = new;
return new;
}
void freeNodeList(struct node* root)
{
struct node *current, *last;
current = root;
while (current)
{
last = current;
current = current->next;
free(last);
}
}
int main(void)
{
struct node *n1, *n2, *n3;
struct node *ptr;
n1 = malloc(sizeof(struct node));
n2 = malloc(sizeof(struct node));
n3 = malloc(sizeof(struct node));
n1->value = 100;
n1->next = n2;
n2->value = 200;
n2->next = n3;
n3->value = 300;
n3->next = 0;
insertEntry(n2, 250);
ptr = n1;
while (ptr)
{
printf("%d\n", ptr->value);
ptr = ptr->next;
}
freeNodeList(n1);
return 0;
}
You should read up on gdb and how to use it.
gcc -Wall -O0 -g x.c -o x
x being your program to compile with debuging information and no optimisation.
then run your program through gdb to find the location/occurrence of the fault.
ie.
gdb x

How to split a linked-list into two lists

I'm writing a code to split a circular linked-list to two linked lists with equal number of codes, following is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node *ptr;
struct node {
int element;
ptr prev;
ptr next;
};
typedef ptr list;
typedef ptr position;
int main() {
list L=malloc(sizeof(struct node));
list first=malloc(sizeof(struct node));
list second=malloc(sizeof(struct node));
splitlist(L,first,second);
return 0;
}
void splitlist(list L, list first,list second) {
position p,temp;
p=malloc(sizeof(struct node));
temp=malloc(sizeof(struct node));
p=L;
int count=0;
while ((p)->next != L) {
count++;
}
int c=count;
while (c!=(count/2)-1) {
p=(p)->next;
temp=(p)->next;
}
first=L;
(p)->next=NULL;
second=temp;
c=count;
while (c!=(count/2)-1) {
temp=(temp)->next;
}
(temp)->next=NULL;
}
When compiling my code it gives no errors but I'm not sure if it's working properly.
In order to get more readable and maintainable code, the first step to improve the code could be to create functions which help manipulating lists. Candidate functions are:
ListInitialize()
ListPushFront()
ListPushBack()
ListPopFront()
ListPopBack()
ListGetFirstNode()
ListGetNextNode()
ListGetFront()
ListGetBack()
ListEmpty()
...
With a proper set of arguments and return values of course.
Then you can write your splitlist function using those basic list operation functions and your code will be easier to read and to reason about.
Also, in order to handle an empty list, you should have an extra list type which is not just a pointer to a node.
typedef struct Node_tag { int value; struct Node_tag *next; struct Node_tag *prev } Node, *NodePtr;
typedef struct IntList_tag { NodePtr front; NodePtr back; } IntList;
// Creates an empty list.
void ListInitialize( IntList *pList ) { pList->front = NULL; pList->back = NULL; }
void ListPushFront( IntList *pList, int value )
{ NodePtr newNode = malloc(sizeof(Node));
if(NULL != newNode )
{ newNode->next = pList->front;
newNode->prev = NULL; newNode->value = value;
pList->front = newNode;
if( pList->back == NULL ) pList->back = newNode; // first element...
}
}
// ...
Eventually, using those functions, you can write splitlist() function in a concise and noise-free way:
void splitlist( IntList * source, IntList *target1, IntList *target2 )
{
IntList * currentTarget = target1;
for( NodePtr currentNode = ListGetFirstNode(source); currentNode != NULL; currentNode = ListGetNextNode(currentNode) )
{
ListPushBack(currentTarget, currentNode->value );
if(currentTarget == target1 ) currentTarget = target2;
else currentTarget = target1;
}
}
It might appear that it is much work to create all those other list functions if all you want is splitlist. But in real world applications you will most likely want all those other functions as well (or you have them already). Only in homework situations, this looks a bit funny.
Example code. Using typedef for node to be compatible with Microsoft C compilers (C89). Note sometimes the pointer to a circular list is a pointer to the last node of the circular list, (which contains a pointer to the first node of the circular list), allowing for faster appends. This example assumes list pointers are pointers to first nodes, but could be modified to assume list pointers are to last nodes.
#include <stdlib.h>
typedef struct _node{
struct _node *next;
int data;
}node;
node * splitlist(node * psrc, node ** ppdst1, node ** ppdst2)
{
node *ps = psrc;
node ** ppd1 = ppdst1;
node ** ppd2 = ppdst2;
*ppd1 = *ppd2 = NULL;
if(ps == NULL)
return NULL;
while(1){
*ppd1 = ps;
ps = *(ppd1 = &(ps->next));
if(ps == psrc)
break;
*ppd2 = ps;
ps = *(ppd2 = &(ps->next));
if(ps == psrc)
break;
}
*ppd1 = *ppdst1;
*ppd2 = *ppdst2;
return NULL;
}
main()
{
node a[8] = {{&a[1],0},{&a[2],1},{&a[3],2},{&a[4],3},
{&a[5],4},{&a[6],5},{&a[7],6},{&a[0],7}};
node *pa = &a[0];
node *pb = NULL;
node *pc = NULL;
pa = splitlist(pa, &pb, &pc);
return 0;
}

Resources