Why my double linked list insertion fail? - c

I am writting a simple timer with a double linked list.If I define the linked list head as below,It will work.
struct timer_head
{
struct timer* prev;
struct timer* next;
pthread_spinlock_t lock;
};
But if I define the head as below, then the insertion will fail,I will lost the previous node after each insertion.
struct timer_head
{
struct timer* next;
struct timer* prev;
pthread_spinlock_t lock;
};
Part of my code:
struct timer
{
struct timer* prev;
struct timer* next;
struct timespec start;
struct timespec interval;
void* par, *par2;
/*if handle return 0 */
/*then delete this timer */
/*else restart it */
int (*handler) (void* par);
};
struct timer_head
{
struct timer* prev;
struct timer* next;
/*
*if i changed the previous definition to
*code below, then my list insertion will failed
*why?
*/
/* struct timer* next;
struct timer* prev;
*/
pthread_spinlock_t lock;
};
void timer_queue_init(struct timer_head* lst)
{
pthread_spin_init(&lst->lock, PTHREAD_PROCESS_SHARED);
lst->next = lst->prev = (struct timer*)lst;
}
static void print_queue(struct timer_head* lst)
{
pthread_spin_lock(&(lst->lock));
struct timer* fst = lst->next;
printf("list travserse:\t");
while (fst != (struct timer*) lst)
{
printf("inteval : %ld, ", fst->interval.tv_nsec);
fst = fst->next;
}
printf("\n");
pthread_spin_unlock(&(lst->lock));
}
void timer_queue_insert(struct timer_head* lst, struct timer* nt)
{
pthread_spin_lock(&(lst->lock));
struct timer* ptr = lst->next;
/*insert into list, sorted as earlist execute time */
while (ptr != (struct timer*) lst &&
timespec_cmp(&(ptr->start), &(ptr->interval),
&(nt->start), &(nt->interval)) <= 0)
{
printf("next\n");
ptr = ptr->next;
}
nt->next = ptr;
nt->prev = ptr->prev;
nt->prev->next = nt;
ptr->prev = nt;
/* send signal to manage thread */
if (!qlen)
{
printf("start :%ld s, %ld ns ", nt->start.tv_sec, nt->start.tv_nsec);
printf("interval :%lds, %ld ns\n", nt->interval.tv_sec, nt->interval.tv_nsec);
pthread_cond_signal(&wait);
}
++qlen;
pthread_spin_unlock(&(lst->lock));
printf("traver after insert\t");
print_queue(lst);
}

