Deep copy - An element of a void** - Member of struct - c

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

Related

Malloc breaks function

I have a problem where my malloc breaks my program. Removing it will make it work but I need it furter on. Can someone please explain what i'm doing wrong. Thanks in advance!!
I have this function in my graph.c
bool graph_initialise(graph_t *graph, unsigned vertex_count)
{
assert(graph != NULL);
graph = (struct graph_s*) malloc(sizeof(struct graph_s));
if (graph == NULL){return true;}
graph->vertex_count = vertex_count;
graph->adjacency_lists = (struct adjacency_list_s*) malloc(vertex_count * sizeof(struct adjacency_list_s));
if (graph->adjacency_lists == NULL){
return true;
}
int i;
for (i = 1; i < vertex_count; ++i){
graph->adjacency_lists[i].first = NULL;
}
return false;
and this in my graph.h
typedef struct edge_s
{
/* Points to the next edge when this edge is part of a linked list. */
struct edge_s *next;
unsigned tail; /* The tail of this edge. */
unsigned head; /* The head of this edge. */
unsigned weight; /* The weight of this edge. */
} edge_t;
typedef struct adjacency_list_s
{
edge_t *first; /* Pointer to the first element of the adjacency list */
} adjacency_list_t;
/* Type representing a graph */
typedef struct graph_s
{
unsigned vertex_count; /* Number of vertices in this graph. */
unsigned edge_count; /* Number of edges in this graph. */
/* Pointer to the first element of an array of adjacency lists. The array
* is indexed by vertex number
*/
adjacency_list_t *adjacency_lists;
} graph_t;
I suspect this issue is that you are expecting this function to allocate grph for you then operating on the allocated graph from the calling code (you dont show the calling code)
ie you are doing something like
graph *gptr;
graph_initialise(gptr,42);
printf("vc = %d", gptr->vertex_count);
trouble is that grpah_initialize doesnt set gptr. You need instead
bool graph_initialise(graph_t **gptr, unsigned vertex_count)
{
*gptr = (struct graph_s*) malloc(sizeof(struct graph_s));
graph_t *graph = *gptr;
if (graph == NULL){return true;}
graph->vertex_count = vertex_count;
graph->adjacency_lists = (struct adjacency_list_s*) malloc(vertex_count * sizeof(struct adjacency_list_s));
if (graph->adjacency_lists == NULL){
return true;
}
int i;
for (i = 1; i < vertex_count; ++i){
graph->adjacency_lists[i].first = NULL;
}
return false;
and call it like this
graph *gptr;
graph_initialise(&gptr,42);
printf("vc = %d", gptr->vertex_count);
also that for loop should probably start at 0 not 1

Writing dynamic double linked list with a sentinel and struct type in C

I was trying to create that list by using example from "Introduction to Algorithms (3rd Edition)". But I experienced some difficulties which I cannot understand. Firstly, the work of the program is changing due to existence of printf function in precise place. There is one place which needs printf and a lot of other places which can't have printf. Secondly, value of L.nil.next changes after every line of code which does something referred to struct. Unfortunately, because of that changing value I cannot fix the program. I would be very pleased if someone fixed and forced it to work like dynamic double linked list with a sentinel.
There is a code
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct sentinel{
struct listel* nil;
};
struct listel{
struct listel* prev;
int key;
struct listel* next;
};
int list_search(struct sentinel *L, int k);
void list_insert(struct sentinel *L, struct listel *x);
void list_delete(struct sentinel *L, struct listel *x);
int main(int argc, char *argv[]) {
int s;
struct sentinel *L=(struct sentinel*)malloc(sizeof(struct sentinel));
printf("---sentinel created\n"); //FORCED TO WRITE
// printf("L.nil = %p\nL.nil.prev = %p\nL.nil.next = %p\n", L->nil, L->nil->prev, L->nil->next);
L->nil->next=L->nil;
L->nil->prev=L->nil;
// printf("sentinel parameters set\n"); //NOT ALLOWED TO WRITE
// printf("L.nil = %p\nL.nil.prev = %p\nL.nil.next = %p\n", L->nil, L->nil->prev, L->nil->next); //NOW ALLOWED TO WRITE
struct listel *x=(struct listel*)malloc(sizeof(struct listel));
printf("created x\n");
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
// printf("prev = %p\nkey = %d\nnext = %p\n", x->prev, x->key, x->next); //NOW ALLOWED TO WRITE
struct listel *y=(struct listel*)malloc(sizeof(struct listel));
printf("created y\n");
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
struct listel *z=(struct listel*)malloc(sizeof(struct listel));
printf("created z\n");
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
x->key=8;
// printf("x.key = %d is set\n", x->key); //NOT ALLOWED TO WRITE
// printf("L.nil.next=%p\n", L->nil->next); //NOT ALLOWED TO WRITE
// x->next=L->nil->next; //Trying to check line from list_insert without using that function
// printf("x.next=L.nil.next=%p\n", x->next); //NOT ALLOWED TO WRITE
list_insert(L, x); //I have checked no further
x->key=3;
list_insert(L, y);
x->key=4;
list_insert(L, z);
printf("%d\n", list_search(L, 8));
printf("%d\n", list_search(L, 6));
printf("%d\n", list_search(L, 3));
return 0;
}
int list_search(struct sentinel *L, int k){
struct listel *x=(struct listel*)malloc(sizeof(struct listel));
x = L->nil->next;
while (x!=L->nil && x->key!=k) x=x->next;
if (x==L->nil) return 0;
return (x->key);
}
void list_insert(struct sentinel *L, struct listel *x){
printf(" LIST INSERT\n");
// printf(" L.nil.next=%p\n", L->nil->next);
x->next=L->nil->next;
// printf(" x.next=L.nil.next=%p\n", x->next); //NOT ALLOWED TO WRITE - I have checked no further
L->nil->next->prev=x;
L->nil->next=x;
x->prev=L->nil;
}
void list_delete(struct sentinel *L, struct listel *x){
x->prev->next=x->next;
x->next->prev=x->prev;
}
malloc does not initialise the allocated memory to anything sensible, so
struct sentinel *L=(struct sentinel*)malloc(sizeof(struct sentinel));
printf( ... L->nil, L->nil->prev ... UNDEFINED!! CRASH!! );
L->nil->next=L->nil; // UNDEFINED!! CRASH!!
L->nil->prev=L->nil; // UNDEFINED!! CRASH!!
Delete all this and start with:
struct sentinel *L=(struct sentinel*)malloc(sizeof(struct sentinel));
L->nil = NULL;
You should be able to see that L->nil->prev and L->nil->next are meaningless unless L actually contains a valid list element, e.g. if you did this:
struct listel *x=(struct listel*)malloc(sizeof(struct listel));
x->prev = NULL;
x->next = NULL;
L->nil = x;
then L->nil->prev == x->prev == NULL and L->nil->next == x->next == NULL
Looking at the code, it's working with a circular double linked list with a sentinel node. This is how C++ std::list is usually implemented.
Use a typedef to simplify the code. This syntax is "legacy" compatible:
typedef struct listel_{
struct listel_* next;
struct listel_* prev;
int key;
}listel;
A sentinel node is the same as a regular node, and should use the same struct, in this case listel. Example code to initialize a sentinel node to represent an empty list by setting the sentinel node's next (first node) pointer and previous (last node) pointer to point to the sentinel node.
listel *L
/* ... */
/* allocate and initialize a sentinel node */
L = (listel *)malloc(sizeof(listel));
L->next = L; /* pointer to first node of list */
L->prev = L; /* pointer to last node of list */
list_insert should take a key as input and allocate a node internally (no need for x, y, z):
void list_insert(listel *L, int k);
list_delete should take a key as input and delete a node internally.
void list_insert(listel *L, int k);
list_search should not allocate a node, it works with an existing list. Normally list_search would return a pointer to node if found or NULL if not found.
listel * list_search(listel *L, int k);
Working example with added display function:
#include <stdio.h>
#include <stdlib.h>
typedef struct listel_{
struct listel_* next;
struct listel_* prev;
int key;
}listel;
void list_display(listel *L);
listel * list_search(listel *L, int k);
void list_insert(listel *L, int k);
void list_delete(listel *L, int k);
int main(int argc, char *argv[]) {
listel *L;
/* allocate sentinel node */
L =(listel *)malloc(sizeof(listel));
L->next = L;
L->prev = L;
/* display list while inserting 3 nodes */
list_display(L);
list_insert(L, 8);
list_display(L);
list_insert(L, 3);
list_display(L);
list_insert(L, 4);
list_display(L);
/* display search list results */
printf("%d %d\n", (list_search(L, 8) != NULL) ? 8 : 0, 8);
printf("%d %d\n", (list_search(L, 6) != NULL) ? 6 : 0, 6);
printf("%d %d\n", (list_search(L, 3) != NULL) ? 3 : 0, 3);
printf("\n");
/* display list while deleting 3 nodes */
list_display(L);
list_delete(L, 3);
list_display(L);
list_delete(L, 8);
list_display(L);
list_delete(L, 4);
list_display(L);
/* free sentinel node */
free(L);
return 0;
}
void list_display(listel *L)
{
listel *e;
if(L == NULL || L->next == L) /* if list empty */
return; /* return */
e = L->next; /* display list forward */
do{
printf("%d ", e->key);
e = e->next;
}while(e != L);
printf("\n");
e = L->prev; /* display list backward */
do{
printf("%d ", e->key);
e = e->prev;
}while(e != L);
printf("\n\n");
}
listel* list_search(listel *L, int k){
listel *e;
if(L == NULL || L->next == L) /* if list empty */
return NULL; /* return null */
e = L->next;
while (e != L && e->key != k) e=e->next;
if (e == L) /* if not found */
return NULL; /* return null */
return e;
}
void list_insert(listel *L, int k){
listel *e;
if(L == NULL) /* if no sentinel node */
return; /* return */
e = (listel *)malloc(sizeof(listel));
if(e == NULL) /* if can't allocate node */
return; /* return */
e->next = L->next; /* e->next = first node */
e->prev = L; /* e->prev = sentinel */
e->key = k;
L->next->prev = e;
L->next = e;
}
void list_delete(listel *L, int k){
listel *e;
if(L == NULL || L->next == L) /* if list empty */
return; /* return */
e = L->next;
while (e != L && e->key != k) e=e->next;
if (e == L) /* if not found */
return; /* return null */
e->prev->next = e->next; /* remove node from list */
e->next->prev = e->prev;
free(e); /* free node */
}

List ADT - How to free a struct pointer and its member?

Below is a List ADT,
typedef struct List{
void **array;
/* Following members for Housekeeping - Array enhancement*/
int lastItemPosition;
int size;
}List;
#define INITIAL_LIST_SIZE 50
createList operation tries to free(*(list->array)) expecting to just free the array of void* but not the objects pointed to each void* because listPointer takes shallow copy of list
List *createList(List *list, Op opType){
List *listPointer = (List *)malloc(sizeof(List));
void *accumulator = NULL;
if(opType == CREATE_NEW_LIST){
accumulator = malloc(INITIAL_LIST_SIZE*sizeof(void*));
listPointer->array = &accumulator;
/* Is it safe to initialise zero to element of array of void* pointers? */
listPointer->array = memset(listPointer->array, 0, INITIAL_LIST_SIZE*sizeof(void *));
listPointer->lastItemPosition = -1;
listPointer->size = INITIAL_LIST_SIZE;
}else if(opType == DOUBLE_THE_LIST){
accumulator = malloc(2*(list->size)*sizeof(void *));
listPointer->array = &accumulator;
/* Performing shallow copy, Is deep copy required? */
listPointer->array = memcpy(listPointer->array, list->array, list->size*sizeof(void*));
listPointer->lastItemPosition = list->lastItemPosition;;
listPointer->size = 2*(list->size);
free(*(list->array)); // How to free list pointer and its members?
}else if(opType == HALF_THE_LIST){
accumulator = malloc(((list->size)/2)*sizeof(void *));
listPointer->array = &accumulator;
/* Performing shallow copy, Is deep copy required? */
listPointer->array = memcpy(listPointer->array, list->array, (list->size/2)*sizeof(void *));
listPointer->lastItemPosition = list->lastItemPosition;
listPointer->size = (list->size)/2;
free(*(list->array)); // How to free list pointer and its members?
}
return listPointer;
}
following list operations are performed List,
void insertItem(List *, void *newItem);
void deleteItem(List *, int listIndex);
User access,
/* main.c */
#include"list.h"
int main(void){
List *arrayList = createList((List *)NULL, CREATE_NEW_LIST);
if (arrayList == (List *)NULL){
fprintf(stderr, "Unable to createList() \n");
exit(1); //Nothing else to do without arrayList
}
/* Objects should be on heap */
int *object = malloc(sizeof(int));
*object = 650;
insertItem(arrayList, object);
}
Question:
Can you please clarify, what does free(*(list->array)) does in my code?
The following code snipped should do the job:
else if(opType == DOUBLE_THE_LIST){
listPointer->array = realloc(listPointer->array, 2*(list->size)*sizeof(void *));
listPointer->lastItemPosition = list->lastItemPosition;;
listPointer->size = 2*(list->size);
// do not free any more: free(*(list->array)); // How to free list pointer and its members?
}
For option DOUBLE_THE_LIST and option HALF_THE_LIST your code is called with an existing list.
The code then creates a new list and copies either the whole or the half of the existing list into the new list.
Then the existing list is deleted (aka free'd) using free(*(list->array));
Finally the new list is returned using return listPointer;
So when using the function with these option, you should always do the assignment of the return value to the same list as you use as argument. That is:
myList = createList(myList, HALF_THE_LIST);
If you do:
myListB = createList(myListA, HALF_THE_LIST);
you'll myListApointing to already free'd memory which is bad.

List - Encapsulation & Performance - trade-off

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?

C, Sorting a queue of structures

I could use a little help. I'm trying to sort a queue of structures by year.
This are my structures:
struct element{
int id;
int sign;
int year;
int month;
double amount;
struct element *next;
};
struct queue{
struct element *head;
struct element *tail;
struct element *heads;
struct element *temp;
struct element *temph;
int size;
};
and this is the function i wrote:
void sort(struct queue* queue){
if (queue->size == 0){
printf("Struct is empty\n");}
else {
struct element* head=queue->head;
struct element* heads=queue->heads;
struct element* temp=NULL;
struct element* temph=queue->head;
int i, size=queue->size;
for(i=0;i<size-1;i++){
heads=head->next;
if((head->year)>(heads->year)){
temp=head;
head=heads;
heads=temp;
}
head=head->next;
heads=NULL;
temp=NULL;
}
head=temph;
}
}
It breaks when I copmare: if((head->year)>(heads->year)).
I'm pretty sure that my problem is caused by improper reference to the structure next to head (I named it heads).
I omitted all the non-important stuff, and reduced the linked-list bubbele sort to this skeletton.
void sort(struct queue* queue)
{
struct element **pp, *this;
if (!queue->head ){
fprintf(stderr, "OMG Struct is empty\n");
return;
}
for(pp = &queue->head; this = *pp; pp = &(*pp)->next){
struct element *other = this->next;
if (!this->next) break;
if (this->year < other->year) continue;
/*
** Now, Swap this (b) and other (c)
** old situation: #a -> (b) -> (c) -> (d)
** new situation: #a -> (c) -> (b) -> (d)
*/
*pp = other; /* #a -> (c) */
this->next = other->next; /* (b) -> (d) */
other->next = this; /* (c) -> (b) */
}
/* Note: when we get here, "this" will contain the last non-NULL node in the
** chain, and can be used to reset the tail-pointer
*/
return;
}

Resources