Below is the code that implements List abstraction using both array and circular doubly linked list
/* list .h */
/*
List is an ordered collection of homogenuous type elements(unique or duplicate).
List is not designed to have collection of heterogenuous type elements
All elements in a List are related.
List is mutable
Each element has a position.
If an element is deleted, then still the remaining elements sit in new order.
Array implementation of List
*/
#include<stddef.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
typedef enum{false, true}bool;
typedef enum {CREATE_NEW_LIST, DOUBLE_THE_LIST, HALF_THE_LIST}Op;
#if defined(ARRAY)
typedef struct List{
int *array;
int lastItemPosition;
int size;
}List;
#define INITIAL_LIST_SIZE 50
#elif defined(LINKED_LIST)
typedef struct DListNode{
int item;
struct DListNode *next;
struct DListNode *prev;
}DListNode;
/*
Reason to introduce 'List' type:
Problem 1:
Say, user code has 'x' and 'y' pointing to the same list that is built using 'Node' type.
Some part of user code update list with new item using 'x'
'y' is not in sync with this updation
Node *x = someCreatedList;
Node *y = x;
Node *z = malloc(sizeof(Node));
z->next = x;
x = z; //y misses that reference.
Solution:
Maintain a List type, whose job is to point to head(first node) of the list.
User code will go via reference of List type
Problem 2:
It make sense to have references of 'Node' type pointing to NULL
Applying operation[insertItem()] on NULL pointer will cause runtime errors
Solution:
Run operations over List type because it does not make sense to have reference of SList type pointing to NULL.
To solve problem1 & problem2, here is 'List' type
*/
typedef struct List{ //Circular
DListNode *head;
int size; //size attribute is not part of list definition, but quick way to help user code
}List;
#define SENTINEL_ITEM -1
#else
#error "Wrong list implementation macro name !!!"
#endif
void insertItem(List *, int, int);
void deleteItem(List *, int);
List* createList(List *, Op);
/* linkedListImpl.c */
#if defined(LINKED_LIST)
#include"list.h"
DListNode* createNode(int value){
DListNode *newNode= malloc(sizeof(DListNode));
newNode->next = newNode;
newNode->prev = newNode;
newNode->item = value;
return newNode;
}
List *createList(List *list, Op opType ){
List *lptr = (List *)malloc(sizeof(List));
if(opType == CREATE_NEW_LIST){
/*
Amidst performing operations on 'List', you need to check special cases
for List with no item
To reduce the number of special cases, we designate one node as 'SENTINEL'
After using sentinel, there will be no NULL assignments/check in code.
*/
DListNode *sentinel = createNode(SENTINEL_ITEM);
lptr->head = sentinel;
lptr->size = 0;
return lptr;
}else{
fprintf(stderr, "Invalid flag passed to createList() \n");
return (List *)NULL;
}
}
void insertItem(List *linkedList, int newItem, int index){ //O(n)
DListNode *positionElem = linkedList->head;
bool isFirstElement = true; //assume
if(index + 1 <= linkedList->size){
fprintf(stderr, "Position already filled \n");
return;
}else{
DListNode *newNode = createNode(newItem);
while(index--){
positionElem = positionElem->next;
isFirstElement = false;
}
if(isFirstElement){
newNode->next = positionElem;
positionElem->prev = newNode;
}else{
newNode->next = positionElem->next;
newNode->next->prev = positionElem->next;
}
newNode->prev = positionElem;
positionElem->next = newNode;
}
return;
}
void deleteItem(List *linkedList, int index){
//delete element given index
return;
}
#endif
/* arrayImpl.c */
#if defined(ARRAY)
#include"list.h"
List *createList(List *list, Op opType){
List *lptr = (List *)malloc(sizeof(List));
if(opType == CREATE_NEW_LIST){
lptr->array = malloc(INITIAL_LIST_SIZE*sizeof(int));
lptr->array = memset(lptr->array, -1, INITIAL_LIST_SIZE*sizeof(int));
lptr->lastItemPosition = -1;
lptr->size = INITIAL_LIST_SIZE;
}else if(opType == DOUBLE_THE_LIST){
lptr->array = malloc(2*(list->size)*sizeof(int));
lptr->array = memcpy(lptr->array, list->array, list->size*sizeof(int));
lptr->lastItemPosition = list->lastItemPosition;;
lptr->size = 2*(list->size);
}else if(opType == HALF_THE_LIST){
lptr->array = malloc(((list->size)/2)*sizeof(int));
lptr->array = memcpy(lptr->array, list->array, (list->size/2)*sizeof(int));
lptr->lastItemPosition = list->lastItemPosition;;
lptr->size = (list->size)/2;
}
return lptr;
}
void insertItem(List *arrayList, int newItem, int index){
/* House keeping */
if(arrayList->lastItemPosition + 1 == arrayList->size){
arrayList = createList(arrayList, DOUBLE_THE_LIST);
}
/* Insert the element */
arrayList->array[index] = newItem;
if(index > arrayList->lastItemPosition){
arrayList->lastItemPosition = index;
}
return;
}
void deleteItem(List *arrayList, int index){
arrayList->array[index] = -1;
if(index == arrayList->lastItemPosition){
arrayList->lastItemPosition--;
}
/* House keeping */
if(arrayList->size > INITIAL_LIST_SIZE){
if(arrayList->lastItemPosition == ((arrayList->size)/2)){
arrayList = createList(arrayList, HALF_THE_LIST);
}
}
}
#endif
/* main.c */
#include"list.h"
int main(void){
List *linkedList = (List *)NULL;
linkedList = createList((List *)NULL, CREATE_NEW_LIST);
//List *arrayList = createList(CREATE_NEW_LIST);
if (linkedList == (List *)NULL){
fprintf(stderr, "Unable to createList() \n");
exit(1); //Nothing else to do without linkedList
}
insertItem(linkedList, 1, 0);
}
Compiled as
> gcc -DLINKED_LIST main.c arrayImpl.c linkedListImpl.c
Encapsulation is about maintaining invariants of an ADT List
The following invariants apply to the List with a sentinel.
(1) For any List d, d.head != NULL. (There’s always a sentinel.)
(2) For any DListNode x, x.next != NULL.
(3) For any DListNode x, x.prev != NULL.
(4) For any DListNode x, if x.next == y, then y.prev == x.
(5) For any DListNode x, if x.prev == y, then y.next == x.
(6) A List’s size member is the number of DListNode's, NOT COUNTING the sentinel (pointed by "head"), that can be accessed from the sentinel by a sequence of `next references.
Abstraction is the creation of barrier between representation and usage(user interface)
Question:
O(1) insertion and deletion is possible by providing DListNode node access via insertItem()/deleteItem() user interfacece to user(main.c). But, Encapsulation will be broken due to malfunction by user on that DListNode type node. How to enforce O(1) using linked list?
Related
My code has two separate (although likely connected) problems, one of which being that when I print out the linked list (regardless of if I push nodes to the front or to the back), it prints an additional 0 at the start of the linked list. I saw a similar post about this, but the implementation of the push method was different, as it didn't take head as an argument, so I've defined head in the main() method with:
struct node *head = NULL;
and my linked list instantiation looks like
struct node *temp, *ptr;
temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL) {
exit(0);
}
temp->next=NULL;
if(head==NULL) {
head=temp;
} else {
ptr=head;
while(ptr->next!=NULL) {
ptr=ptr->next;
}
ptr->next=temp;
ptr->data=NULL;
}
The issue I'm having is that I'm not sure whether or not the issue is in the print method, my push front method or my linked list instantiation.
The relevant code is:
case PUSH_FRONT: ; // push onto front of list
struct node *temp1;
temp1=(struct node*)malloc(sizeof(struct node));
if(temp1==NULL) {
break;
}
temp1->next=NULL;
temp1->data=val;
if(head==NULL) {
head=temp1;
} else {
temp1->next=head;
head=temp1;
}
break;
case PRINT_LIST: ; // print list
printf("Elements: ");
struct node *ptr4;
ptr4=(struct node*)malloc(sizeof(struct node));
if(head==NULL) {
break;
} else {
ptr4=head;
while(ptr4) {
printf("%d",ptr4->data);
printf(" ");
ptr4=ptr4->next;
}
printf("\n");
free(ptr4);
}
break;
My other issue (although I'm still convinced that this issue lies elsewhere) is that my pop front method does absolutely nothing, which I'm guessing has to do with the initial instantiation of the linked list. The relevant code is:
case POP_FRONT: ; // remove from front of list
// If list is empty, do nothing.
struct node *ptr2;
ptr2=(struct node *)malloc(sizeof(struct node));
if(ptr2==NULL) {
break;
}
if(head==NULL) {
break;
} else if(head->next==NULL) {
ptr2=head;
head=head->next;
free(ptr2);
}
break;
You should post code someone could download and compile. And when
needed a data file or a description of the problem. Code fragments are
not good.
I believe that the data component of your list is just an int by looking at the code at the label PRINT_LIST
here goes what I think
a list is a collection of nodes. In java a list is even called a collection. In C++ lists are called containers. When you write code for a linked list as if it is a node you will have more work and less results.
as a direct consequence of using a node as a list you have 3 pointers here just to manage the list, in the instantiation code: head, temp and ptr, It is too much. Imagine if there where 3 lists...
a list with pointers only to one direction is harder to program and much less useful than one with pointers to next and previous nodes. If it is your decision may be you should reconsider. If the space of the additional pointer is not a concern, it is hard to justify not to use 2 pointers. Imagine a list for a library, a path,, a playlist, all the classic examples: it is very handful to be able to navigate in both directions.
the use of a switch() is uncommon. Why not just use functions?
back to your code
struct node *temp, *ptr;
temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL) {
exit(0);
}
temp->next=NULL;
if(head==NULL) {
head=temp;
} else {
ptr=head;
while(ptr->next!=NULL) {
ptr=ptr->next;
}
ptr->next=temp;
ptr->data=NULL;
}
here you write ptr->data = NULL; and we may think that data is a pointer, but in the list label you wrote
ptr4=head;
while(ptr4) {
printf("%d",ptr4->data);
printf(" ");
ptr4=ptr4->next;
}
printf("\n");
free(ptr4);
and data is just an int as you are using %d in the printf(). Well, the NULL in instantiation is, well, a zero.
And that NULL is the 0 you are complaining about.
This code seems to be much more complex and hard to read than it may need to be.
Let me show an alternative
about the declaration
You may write the node struct like
typedef struct _nd
{
int data;
struct _nd* next;
} node;
So you can use node in the declaration and not have to repeat struct at all times. Also it is useful to have a convention for typedef, like using first letter uppercase to help in readability
As I said before a list is a collection of nodes, it is NOT just a node --- with a pointer inside --- and each node has a payload, some data, usually a pointer. As an example consider
an alternate example of list structs
typedef struct _nda
{
int data;
struct _nda* next;
} Node;
struct _the_list
{
char* name;
unsigned size;
unsigned limit;
Node* head;
Node* tail;
};
typedef struct _the_list List;
Here the list is, well, List. And each list has head, tail, size, limit and even a name. I kept data as an int but is is not good: you really want it as a pointer, maybe (void*).
Why? Because in this way you can reuse the code everywhere with no change.
How to use a List like this?
Using functions like these possible prototypes
List* _create(const char*);
int _define_max(List* l, const unsigned);
List* _delete(List*);
int _empty(List*);
int _get_max(List*);
List* _insert_begin(int, List*);
List* _insert_end(int, List*);
int _insert_your_way(List*, int(*)(int,int));
int _print(List*);
int _print_your_way(List*, int(*)(int,int));
List* _remove(int, List*);
int _size(List*);
I will post a running example below just to have something you can test or ask about case you need. But it is the usual. Only these two functions are less usual, but more useful:
int _insert_your_way(List*, int(*F)(int,int));
int _print_your_way(List*, int(*F)(int,int));
Here you can pass a function like in the qsort() function, and the node is inserted at the position, using the function F() to compare the nodes. The effect is that you can have the nodes inserted (or listed) in any order, with no change in the list code, just by providing different functions to the print or insert function. C does that, C++ does that, everybody does that, so we can too :)
code for instantiating such a list
List* _create(const char* name)
{
List* one = (List*)malloc(sizeof(List));
one->name = (char*)malloc(1 + strlen(name));
strcpy(one->name, name);
one->size = 0;
one->limit = 0;
one->head = NULL;
one->tail = NULL;
return one;
}; // criar()
You may find that writing this way makes easier to maintain or read the code. And the List as a container is much more expressive: metadata about the list in included in the list. No need for ptr, head, temp, size or other controls hanging loose in main()
To create a list you can just write, like in the example
List* first = _create("The First List");
inserting nodes at the beggining
List* _insert_begin(int value, List* l)
{
if (l == NULL) return l; //no list
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and stuff data in
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value; // data comes in
nd->next = l->head; // depois vem o que estava na frente
l->head = nd; // nd fim
l->size = l->size + 1;
// if it is the first node
if (l->size == 1)l->tail = nd;
return l;
};
As I told you this is just a toy, an example. In practice you will use a void* in order to have a generic code. I am using an int as data here, as you did. To insert a few nodes in the list created above you just write
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
And you can have even an array of lists and all goes well. No external variables to look after. And each list has size updated, head, tail...
printing nodes
print is also easy and can be more expressive, since we have metadata with limits, size, head, tail and even the name for each list.
sample program
int main(void)
{
List* first = _create("The First List");
_print(first);
_define_max(first,300);
_print(first);
// insert 5,4,3,2,1 at the beggining
for(int i = 5; i>0; i-=1 ) _insert_begin(i, first);
// list again
_print(first);
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
// list again
_print(first);
printf("empty(): %d size()= %d\n",
_empty(first),
_size(first) );
first = _delete(first);
_print(first);
return 0;
}
This code just
create a list and prints the nodes
set the optional limit to 300 nodes
list the nodes
insert 5,4,3,2,1 at the beginning
list the nodes
insert 6,7,8,9,10 at the tail
list the nodes
call a few functions on the list
deletes all data
output
List 'The First List' with 0 elements [MAX not defined yet]
List 'The First List' with 0 of 300 MAX elements
List 'The First List' with 5 of 300 MAX elements
First: 1
Last: 5
Elements
1
2
3
4
5
End of list
List 'The First List' with 10 of 300 MAX elements
First: 1
Last: 10
Elements
1
2
3
4
5
6
7
8
9
10
End of list
empty(): 0 size()= 10
Deleting 'The First List'
List not created!
the code (with almost no testing)
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct _nda
{
int data;
struct _nda* next;
} Node;
struct _the_list
{
char* name;
unsigned size;
unsigned limit;
Node* head;
Node* tail;
};
typedef struct _the_list List;
List* _create(const char*);
int _define_max(List* l, const unsigned);
List* _delete(List*);
int _empty(List*);
int _get_max(List*);
List* _insert_begin(int, List*);
List* _insert_end(int, List*);
int _insert_your_way(List*, int(*)(void*));
int _print(List*);
int _print_your_way(List*, int(*)(void*));
List* _remove(int, List*);
int _size(List*);
int main(void)
{
List* first = _create("The First List");
_print(first);
_define_max(first,300);
_print(first);
// insert 5,4,3,2,1 at the beggining
for(int i = 5; i>0; i-=1 ) _insert_begin(i, first);
// list again
_print(first);
// insert 6,7,8,9,10 at the end
for(int i = 6; i<11; i+=1 ) _insert_end(i, first);
// list again
_print(first);
printf("empty(): %d size()= %d\n",
_empty(first),
_size(first) );
first = _delete(first);
_print(first);
return 0;
}
List* _create(const char* name)
{
List* one = (List*)malloc(sizeof(List));
one->name = (char*)malloc(1 + strlen(name));
strcpy(one->name, name);
one->size = 0;
one->limit = 0;
one->head = NULL;
one->tail = NULL;
return one;
}; // criar()
int _define_max(List* l, const unsigned m)
{
if (l == NULL) return -1;
// new value can not be less than present size
if (l->size > m) return -2;
l->limit = m;
return m;
};
List* _delete(List* l)
{
if (l == NULL) return NULL;
printf("Deleting '%s'\n", l->name);
free(l->name);
if (l->size == 0)
{
free(l);
return NULL; // empty
}; // if()
Node* node = l->head;
do
{
Node* p = node->next;
free(node);
node = p;
} while (node != NULL);
return NULL;
};
int _empty(List* L)
{
if (L == NULL) return -1;
return (L->size == 0);
};
int _get_max(List* L)
{
if (L == NULL) return -1;
return (int)L->limit;
};
List* _insert_begin(int value, List* l)
{
if (l == NULL) return l; //no list
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and stuff data in
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value; // data comes in
nd->next = l->head; // depois vem o que estava na frente
l->head = nd; // nd fim
l->size = l->size + 1;
// if it is the first node
if (l->size == 1)l->tail = nd;
return l;
};
List* _insert_end(int value, List* l)
{
if (l == NULL) return l;
if ((l->limit > 0) && (l->size == l->limit)) return l; // full
// ok: create a node and insert at the end
Node* nd = (Node*)malloc(sizeof(Node));
nd->data = value;
// first one?
if (l->size == 0)
{
l->head = nd;
nd->next = NULL;
}
else
{
nd->next = NULL; // no one after this
(l->tail)->next = nd;
}; // if()
l->tail = nd; // nd is tail now
l->size = l->size + 1;
// of this is the first node
if (l->size == 1)l->head = nd;
return l;
};
int _insert_your_way(List* L, int(*F)(void*))
{
return 0;
};
int _print(List* l)
{
if (l == NULL)
{
printf("List not created!\n");
return -1;
};
if (l->limit > 0)
{
printf("\nList '%s' with %d of %d MAX elements\n",
l->name,
l->size,
l->limit
);
}
else
{
printf("\nList '%s' with %d elements [MAX not defined yet]\n",
l->name,
l->size
);
}
if (l->size < 1) return 0;
// assume data as just an int
Node* p = l->head;
printf("\n First:%10d\n", l->head->data);
printf(" Last:%10d\n", l->tail->data);
printf("\nElements\n\n");
do
{
printf("%10d \n", p->data);
p = p->next;
} while (p != NULL);
printf("\nEnd of list\n\n");
return 0;
}; // _print()
int _print_your_way(List* L, int(*F)(void*))
{
return 0;
};
List* _remove(int value, List* L)
{
return NULL;
};
int _size(List* L)
{
if (L == NULL) return -1;
return (int)L->size;
};
It was extracted for a larger example, for WIndows. Compiled just under gcc 9.3 on Ubuntu on Windows WSL
I'm currently doing an assignment for uni and I need to find the sum of a graph.
To do this I believe I need a linked list that I can use to remember which nodes have been visited. I have the linkedlist working correctly but I can't get a contains function to work. This is the code I have:
struct listnode
{
struct N *val;
struct listnode *next;
};
int contains(struct listnode *head,struct N* value)
{
struct listnode *current = head;
while (current)
{
if ((current -> val) == value)
{
return 1;
}
current = current -> next;
}
return 0;
}
note: N is a node of the graph.
Can anyone see any problems with what I'm doing?
EDIT: contains function should return 1 when N *value is in the list, 0 otherwise
EDIT2:
I have a push function:
void push(struct listnode *head,struct N *value)
{
if (head)
{
struct listnode *current = head;
while (current->next)
{
current = current -> next;
}
current->next = malloc(sizeof(struct listnode*));
current->next->val = value;
current->next->next = NULL;
}
else
{
head = malloc(sizeof(struct listnode*));
if (head)
{
head -> val = value;
head -> next = NULL;
}
else
{
printf("error");
exit(0);
}
}
}
and I want the following line to return 1:
contains(push(visited,p),p);
where p is a pointer to a struct N and visited is my global linked list
EDIT3:
this is my final sum function that I believe should work, but doesnt because of contains.
long sum(struct N *p)
{
if (p)
{
if (contains(visited,p) == 0) //if p hasnt been visited
{
push(visited,p); //make it visited
return (p -> data) + sum(p -> x) + sum(p -> y) + sum(p -> z);
}
else
{
return 0;
}
}
else
{
return 0;
}
}
Your contains function appears to be fine. The issue is that you are always passing a NULL list to it, which is caused by a faulty push function. You need a return in push, or to pass in a pointer with one more level of indirection, so you can assign to head outside of push. One more possible improvement is to notice that no matter what you pass in, the malloc and initialization of a new node is actually the same.
Finally, the main issue, that is really the most likely to cause a segfault is the fact that you are allocating enough space for a pointer to a node, not for the node itself.
Here is an example:
#ifdef BY_INDIRECTION
#define RET_TYPE void
#define IN_TYPE struct listnode **
#else
#define RET_TYPE struct listnode *
#define IN_TYPE struct listnode *
#endif
RET_TYPE push(IN_TYPE head, struct N *value)
{
struct listnode *current, **next;
if(head)
{
for(current = head; current->next; current = current->next) ;
next = &(current->next);
}
else
{
#ifdef BY_INDIRECTION
next = head;
#else
next = &head;
#endif
}
*next = malloc(sizeof(struct listnode));
if(!*next) {
printf("error");
exit(0);
}
(*next)->val = value;
(*next)->next = NULL;
#ifndef BY_INDIRECTION
return head
#endif
}
I have included both suggestions here. If you want to read the one where we use indirection (pass in a listnode ** and have void return), choose the path where BY_INDIRECTION is defined. If you want to have head returned (and pass in just a regular listnode *) read the path where BY_INDIRECTION is not defined.
The latter approach has a return value, so it can be used to write a shortened form like if(contains(push(head, value), value)) { ... }. The former approach does not, so you would have to do
push(&head, value);
if(contains(head, value)) { ... }
I would recommend using the indirect approach regardless because there are very few instances that you would want to check for containment after putting in a value.
This comparison:
if ((current -> val) == value)
it's comparing pointers. If you call your contains() function this way...
...
struct N val_to_find;
...
result = contains (list, &val_to_find);
You will never find the value, even if the contents of val_to_find are the same as the contents of any struct whose pointer is stored in the list.
If your intention for contains() is to find nodes that have the same data, and not just the same pointers, I'd suggest you something like this:
if (struct_n_comparing_function (current -> val, value) == EQUAL) ...
Where struct_n_comparing_function should have the following prototype:
int struct_n_comparing_function (struct N *a, struct N *b);
which compares the contents of the two structs pointed by a and b and return EQUAL if all the fields of the struct pointed by a have the same value as the fields of struct pointed by b.
Below is the code,
/****** list.h **********/
#include<stddef.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
/***************** Usage-start ************/
typedef enum{false, true}bool;
typedef enum {CREATE_NEW_LIST, DOUBLE_THE_LIST, HALF_THE_LIST}Op;
#if defined(ARRAY)
/* To ensure Encapsulation(i.e., maintain invariants of array) */
typedef struct List List;
#elif defined(LINKED_LIST)
/* To ensure Encapsulation(i.e., maintain invariants of linked list) */
/* User will not get access to node*/
typedef struct List List;
#else
#error "Wrong list implementation macro name !!!"
#endif
void insertItem(List *, void *newItem);
void *deleteItem(List *, int listIndex);
List* createList(List *, Op opType);
/************* arrayImpl.c ***********/
#include"list.h"
/************ Representation - start ************/
typedef struct List{
void **array;
/* Following members for Housekeeping - Array enhancement*/
int lastItemPosition;
int size;
}List;
#define INITIAL_LIST_SIZE 50
List *createList(List *list, Op opType){
if(opType == CREATE_NEW_LIST){
list = malloc(sizeof(List));
list->array = malloc(INITIAL_LIST_SIZE*sizeof(void*));
/* Is it safe to initialise zero to array of pointers? */
list->array = memset(list->array, 0, INITIAL_LIST_SIZE*sizeof(void *));
list->lastItemPosition = -1;
list->size = INITIAL_LIST_SIZE;
}else if(opType == DOUBLE_THE_LIST){
list->array = realloc(list->array, 2*(list->size)*sizeof(void *));
list->lastItemPosition = list->lastItemPosition;;
list->size = 2*(list->size);
}else if(opType == HALF_THE_LIST){
list->array = realloc(list->array, ((list->size)/2)*sizeof(void *));
list->lastItemPosition = list->lastItemPosition;
list->size = (list->size)/2;
}
return list;
}
/********** arrayImpl.c*********/
void *deleteItem(List *arrayList, int listIndex){
void *returnElement; //Deep copy before freeing the object
free(arrayList->array[listIndex]);
/* Delete operation - O(n) operation */
for(int accumulator = listIndex; accumulator <= arrayList->lastItemPosition; accumulator++){
arrayList->array[accumulator] = arrayList->array[++accumulator];
}
arrayList->lastItemPosition--;
/* House keeping - Half the list */
if(arrayList->size > INITIAL_LIST_SIZE){ /* Minimum size maintained */
if((arrayList->lastItemPosition + 1) == ((arrayList->size)/2)){
arrayList = createList(arrayList, HALF_THE_LIST);
}
}
return returnElement;
}
/***************arrayImpl.c***************/
void insertItem(List *arrayList, void *newItem){
/* House keeping - Enhance the array */
if(arrayList->lastItemPosition + 1 == arrayList->size){
arrayList = createList(arrayList, DOUBLE_THE_LIST);
}
/* Insert new element - O(1) operation */
arrayList->array[++(arrayList->lastItemPosition)] = newItem;
return;
}
User code,
#include"list.h"
int main(void){
List *arrayList = createList((List *)NULL, CREATE_NEW_LIST);
if (arrayList == (List *)0){
fprintf(stderr, "Unable to create list \n");
exit(1); //Nothing else to do without arrayList
}
// Objects should only be on heap
int *object1 = malloc(sizeof(int));
*object1 = 777;
insertItem(arrayList, object1);
int *object2 = malloc(sizeof(int));
*object2 = 888;
insertItem(arrayList, object2);
object1 = deleteItem(arrayList, 0);
}
I want to re-use List abstraction for writing Stack abstraction, as shown below with push()/pop()
#include"../list/list.h"
typedef struct Stack{
List *stack;
}Stack;
Question:
In deleteItem() function, how to deep copy arrayList->array[listIndex] and return returnElement from deleteItem() function?
pop() would be calling deleteItem()
Note: Compilation >gcc -DARRAY main.c arrayImpl.c
insertItem didn't allocate an item - so deleteItem shouldn't free it.
void *deleteItem(List *arrayList, int listIndex){
void *returnElement = arrayList->array[listIndex];
/* Delete operation - O(n) operation */
....
/* House keeping - Half the list */
....
return returnElement;
}
I've been trying to teach myself c over spring break and it's been a lot more challenging than i had anticipated! I've made some good progress, however i seem to have hit a snag. I've been writing my own implementation of a doubly linked list. After about eight hours of plugging along, I've got what seems to be a fairly coherent program. The compiler is giving me the all clear ahead, and i've successfully built the project multiple times. Now, i started programming in java; so to my mind the aforementioned assurances constitute an ironclad guarantee of success. However C seems to c things differently (pardon the pun)! When i attempt to run my program, i get a 'segfault' run-time error. I've spent some time reading up on this error, and (as im sure i'm about to be informed) it's an issue of memory mis-allocation. I've tried to debug, but no matter where i set my breakpoints i cant seem to preempt the error. I'm in a bit of a quandry, and i'd really appreciate any insights y'all might have to offer me! I apologize for the monolith of text i've just scrawled out... and i'll try to keep the post script brief. Here's a rough outline of my setup:
NetBeans 6.8 IDE with Cygwin environment
Currently running windows 7 x64
I'll post my code below, but certainly don't feel obligated to go sifting through it. What i'm really hoping for is a few suggestions on how to handle segfaults in general. I get the feeling i'll be seeing them a lot, and i'd like to develop a strategy for troubleshooting this particular issue.
Thanks in advance! without you guys i'd be up a serious creek!
main.c
#include <stdlib.h>
#include <stdbool.h>
#include"dll.h"
int main(int argc, char** argv) {
VECT coord1;
coord1->x = 0.0012345;
coord1->y = 0.012345;
coord1->z = 0.12345;
LIST coords = init_list();
list_add(coords, coord1);
return (EXIT_SUCCESS);
}
dll.c (doubley linked list source file)
#include "dll.h"
#include <stdlib.h>
#include <string.h>
#include<stdbool.h>
#include"dll.h"
LIST init_list() {
LIST list = (LIST) malloc(sizeof (struct list));
list->length = 0;
list->first = NULL;
list->last = NULL;
list->destructor = free;
return list;
}
LIST_ITR list_iterator(LIST list, bool from_front) {
LIST_ITR iter = (LIST_ITR) malloc(sizeof (struct list_itr));
if (from_front) {
iter->current = list->first;
} else if (!from_front) {
iter->current = list->last;
} else return NULL;
iter->started = 0;
return iter;
}
void list_add(LIST list, VECT coords) {
NODE node = (NODE) malloc(sizeof (struct node));
node->coord_vector = coords;
if (list->first == NULL) {
node->prev = NULL;
node->next = NULL;
list->first = node;
list->last = node;
} else {
list->last->next = node;
node->prev = list->last;
node->next = NULL;
list->last = node;
}
list->length++;
}
VECT list_itr_current(LIST_ITR iter) {
if (iter->started && iter->current != NULL)
return iter->current->coord_vector;
else {
return NULL;
}
}
VECT list_itr_next(LIST_ITR iter) {
if (!iter->started && iter->current != NULL) {
iter->started = 1;
return iter->current->coord_vector;
}
if (iter->current != NULL) {
iter->current = iter->current->next;
return list_itr_current(iter);
}
return NULL;
}
VECT list_prev(LIST_ITR iter) {
if (!iter->started && iter->current != NULL) {
iter->started = 1;
return iter->current->coord_vector;
}
if (iter->current != NULL) {
iter->current = iter->current->prev;
return list_itr_current(iter);
}
return NULL;
}
VECT list_get_first(LIST list) {
return list->first->coord_vector;
}
VECT list_get_last(LIST list) {
return list->last->coord_vector;
}
VECT list_pop(LIST list) {
NODE last = list->last;
if (last == NULL) return NULL;
if (list->first == list->last) {
list->first = NULL;
list->last = NULL;
} else {
list->last = last->prev;
last->prev->next = NULL;
}
VECT data = last->coord_vector;
free(last);
list->length--;
return data;
}
VECT list_poll(LIST list) {
NODE first = list->first;
if (first == NULL)
return NULL;
if (list->first == list->last) {
list->first = NULL;
list->last = NULL;
} else {
list->first = first->next;
first->next->prev = NULL;
}
VECT data = first->coord_vector;
free(first);
list->length--;
return data;
}
void list_remove(LIST list, bool from_front) {
VECT data;
if (from_front)
data = list_poll(list);
else if (!from_front)
data = list_pop(list);
else return;
list->destructor(data);
}
void destroy_list(LIST list) {
NODE current = list->first;
NODE next;
while (current != NULL) {
next = current->next;
list->destructor(current->coord_vector);
free(current);
current = next;
}
free(list);
}
dll.h (doubley linked list header file)
#include<stdbool.h>
#ifndef _DLL_H
#define _DLL_H
#ifdef __cplusplus
extern "C" {
#endif
/* A C implementation of a doubly-linked list. Contains void pointer values.
Can be used as a LIFO stack of FIFO queue. */
#define FRONT 0
#define BACK 1
struct vector{
double x;
double y;
double z;
};
typedef struct vector* VECT;
struct node{
VECT coord_vector;
struct node* next;
struct node* prev;
};
typedef struct node* NODE;
struct list{
int length;
NODE first;
NODE last;
void (*destructor)(void*);
};
typedef struct list * LIST;
struct list_itr{
NODE current;
char started;
};
typedef struct list_itr * LIST_ITR;
//Initializes the list
LIST init_list();
//initializes the list iterator
LIST_ITR list_iterator(LIST list, bool from_front);
//append element to end
void list_add(LIST list, VECT coords);
//Gets the data stored in the first item of the list or NULL if the list is empty
VECT list_get_first(LIST list);
//Gets the data stored in the last item of the list or NULL if the list is empty
VECT list_get_last(LIST list);
//LIFO pop: remove element and return data
VECT list_pop(LIST list);
//FIFO poll: remove element and return data
VECT list_poll(LIST list);
//Deletes element and frees memory
void list_remove(LIST list, bool from_front);
//Delete list and free all memory
void destroy_list(LIST list);
//returns the data of the element pointed to by current
VECT list_itr_current(LIST_ITR list_itr);
//Increments the index of current by 1 and returns the data stored there
VECT list_itr_next(LIST_ITR list_itr);
//Decrements the index of current by 1 and returns the data stored there
VECT list_prev(LIST_ITR list_itr);
#ifdef __cplusplus
}
#endif
#endif /* _DLL_H */
You should build your code with -Wall flag to compiler. At compile time it will then print:
main.c:9:15: warning: ‘coord1’ is used uninitialized in this function [-Wuninitialized]
This points you to the problem.
coord1 is a pointer type, that you assign to, but coord1 has no memory backing it until it is initialized. In the following snippet coord1 is initialized by allocating memory to store it's components. This gets rid of the segfault.
VECT coord1 = NULL;
coord1 = (VECT)malloc(sizeof(struct vector));
if (NULL == coord1)
{
fprintf(stderr, "Out of memory!\n");
exit(1);
}
coord1->x = 0.0012345;
coord1->y = 0.012345;
coord1->z = 0.12345;
In general, segfaults happen when a program accesses memory that the operating system has not allocated to it. Unintialized pointers usually point to address zero, which is not allocated to any program. Always use gcc -Wall when compiling, this will many times point to these potential problems. Helped me find it right away.
Also, you could have declared your VECT type to be typedef struct vector (a non-pointer type).
VECT coord1;
VECT* v_coord1 = &coord1;
v_coord1->x = 0.0012345;
v_coord1->y = 0.012345;
v_coord1->z = 0.12345;`
Also, variable naming conventions can help here as well.
struct vector{
double x;
double y;
double z;
};
typedef struct vector VECT;
typedef struct vector* pVECT;
I am creating a linked list as in the previous question I asked. I have found that the best way to develop the linked list is to have the head and tail in another structure. My products struct will be nested inside this structure. And I should be passing the list to the function for adding and deleting. I find this concept confusing.
I have implemented the initialize, add, and clean_up. However, I am not sure that I have done that correctly.
When I add a product to the list I declare some memory using calloc. But I am thinking shouldn't I be declaring the memory for the product instead. I am really confused about this adding.
Many thanks for any suggestions,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 128
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct product_data_t *next;
}product_data_t;
typedef struct list
{
product_data_t *head;
product_data_t *tail;
}list_t;
void add(list_t *list, int code, char name[], int cost);
void initialize(list_t *list);
void clean_up(list_t *list);
int main(void)
{
list_t *list = NULL;
initialize(list);
add(list, 10, "Dell Inspiron", 1500);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
// Allocate memory for the new product
list = calloc(1, sizeof(list_t));
if(!list)
{
fprintf(stderr, "Cannot allocated memory");
exit(1);
}
if(list)
{
// First item to add to the list
list->head->product_code = code;
list->head->product_cost = cost;
strncpy(list->head->product_name, name, sizeof(list->head->product_name));
// Terminate the string
list->head->product_name[127] = '/0';
}
}
// Initialize linked list
void initialize(list_t *list)
{
// Set list node to null
list = NULL;
list = NULL;
}
// Release all resources
void clean_up(list_t *list)
{
list_t *temp = NULL;
while(list)
{
temp = list->head;
list->head = list->head->next;
free(temp);
}
list = NULL;
list = NULL;
temp = NULL;
}
============================== Edited ============================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 64
// typedef struct product_data product_data_t;
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
}product_data_t;
typedef struct list
{
struct list *head;
struct list *tail;
struct list *next;
struct list *current_node;
product_data_t *data;
}list_t;
void add(list_t *list, int code, char name[], int cost);
int main(void)
{
list_t *list = NULL;
list = initialize(list);
add(list, 1001, "Dell Inspiron 2.66", 1299);
add(list, 1002, "Macbook Pro 2.66", 1499);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
/* Allocate memory for the new product */
product_data_t *product = (product_data_t*) calloc(1, sizeof(*product));
if(!product)
{
fprintf(stderr, "Cannot allocate memory.");
exit(1);
}
/* This is the first item in the list */
product->product_code = code;
product->product_cost = cost;
strncpy(product->product_name, name, sizeof(product->product_name));
product->product_name[PRODUCT_NAME_LEN - 1] = '\0';
if(!list->head)
{
/* Assign the address of the product. */
list = (list_t*) product;
/* Set the head and tail to this product */
list->head = (list_t*) product;
list->tail = (list_t*) product;
}
else
{
/* Append to the tail of the list. */
list->tail->next = (list_t*) product;
list->tail = (list_t*) product;
}
/* Assign the address of the product to the data on the list. */
list->data = (list_t*) product;
}
If you are looking to better understand the basics of linked lists, take a look at the following document:
http://cslibrary.stanford.edu/103/LinkedListBasics.pdf
Arguably you want your list data structure to be external to the data that it stores.
Say you have:
struct Whatever
{
int x_;
}
Then your list structure would look like this:
struct Whatever_Node
{
Whatever_Node* next_
Whatever* data_
}
Ryan Oberoi commented similarly, but w/o example.
In your case the head and tail could simply point to the beginning and end of a linked-list. With a singly linked-list, only the head is really needed. At it's most basic, a linked-list can be made by using just a struct like:
typedef struct listnode
{
//some data
struct listnode *next;
}listnodeT;
listnodeT *list;
listnodeT *current_node;
list = (listnodeT*)malloc(sizeof(listnodeT));
current_node = list;
and as long as list is always pointing to the beginning of the list and the last item has next set to NULL, you're fine and can use current_node to traverse the list. But sometimes to make traversing the list easier and to store any other data about the list, a head and tail token are used, and wrapped into their own structure, like you have done. So then your add and initialize functions would be something like (minus error detection)
// Initialize linked list
void initialize(list_t *list)
{
list->head = NULL;
list->tail = NULL;
}
void add(list_t *list, int code, char name[], int cost)
{
// set up the new node
product_data_t *node = (product_data_t*)malloc(sizeof(product_data_t));
node->code = code;
node->cost = cost;
strncpy(node->product_name, name, sizeof(node->product_name));
node->next = NULL;
if(list->head == NULL){ // if this is the first node, gotta point head to it
list->head = node;
list->tail = node; // for the first node, head and tail point to the same node
}else{
tail->next = node; // append the node
tail = node; // point the tail at the end
}
}
In this case, since it's a singly linked-list, the tail is only really useful for appending items to the list. To insert an item, you'll have to traverse the list starting at the head. Where the tail really comes in handy is with a doubly-linked list, it allows you to traverse the list starting at either end. You can traverse this list like
// return a pointer to element with product code
product_data_t* seek(list_t *list, int code){
product_data_t* iter = list->head;
while(iter != NULL)
if(iter->code == code)
return iter;
iter = iter->next;
}
return NULL; // element with code doesn't exist
}
Often times, the head and tail are fully constructed nodes themselves used as a sentinel to denote the beginning and end of a list. They don't store data themselves (well rather, their data represent a sentinel token), they are just place holders for the front and back. This can make it easier to code some algorithms dealing with linked lists at the expense of having to have two extra elements. Overall, linked lists are flexible data structures with several ways to implement them.
oh yeah, and nik is right, playing with linked-lists are a great way to get good with pointers and indirection. And they are also a great way to practice recursion too! After you have gotten good with linked-list, try building a tree next and use recursion to walk the tree.
I am not writing the code here but you need to do the following:
Create and object of list, this will remain global for the length of program.
Malloc the size of product _ data _ t.
For first element (head is NULL), point head to the malloced' address.
To add next element, move to the end of list and then add the pointer of malloced address to next of last element. (The next of the last element will always be NULL, so thats how you traverse to end.)
Forget tail for a while.
If you are learning C pointer theory this is a good exercise.
Otherwise, it feels like too much indirection for code that is not generic (as in a library).
Instead of allocating a static 128 byte character string, you might want to do some more pointer practice and use an allocated exact length string that you clean up at exit.
Academically, kungfucraigs' structure looks more generic then the one you have defined.
You're calloc'ing space for your list_t struct, just pointers to list head and tail, which isn't what you want to do.
When you add to a linked list, allocate space for an actual node in the list, which is your product_data_t struct.
You're allocating the wrong chunk of memory. Instead of allocating memory for each list element, you're allocating for the list head and tail.
For simplicity, get rid of the separate structure for the head and tail. Make them global variables (the same scope they're in now) and change them to be listhead and listtail. This will make the code much more readable (you won't be needlessly going through a separate structure) and you won't make the mistake of allocating for the wrong struct.
You don't need a tail pointer unless you're going to make a doubly linked list. Its not a major element to add once you create a linked list, but not necessary either.
In memory your items are linked by pointers in the list structure
item1 -> item2
Why not make the list structure part of your item?
Then you allocate a product item, and the list structure is within it.
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct list_t list; // contains the pointers to other product data in the list
}product_data_t;
I think u first need to Imagin back-end. Code are nothing to important. Go here and visualize back-end basic c code of all insertion.
1) Insertion at beginning Visit and scroll to get every instruction execution on back- end
And u need front and imagin Go here
Back end imagin
And All other possible insertion here.
And important thing u can use this way.
struct Node{
int data;//data field
struct Node*next;//pointer field
};
struct Node*head,*tail; // try this way
or short cut
struct Node{
int data;//data field
struct Node*next;//pointer field
}*head,*tail; //global root pointer
And << Click >> To visualize other linked list problem.
Thanks.
A demo for Singly Linked List. If you prefer, try to check Circular Linked List and Doubly Linked List.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node * next;
} node_t;
// Iterating over a list
void
print_list(node_t *head)
{
node_t *current = head;
while(current != NULL)
{
printf("%d\n", current->val);
current = current->next;
}
}
// Adding an item to the end of the list
void
push_end(node_t *head, int val)
{
node_t *current = head;
while (current->next != NULL)
{
current = current->next;
}
current->next = malloc(sizeof(node_t));
current->next->val = val;
current->next->next = NULL;
}
// Adding an item to the head of the list
void
push_head(node_t **head, int val)
{
node_t *new_node = NULL;
new_node = malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head;
*head = new_node;
}
// Removing the head item of the list
int
pop_head(node_t **head)
{
int retval = -1;
node_t *next_node = NULL;
if (*head == NULL) {
return -1;
}
next_node = (*head)->next;
retval = (*head)->val;
free(*head);
*head = next_node;
return retval;
}
// Removing the last item of the list
int
pop_last(node_t *head)
{
int retval = 0;
node_t *current = NULL;
if (head->next == NULL) {
retval = head->val;
free(head);
return retval;
}
/* get to the second to last node in the list */
current = head;
while (current->next->next != NULL) {
current = current->next;
}
/* now current points to the second to last item of the list.
so let's remove current->next */
retval = current->next->val;
free(current->next);
current->next = NULL;
return retval;
}
// Removing a specific item
int
remove_by_index(node_t **head, int n)
{
int i = 0;
int retval = -1;
node_t *current = *head;
node_t *temp_node = NULL;
if (n == 0) {
return pop_head(head);
}
for (i = 0; i < n - 1; i++) {
if (current->next == NULL) {
return -1;
}
current = current->next;
}
temp_node = current->next;
retval = temp_node->val;
current->next = temp_node->next;
free(temp_node);
return retval;
}
int
main(int argc, const char *argv[])
{
int i;
node_t * testnode;
for (i = 0; i < argc; i++)
{
push_head(&testnode, atoi(argv[i]));
}
print_list(testnode);
return 0;
}
// http://www.learn-c.org/en/Linked_lists
// https://www.geeksforgeeks.org/data-structures/linked-list/
The linked list implementation inspired by the implementation used in the Linux kernel:
// for 'offsetof', see: https://stackoverflow.com/q/6433339/5447906.
#include <stddef.h>
// See: https://stackoverflow.com/q/10269685/5447906.
#define CONTAINER_OF(ptr, type, member) \
( (type *) ((char *)(ptr) - offsetof(type, member)) )
// The macro can't be used for list head.
#define LIST_DATA(ptr, type, member) \
CONTAINER_OF(ptr, type, member);
// The struct is used for both: list head and list nodes.
typedef struct list_node
{
struct list_node *prev, *next;
}
list_node;
// List heads must be initialized by this function.
// Using the function for list nodes is not required.
static inline void list_head_init(list_node *node)
{
node->prev = node->next = node;
}
// The helper function, mustn't be used directly.
static inline void list_add_helper(list_node *prev, list_node *next, list_node *nnew)
{
next->prev = nnew;
nnew->next = next;
nnew->prev = prev;
prev->next = nnew;
}
// 'node' must be a list head or a part of a list.
// 'nnew' must not be a list head or a part of a list. It may
// be uninitialized or contain any data (even garbage).
static inline void list_add_after(list_node *node, list_node *nnew)
{
list_add_helper(node, node->next, nnew);
}
// 'node' must be a list head or a part of a list.
// 'nnew' must not be a list head or a part of a list. It may
// be uninitialized or contain any data (even garbage).
static inline void list_add_before(list_node *node, list_node *nnew)
{
list_add_helper(node->prev, node, nnew);
}
// 'node' must be part of a list.
static inline list_node *list_del(list_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
return node->prev;
}
Example of usage:
#include <stdio.h>
// The struct must contain 'list_node' to be able to be inserted to a list
typedef struct
{
int data;
list_node node;
}
my_struct;
// Convert 'list_node *' to 'my_struct*' that contains this 'list_node'
static inline my_struct* get_my_struct(list_node *node_ptr)
{
return LIST_DATA(node_ptr, my_struct, node);
}
void print_my_list(list_node *head)
{
printf("list: {");
for (list_node *cur = head->next; cur != head; cur = cur->next)
{
my_struct *my = get_my_struct(cur);
printf(" %d", my->data);
}
printf(" }\n");
}
// Print 'cmd' and run it. Note: newline is not printed.
#define TRACE(cmd) \
(printf("%s -> ", #cmd), (cmd))
int main()
{
// The head of the list and the list itself. It doesn't contain any data.
list_node head;
list_head_init(&head);
// The list's nodes, contain 'int' data in 'data' member of 'my_struct'
my_struct el1 = {1};
my_struct el2 = {2};
my_struct el3 = {3};
print_my_list(&head); // print initial state of the list (that is an empty list)
// Run commands and print their result.
TRACE( list_add_after (&head , &el1.node) ); print_my_list(&head);
TRACE( list_add_after (&head , &el2.node) ); print_my_list(&head);
TRACE( list_add_before(&el1.node, &el3.node) ); print_my_list(&head);
TRACE( list_del (head.prev) ); print_my_list(&head);
TRACE( list_add_before(&head , &el1.node) ); print_my_list(&head);
TRACE( list_del (&el3.node) ); print_my_list(&head);
return 0;
}
The result of execution of the code above:
list: { }
list_add_after (&head , &el1.node) -> list: { 1 }
list_add_after (&head , &el2.node) -> list: { 2 1 }
list_add_before(&el1.node, &el3.node) -> list: { 2 3 1 }
list_del (head.prev) -> list: { 2 3 }
list_add_before(&head , &el1.node) -> list: { 2 3 1 }
list_del (&el3.node) -> list: { 2 1 }
http://coliru.stacked-crooked.com/a/6e852a996fb42dc2
Of course in real life you will most probably use malloc for list elements.
In C language, we need to define a Node to store an integer data and a pointer to the next value.
struct Node{
int data;
struct Node *next;
};
To add a new node, we have a function add which has data as an int parameter. At first we create a new Node n. If the program does not create n then we print an error message and return with value -1. If we create the n then we set the data of n to have the data of the parameter and the next will contain the root as it has the top of the stack. After that, we set the root to reference the new node n.
#include <stdio.h>
struct node
{
int data;
struct node* next;
};
int main()
{
//create pointer node for every new element
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
//initialize every new pointer with same structure memory
head = malloc(sizeof(struct node));
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 18;
head->next = second;
second->data = 20;
second->next = third;
third->data = 31;
third->next = NULL;
//print the linked list just increment by address
for (int i = 0; i < 3; ++i)
{
printf("%d\n",head->data++);
return 0;
}
}
This is a simple way to understand how does pointer work with the pointer. Here you need to just create pointer increment with new node so we can make it as an automatic.
Go STL route. Declaring linked lists should be agnostic of the data. If you really have to write it yourself, take a look at how it is implemented in STL or Boost.
You shouldn't even keep the *next pointer with your data structure. This allows you to use your product data structure in a various number of data structures - trees, arrays and queues.
Hope this info helps in your design decision.
Edit:
Since the post is tagged C, you have equivalent implementations using void* pointers that follow the basic design principle. For an example, check out:
Documentation | list.c | list.h