This code casts a pointer to a struct timer_head to a pointer to a struct timer.
void timer_queue_init(struct timer_head* lst)
{
pthread_spin_init(&lst->lock, PTHREAD_PROCESS_SHARED);
lst->next = lst->prev = (struct timer*)lst; /* HERE */
}
This works (by luck) so long as they have the same structure. Your struct timer looks like this:
struct timer
{
struct timer* prev;
struct timer* next;
...
So putting prev before next allows the cast to "happen to" preserve the values of prev and next, though you definitely shouldn't do it. The problem with code that "happens to" work is that sometimes it will happen not to work.

Looking at your code, the problem is that you cast a timer_head * to timer *. If timer_head looks like
struct {
struct timer * next;
struct timer * prev;
...
}
then in memory you (may) have the following layout
[next][prev]
. If at the same time timer looks like
struct {
struct timer * prev;
struct timer * next;
...
}
, as in your code, it has a different layout in memory, i.e. something like
[prev][next]
. Your cast from one pointer to the other changes what prev and next stand for. (In one case the first and second pointer in memory, in the other case the second and first pointer in memory).

Related

C dereferencing pointer to incomplete type struct

In the tree.h header, I declared "struct privates" in order to hide the global variables. (relevant snippet)
struct privates;
/*
* a tree
*/
typedef struct tree_node
{
struct tree *left;
struct tree *right;
struct tree_node *left;
struct tree_node *right;
float * info;
float distance_to_neighbor;
} tree_node;
typedef struct tree
{
/*in order to keep track of the kd-tree root*/
tree_node * _root;
/*pointer to internal variables struct*/
struct privates* _privates;
} tree;
struct privates* init_heap_tree();
etc....
In the implementation file kdtree.c , I defined the "struct privates": (relevant snippet)
tree* my_tree=NULL;
typedef struct privates
{
/*variables*/
int current_number_of_tree_nodes;
/*previous tree rebuild's node count*/
int previous_tree_size;
} privates;
privates* init_heap_tree()
{
return (privates*) calloc(1, sizeof (privates));
}
tree* tree_get_tree()
{
my_tree = get_pre_allocated_tree();
return my_tree;
}
etc...
Now in the memory management code, see relevant snippet of init_heap().
I’m attempting to set initialize values for struct members "tree_space->_privates->current_number_of_tree_nodes = 0;"
void
init_heap (int max_dimensions)
{
tree_space = (tree *) calloc (tree_HEAP_SIZE, sizeof (tree));
tree_space = get_pre_allocated_tree();
tree_space->_privates = init_heap_tree();
//THIS IS WERE COMPILE TIME ERROR OCCURS
tree_space->_privates->current_number_of_tree_nodes = 0;
tree_space->_privates->previous_tree_size =0;
//allocate memory based on tree_HEAP_SIZE
tree_space = (tree_node*) calloc (tree_HEAP_SIZE, sizeof (tree_node));
tree_set_k_dimensions (max_dimensions);
etc...
}
"error: dereferencing pointer to incomplete type "struct privates"
I don't want any other design pattern for information hiding perse, How can I resolve this error with the struct member access?
Thanks a million.
Only functions in kdtree.c can access the members of private, so you need to do the initialization there.
privates* init_heap_tree()
{
privates *rval = calloc(1, sizeof (privates));
rval->current_number_of_tree_nodes = 0;
rval->previous_tree_size = 0;
return rval;
}

Expression must have struct or union type

I'm trying to make a stack / linkedlist implementation in C with. I'm struggling on the pop function of a stack.
Here's what my stack/linkedlist implementation looks like :
// a cell
struct cell_s
{
void *elem;
struct cell_s *next;
};
typedef struct cell_s cell_t;
// the list is a pointer to the first cell
struct linkedlist_s
{
struct cell_s *head;
int len;
};
typedef struct linkedlist_s linkedlist_t;
Here's the pop function :
/**
* Pop remove and return the head
*/
cell_t *pop(linkedlist_t *list)
{
if ((*list).len == 0) {
// we cannot pop an empty list
return NULL;
}
else
{
cell_t* tmp = (*list).head;
(*list).head = (*list).head.next; // <-- error occurs here
(*tmp).next = NULL;
return tmp;
}
}
I don't understand what I did wrong. (*list).head is a struct cell_s so I should be able to access the attribute next ? But compiler won't let me do it.
Thanks.
The head field is not a struct cell_s. It is a struct cell_s *, i.e. a pointer to struct cell_s. As such, you need to use the -> operator to dereference and access the member.
list->head = list->head->next;
Note also that ptr->field is easier to read than (*ptr).field.

Generic Linked List in C

I have a linked_list struct:
typedef struct linked_list{
void *data;
struct linked_list *next;
struct linked_list *previous;
} linked_list;
And some linked list operations:
linked_list *init_linked_list() {
linked_list *ll;
ll = (linked_list *) malloc(sizeof(linked_list));
ll->next = ll;
ll->previous = ll;
return ll;
}
void add_element( linked_list *list, void *element) {
linked_list *list_element;
list_element = malloc(sizeof(linked_list));
list_element->data = element;
list_element->next = list->next;
list->next->previous = list_element ;
list->next = list_element ;
list_element->previous = list;
}
I have a graph struct:
typedef struct graph {
int number_vertices;
vertex **vertices;
} graph;
I have a vertex struct:
typedef struct vertex {
int time;
char *name;
linked_list *edges;
} vertex;
I have a edge struct:
typedef struct edge{
int weight;
int change;
vertex *to;
} edge;
And an "add-edge" function:
void add_edge_to_vertex(vertex *v, int weight, int change, vertex *to) {
edge *pEdge = malloc(sizeof(edge));
pEdge->weight = weight;
pEdge->change = change;
pEdge->to = to;
// add edge to vertex linked list
add_element(v->edges, pEdge);
}
Now to my problem. I setup my graph:
int aSize = 30;
int bSize = 30;
pGraph = malloc(sizeof(graph));
pGraph->vertices = malloc(sizeof(vertex*) * aSize);
pGraph->vertices[0] = malloc(sizeof(vertex) * bSize);
I setup my a vertex and init the linked_list:
vertex *pVertex ;
pVertex = malloc(sizeof(vertex));
pVertex->edges = init_linked_list();
And I add the vertex to my graph:
pGraph->vertices[a][b] = *pVertex;
Last I add an edge between two vertices:
add_edge_to_vertex(&pGraph->vertices[a][i], 100, 0, &pGraph->vertices[a][i+1]);
When I try to fetch the edge weight, I get an segment fault: 11
vertex *v = &pGraph->vertices[0][0];
linked_list *ll = v->edges;
int s = linked_list_size(ll);
printf("%d\n", s); // outputs 1 - works so far!
edge *e = (edge *) ll->data;
int weight = e->weight; // segment fault: 11 ..
I have also tried to add an int and a char to the linked_list struct, and fetched that value, instead of fetching (and casting) edge from the "void *data". This works.
My problem now is, that I don't know if my fault is when I fetch the data, or when I store the data.
Your linked list has one extra node at the start that does not have its data member initialized (the node created by the init_linked_list() function).
When you do :
edge *e = (edge *) ll->data;
you get that first node's data member, which is uninitialized. That causes the segmentation fault when you try to dereference e.
Try this instead :
edge *e = (edge *) ll->next->data;
which will get the data member for the node that was inserted by the last add_element function call. Obviously, this is only safe if there has been at least one element added into the 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;
}

