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;
}
Related
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
I have the following Linked List:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head = NULL;
struct Node *second = NULL;
struct Node *third = NULL;
head = (struct Node*) malloc(sizeof(struct Node));
second = (struct Node*) malloc(sizeof(struct Node));
third = (struct Node*) malloc(sizeof(struct Node));
head -> data = 1;
head -> next = second;
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
printfList(head);
return 0;
}
How can I modularize this example to get something more professional? node type and separated from the others and function separately?
I think by "modularize" here you mean more kinda professional, clean looking code, I came up with following :
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
struct Node * makeNode(int data){
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
return temp;
}
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head, *prev;
int i, n;
printf("How many values you want to insert ?");
scanf("%d", &n);
printf("\nNow enter values :\n");
for(i = 0; i < n; i++){
int val;
scanf("%d", &val);
if(i == 0){
head = makeNode(val);
prev = head;
}
else{
struct Node *temp = makeNode(val);
prev->next = temp;
prev = temp;
}
}
printfList(head);
return 0;
}
Hope it helps.
I'm not sure what you're looking to do, but I think you should start by reviewing the question: should a "node" be a property of an object (a struct data type) or should a "node" be an accessor to a data type...?
Both work and I've used both.
When I need to link existing objects together, than a node will contain a reference data type... but unlike your list, the data is always accessed using a pointer (not containing the actual data type, but only using a reference).
This allows one (object) to many (lists) relationships.
However, many times the data type itself will need to be "chained" (in a single list - one to one relationship), in which case the "node" is a property of the data type and can be re-used in many different types.
A list to link existing types
Here's an example code where I used a linked list to link existing objects using a void pointer.
I'm not sure this implementation adds anything to your initial concept, but it does show the "modularization" for a "one (objet) to many (lists)" approach.
/* *****************************************************************************
Simple List
***************************************************************************** */
typedef struct fio_ls_s {
struct fio_ls_s *prev;
struct fio_ls_s *next;
void *obj;
} fio_ls_s;
#define FIO_LS_INIT(name) \
{ .next = &(name), .prev = &(name) }
/** Adds an object to the list's head. */
static inline __attribute__((unused)) void fio_ls_push(fio_ls_s *pos,
void *obj) {
/* prepare item */
fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
if (!item)
perror("ERROR: fiobj list couldn't allocate memory"), exit(errno);
*item = (fio_ls_s){.prev = pos, .next = pos->next, .obj = obj};
/* inject item */
pos->next->prev = item;
pos->next = item;
}
/** Adds an object to the list's tail. */
static inline __attribute__((unused)) void fio_ls_unshift(fio_ls_s *pos,
void *obj) {
pos = pos->prev;
fio_ls_push(pos, obj);
}
/** Removes an object from the list's head. */
static inline __attribute__((unused)) void *fio_ls_pop(fio_ls_s *list) {
if (list->next == list)
return NULL;
fio_ls_s *item = list->next;
void *ret = item->obj;
list->next = item->next;
list->next->prev = list;
free(item);
return ret;
}
/** Removes an object from the list's tail. */
static inline __attribute__((unused)) void *fio_ls_shift(fio_ls_s *list) {
if (list->prev == list)
return NULL;
fio_ls_s *item = list->prev;
void *ret = item->obj;
list->prev = item->prev;
list->prev->next = list;
free(item);
return ret;
}
/** Removes an object from the containing node. */
static inline __attribute__((unused)) void *fio_ls_remove(fio_ls_s *node) {
void *ret = node->obj;
node->next->prev = node->prev->next;
node->prev->next = node->next->prev;
free(node);
return ret;
}
A list that is integrated in the data-type
Often I have objects that I know I will link together and that by nature will only belong to a single list ("one to one").
In these cases, placing the node struct data within the data-type allows better locality and improved performance through a single allocation for both the data and the node information.
A good enough example for such a situation can be examined is this SO answer.
I am starting out on C and i was just wondering how I would declare these linked lists structures in the main function so that I could call the functions on them, and then how I would print the values from the elements of the linked list.
Thanks for the help
#include <stdio.h>
#include <stdlib.h>
void main() {
}
struct element {
struct element * next;
int data;
};
struct linked_list {
struct element * head;
};
void append_int(struct linked_list * list, int val) {
struct element * elem = malloc(sizeof(struct element));
elem->data = val;
elem->next = NULL; // Really important to explicitly set this to null. Malloc does not zero memory
if (list->head == NULL) {
// Empty list, we need to append to head
list->head = elem;
} else {
// List has some elements, find the end and append to that
struct element * tail = list->head;
while (tail->next != NULL) {
tail = tail->next;
}
tail->next = elem;
}
}
void deletehead(struct linked_list * list) {
while(list->head) {
struct element * temp_head = list->head->next;
free(list->head);
list->head = temp_head;
}
}
void inserthead(struct linked_list * list, int val) {
struct element * new_node = malloc(sizeof(struct element));
new_node->data = val;
struct element * temp_head2 = list->head;
list->head = new_node;
new_node->next = temp_head2;
}
you can create the struct linked_list, that will hold the pointer to the first "link", the first element that is your "object" like in Object Oriented programming.
also don't forget to forward declare your functions if needed!
to create a linked list:
struct linked_list* list = malloc(sizeof(linked_list));
to call functions on it:
inserthead(list, 5);
if you are coming from an oop background, all functions are static, you can think of passing the pointer to the function as calling it like "list.insert()".
I keep getting Segmentation Fault (core dumped) run time error and I can't figure out why.
My code:
struct Node
{
void *next;
void *val;
};
typedef struct Node* NodePtr;
struct List
{
NodePtr head;
};
typedef struct List* ListPtr;
ListPtr create()
{
ListPtr ptr = malloc(sizeof(struct List));
return ptr;
}
int insert(ListPtr list, void *obj)
{
NodePtr newObj = malloc(sizeof(struct Node));
//Cast next as a self referencing Node
newObj->next = (NodePtr) newObj->next;
//Point to beginning of list
NodePtr current = list->head;
if(list->head == NULL)
{
newObj->val = obj;
list->head->next = newObj;
newObj->next = NULL;
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
int x = 2;
int *p = &x;
ListPtr thing = create();
insert(thing, p);
return 0;
}
The error is here: list->head->next = newObj after some debugging. I thought I had to allocate memory for list->head->next, but when I added the code in for that it still gave me the same error. Am I casting it wrong or not allocating memory correctly? Any help would be appreciated, thanks!
Just put this together, runs fine.
#include <stdlib.h>
#include <stdio.h>
struct Node {
void *next;
void *val;
};
typedef struct Node* NodePtr;
struct List {
NodePtr head;
};
typedef struct List* ListPtr;
ListPtr CreateList() {
ListPtr ptr = malloc(sizeof(struct List));
return ptr;
}
void Insert(ListPtr list, void *obj) {
// create and initialize new node
NodePtr newObj = malloc(sizeof(struct Node));
newObj->val = obj;
newObj->next = NULL;
//Point to beginning of list
NodePtr curr = list->head;
// Add node to the list
if(curr == NULL) // if no head node, make newObj the head node
{
list->head = newObj;
}
else{ // otherwise traverse the list until you find the last node (the one that points to a null as the next)
while(1) {
if(curr->next != NULL) {
curr = curr -> next;
} else {
curr->next = newObj;
}
list->head = newObj;
newObj->val = obj;
list->head->next = newObj;
newObj->next = NULL;
}
}
}
int main() {
int x = 2;
int *p = &x;
ListPtr thing = CreateList();
Insert(thing, p);
return 0;
}
You check if list->head is NULL and then do some operations with that. Change that to if(list->head != NULL)
{
...
}
At a thought, malloc does not guarantee allocated memory is empty. It's good practice to set all values where they matter after allocation.
list->head is probably not null
also : newObj->next = (NodePtr) newObj->next;
doesn't set to a rational value, it sets to whatever memory was set - were you intending newObj->next = (NodePtr) newObj; ?
list->head should not be referenced if null. list->head->next will only be valid if it's not null.
if you actually want to build a list,
newObj->val = obj;
if (list->head == NULL) { newObj->next = list->head; }
list->head = newObj;
either that or travel down list->head->next chain until next is null, and set that to be newObj->next. If that way then it's possibly a good idea, newObj->next should be set to NULL and not itself.
Might want to figure out how your list will behave - is it circular? does it grow from the head (list->head) or tail (last ->next) ? Do you spot the tail when listObject->next == NULL or when listObject->next == listObject ?
I realize that this answer is mostly stylistic. But I do think that (bad) style and (bad) habits are an (important) part of (bad) programming. Summing it up ...
(in most cases) typedefs are not needed; they just introduce an alias for something that already existed.
[rule of seven] human readers have a limited amount of identifiers ("names") that they can keep track of. This could be 7. Minimising the number of distinct words makes reading easier.
also, the reader has to remember that xPtr and xNode are related (typeof *xPtr === typeof xNode)
when reading source code, keywords and special character tokens (such as operators) don't count as an identifier, since you do not have to remember them. (Syntax-highligting helps, too)
if there is only one way of expressing your program, there is no possibility for errors like iPtr *p; p = (qPtr) malloc (sizeof xNode);
creating yet another struct (+typedefs for it), just to accomodate a root pointer will clobber up your mental namespace even more.
Now a rework of the (intended) code:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *next;
void *payload;
};
struct node *root=NULL;
void initialize() { /* nothing .... */ }
int insert(struct node **pp, void *pv) {
struct node *p;
p = malloc(sizeof *p);
if (!p) { /* handle error */ return -1; }
p->payload = pv;
p->next = *pp;
*pp = p;
return 1; /* inserted one element */
}
int main(void)
{
int i;
i=666;
/* note: this function call will pass a pointer to a local variable `i`
** to the insert() function, which will remember it.
** This is generally a bad idea, to say the least.
*/
insert( &root, &i);
return 0;
}
Here is a linked list I am working on, and trying to figure out exactly what each line does. The way I seem to be learning how to program is painstakingly difficult, and I am getting extremely discouraged. Regardless, I understand how the link list works, but I am not understanding what the code is saying and what it exactly is doing to create the structs. For example: I can't understand why would you be assigning a pointer to node (13 and 14), especially when my understand of pointers is that they are used to store memory locations.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct numnode
{
int val;
struct numnode * next;
};
typedef struct numnode node;
main()
{
int i;
node * head;
node * newnode;
head = NULL;
for (i = 1; i <= 10; i++)
{
newnode = (node *) malloc(sizeof(node));
newnode->val = i;
newnode->next = NULL;
if (head == NULL)
{
head = newnode;
}
else
{
newnode->next = head;
head = newnode;
}
}
}
Here are some annotations (and minor edits to reduce the amount of code).
/* Linked list node definition */
struct node {
int val;
struct node * next;
};
int main() {
int i;
struct node *head, *new_node;
head = NULL;
for (i = 1; i <= 10; i++) {
// Allocate a new node and initialize its components (val and next)
new_node = (struct node *) malloc(sizeof(node));
new_node->val = i;
new_node->next = NULL;
// The if block is actually not necessary...
if (head == NULL) {
// If the linked list is empty, set the head pointer to the initial node
head = new_node;
} else {
// Now that you have your new node, connect it. Start:
// head->[current linked list]
// [new_node.next]->NULL
new_node->next = head;
// head->[current linked list]->...
// [new_node.next]->[current linked list]->...
head = newnode;
// head->[new_node.next]->[current linked list]->...
}
}
}
The key thing is that malloc returns a pointer to memory. Each new node is allocated dynamically and thus is a location in memory (not a basic type).
If you fix the statement pointed out by PakkuDon you will find that the code inserts at the head. It will end up with a list whose values descend from 9 down to 1.
pointer is just the thing to tell you where is the value,like a phone number,you can call anyone no matter who there is,as you konw the number.pointer can point to anything(under your access) as you want,no matter it is a int or a struct.
Here is the summary of this code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct numnode
{
int val;
struct numnode * next;
};
typedef struct numnode node;
main()
{
int i;
node * head;
node * newnode;
head = NULL;
for (i = 1; i <= 10; i++)
{
newnode = (node *) malloc(sizeof(node));
newnode->val = i;
newnode->next = NULL;
if (head == NULL) // It'll be NULL first time, as head = NULL.
{
// True # i = 1
head = newnode;
}
else // Afterwards, as head=newnode
{
// New node will be created every time. Till i <= 10.
newnode->next = head;
head = newnode;
}
}
}
It is a simple code though.
PS: It is head == NULL