Removing all nodes from a queue of structures

I'm trying to delete all nodes from my queue of structures.
Structure:
struct element{
int id;
int sign;
int year;
int month;
double amount;
struct element *next;
};
struct queue{
struct element *head;
int size;
};
And the function I wrote:
void delete(struct queue *queue) {
if (queue->size == 0){
printf("Structure is empty\n");
}
else {
struct element* this;
struct element* other;
for(this=queue->head;this!=NULL;this=other)
{
other=this->next;
free(this);
}
free(queue);
}
}
It doesn't work, and I'm out of ideas. Any suggestions?
In your delete routine, you do not free the queue if the size is empty, but you do free it if the size is non-empty. You should probably do the same for both cases. That is, either don't free in both places, or free in both places.
It is bothersome to need to figure out what the right thing to do is, because delete can not know how the queue was allocated. Given your current design, a way out may be to pass a flag to delete to indicate what it should do:
void delete(struct queue *queue, int do_free) {
if (queue->size == 0){
printf("Structure is empty\n");
}
else {
struct element* this;
struct element* other;
for(this=queue->head;this!=NULL;this=other) {
other=this->next;
free(this);
}
queue->head = 0;
queue->size = 0;
}
if (do_free) free(queue);
}
struct queue new;
/* ... */
delete(&new, 0); /* don't free the queue */
struct queue *empty_new = malloc(sizeof(struct queue));
empty_new->size = 0;
delete(empty_new, 1); /* free the empty queue */
Here
struct queue new;
//...
delete(&new);
new is allocated on the stack, so don't call free(queue) in delete.
Instead, set queue->head = NULL; queue->size = 0; to indicate that the queue is now empty as mentioned by #kirill.
How about just passing the first element of the queue.
void delete(element *el ) {
if(el) {
delete(el->next );
free(el);
}
}
with
typedef struct _element{
int id;
int sign;
int year;
int month;
double amount;
struct _element *next;
} element;
you might have forgotten to update at the end of the function the pointer to NULL as well as changing the size of the queue to 0.

Resources