Here is a doubly linked list, with the node/link carrying the information needed in order to be stored in the list (intrusive):
dlist.h:
#ifndef DLIST_H
#define DLIST_H
//--------------------------------------------------------------------------
typedef struct Link
{
struct Link* succ;
struct Link* prev;
} Link;
//--------------------------------------------------------------------------
typedef struct List
{
Link* first;
Link* last;
} List;
//--------------------------------------------------------------------------
void init(List* lst)
{
assert(lst);
lst->first = 0;
lst->last = 0;
}
//--------------------------------------------------------------------------
List* create()
{
List* lst = (List*) malloc(sizeof(List*));
init(lst);
return lst;
}
//--------------------------------------------------------------------------
void push_back(List* lst, Link* l)
{
assert(l);
assert(lst);
{
Link* last = lst->last;
if (last)
{
last->succ = l;
l->prev = last;
}
else
{
lst->first = l;
l->prev = 0;
}
lst->last = l;
l->succ = 0;
}
}
//--------------------------------------------------------------------------
void clear (List* lst)
{
assert(lst);
{
Link* curr = lst->first;
Link* next = 0;
while (curr)
{
next = curr->succ;
free(curr);
curr = next;
}
lst->first = 0;
lst->last = 0;
}
}
//--------------------------------------------------------------------------
void destroy (List* lst)
{
assert(lst);
clear(lst);
free(lst);
}
//--------------------------------------------------------------------------
typedef struct Name
{
Link l;
char* s;
} Name;
//--------------------------------------------------------------------------
Name* make_name(char* str)
{
Name* n = (Name*) malloc(sizeof(Name*));
n->s = str;
return n;
}
//--------------------------------------------------------------------------
#endif
main.c:
#include <stdlib.h> // malloc
#include <stdio.h> // printf
#include <assert.h> // assert
#ifdef __cplusplus
#else // compiling in C.
int main ()
{
List* lst = create();
char* names[ ] = { "Giorikas", "Kostikas", "Foo", "Bar", "Gosho", "Pesho" };
char* name;
int i = 0;
int size = 6;
for (i; i < size; ++i)
{
push_back(lst, (Link*)(make_name(names[i])));
name = ((Name*)(lst->last))->s;
printf("Name: %s \n", name);
}
destroy(lst);
getchar();
return 0;
}
#endif
Stepping with the debugger I get the names printed and in function clear(), at the first attempt of freeing a link, I get two warnings and finally:
_CrtIsValidHeapPointer(pUserData)
Note: after a bit of research I understand that: "you'll receive heap corruption not immediately on rewrite occurs, but on the next heap check, which will be performed on any next memory allocation/deallocation.". So, probably, what happens in clear()is the heap check that triggers the error.
Where is this heap corruption taking place?
You make bad allocations. You need to allocate objects not pointer to, so:
List* lst = (List*) malloc(sizeof(List*));
should be
List* lst = (List*) malloc(sizeof(List));
and the same for Nameat least. You can also remove the cast:
List* lst = malloc(sizeof(List));
-----EDIT----
and a much better idiom is:
List* lst = malloc(sizeof(*lst));
Related
I'm new to C and I'm stuck with the insert function in a linked list. When I try printing the list. The result isn't what I expect. I know it has something to do with pointers but I just can't get my head around it. What am I doing wrong here?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
typedef struct CELL_NODE CellNode;
struct CELL_NODE {
int row;
int column;
CellNode *next;
};
struct LinkedList {
CellNode *head;
};
typedef struct LinkedList LinkedList;
void printList(LinkedList *myList) {
CellNode *curr = (*myList).head;
if (curr != NULL) {
printf("(%d,%d)", (*curr).row, (*curr).column);
if ((*curr).next != NULL) {
curr = (*curr).next;
printf(" - (%d,%d)", (*curr).row, (*curr).column);
}
} else {
printf("The list is empty");
}
printf("\n");
}
void insert(LinkedList *myList, CellNode *node) {
CellNode *ref = (*myList).head;
if (ref == NULL) {
(*myList).head = node;
} else {
while ((*ref).next != NULL) {
ref = (*ref).next;
}
(*ref).next = node;
}
}
int main(int argc, char *argv[]) {
LinkedList myList = { NULL };
for (int k = 0; k < 2; k++) {
CellNode myNode = { 1, k, NULL };
insert(&myList, &myNode);
printList(&myList);
printf("\n");
}
return 1;
}
The result I get is:
(1,0)
(1,1) - (1,1)
I'm expecting:
(1,0)
(1,0) - (1,1)
You should first change every instance of (*x).y to x->y to make your code much more readable.
Then, look at this code:
int main(int argc, char *argv[])
{
LinkedList myList = {NULL};
for(int k = 0 ; k<2 ; k++) {
CellNode myNode = {1,k,NULL};
insert(&myList,&myNode);
printList(&myList);
printf("\n");
}
return 1;
}
You create myNode as a local variable inside the for loop. That means that each iteration of the loop gets a new instance of myNode, destroying the previous one. So you've connected myNode to your linked list through pointers, and then you let it get destroyed the next time through the for loop.
If you're going to let some piece of code stash a pointer to something, you must ensure that something remains valid until there is no longer any possibility of those pointers being dereferenced.
You need to make a decision -- what will own the objects that the linked list contains pointers to? When will that lifetime end? And when they end, what will destroy them?
You haven't done this. So you have objects whose lifetimes end too early.
With
CellNode myNode = {1,k,NULL};
insert(&myList,&myNode);
you are passing a pointer to a local variable. The life time of this variable is just as long as the respective iteration of the loop, i.e. in the second iteration, the object of the first iteration is out of scope. So you will access an object which's life time has already ended by the pointer you stored in your list. This yields undefined behaviour.
Use dynamically generated objects instead (and don't forget to free them later on):
CellNode *myNode = malloc(sizeof(CellNode));
myNode->row = ...
You repeatedly insert a node into the linked list from a local variable that immediately goes out of scope. The behavior is undefined, your program might fail in many unpredictable ways.
You should modify the code this way:
change the insert function to take the element data as arguments and allocate a new node with malloc().
make printList() print the full list, not just the first couple of cells.
change the clumsy (*pointer).member notation into the equivalent but more idiomatic pointer->member notation.
return 0 from main for successful operation.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
typedef struct CellNode CellNode;
struct CellNode {
int row;
int column;
CellNode *next;
};
typedef struct LinkedList LinkedList;
struct LinkedList {
CellNode *head;
};
void printList(LinkedList *myList) {
CellNode *curr = myList->head;
if (curr != NULL) {
printf("(%d,%d)", curr->row, curr->column);
while (curr->next != NULL) {
curr = curr->next;
printf(" - (%d,%d)", curr->row, curr->column);
}
} else {
printf("The list is empty");
}
printf("\n");
}
CellNode *insert(LinkedList *myList, int row, int column) {
CellNode *node = malloc(sizeof(*node));
CellNode *ref = myList->head;
if (node != NULL) {
if (ref == NULL) {
myList->head = node;
} else {
while (ref->next != NULL) {
ref = ref->next;
}
ref->next = node;
}
}
return node; // return node pointer to allow the caller to detect out of memory error
}
int main(int argc, char *argv[]) {
LinkedList myList = { NULL };
CellNode *node;
for (int k = 0; k < 2; k++) {
insert(&myList, 1, k);
printList(&myList);
printf("\n");
}
// free the nodes
while ((node = myList->head) != NULL) {
myList->head = node->next;
free(node);
}
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am doing a Circular Linked List Deque assignment in C. The code runs fine and the outputs are as expected, but for some reason after the circularListReverse()
void circularListReverse(struct CircularList* list)
{
assert(!circularListIsEmpty(list));
struct Link *curLink;
struct Link *tempLink;
curLink = list->sentinel;
do {
tempLink = curLink->next;
curLink->next = curLink->prev;
curLink->prev = tempLink;
curLink = tempLink;
} while (curLink != list->sentinel);
}
is called on the list, the circularListPrint()
void circularListPrint(struct CircularList* list)
{
assert(!circularListIsEmpty(list));
struct Link *newLink = list->sentinel->next;
while(newLink != list->sentinel) {
printf("%g ", newLink->value);
newLink = newLink->next;
}
printf("\n"); //This prints, so it exits the loop
}
function hangs after it prints all of the expected results. After troubleshooting for hours I have found that the program exits the while loop which does the printing, but does not exit the function. This function DOES work properly before the reverse function is called. Why is it hanging?
Below is the driver:
#include "circularList.h"
#include <stdio.h>
int main()
{
struct CircularList* deque = circularListCreate();
circularListAddBack(deque, (TYPE)1);
circularListAddBack(deque, (TYPE)2);
circularListAddBack(deque, (TYPE)3);
circularListAddFront(deque, (TYPE)4);
circularListAddFront(deque, (TYPE)5);
circularListAddFront(deque, (TYPE)6);
circularListPrint(deque); //Works fine
printf("%g\n", circularListFront(deque));
printf("%g\n", circularListBack(deque));
circularListRemoveFront(deque);
circularListRemoveBack(deque);
circularListPrint(deque);
circularListReverse(deque);
circularListPrint(deque); //HANGS
//Debug
printf("\nEnd of print\n"); //This does NOT print, so function never exits
circularListDestroy(deque);
return 0;
}
List and Link structures:
struct Link
{
TYPE value;
struct Link * next;
struct Link * prev;
};
struct CircularList
{
int size;
struct Link* sentinel;
};
Add functions:
static void addLinkAfter(struct CircularList* list, struct Link* link, TYPE value)
{
assert(link != NULL);
struct Link *newLink = createLink(value);
newLink->prev = link;
newLink->next = link->next;
newLink->next->prev = newLink;
link->next = newLink;
list->size++;
}
/**
* Adds a new link with the given value to the front of the deque.
*/
void circularListAddFront(struct CircularList* list, TYPE value)
{
assert(list != NULL);
addLinkAfter(list, list->sentinel, value);
}
/**
* Adds a new link with the given value to the back of the deque.
*/
void circularListAddBack(struct CircularList* list, TYPE value)
{
assert(list != NULL);
addLinkAfter(list, list->sentinel->prev, value);
}
Create Circular List:
/**
* Allocates and initializes a list.
*/
struct CircularList* circularListCreate()
{
struct CircularList* list = malloc(sizeof(struct CircularList));
init(list);
return list;
}
/**
* Allocates the list's sentinel and sets the size to 0.
* The sentinel's next and prev should point to the sentinel itself.
*/
static void init(struct CircularList* list)
{
assert(list != 0);
list->sentinel = (struct Link *)malloc(sizeof(struct Link));
assert(list->sentinel != 0);
list->sentinel->next = list->sentinel;
list->sentinel->prev = list->sentinel;
list->size = 0;
list->sentinel->value = 0;
}
Removes:
static void removeLink(struct CircularList* list, struct Link* link)
{
// FIXME: you must write this
assert(!circularListIsEmpty(list));
assert(link != NULL);
link->prev->next = link->next;
link->next->prev = link->prev;
free(link);
list->size--;
}
/**
* Removes the link at the front of the deque.
*/
void circularListRemoveFront(struct CircularList* list)
{
assert(!circularListIsEmpty(list));
removeLink(list, list->sentinel->next);
}
/**
* Removes the link at the back of the deque.
*/
void circularListRemoveBack(struct CircularList* list)
{
assert(!circularListIsEmpty(list));
removeLink(list, list->sentinel->prev);
}
The output is
6 5 4 1 2 3
6
3
5 4 1 2
2 1 4 5
//Cursor sits here and program doesn't exit
Can't reproduce. This code works fine (fixing memory leaks left as the reader's exercise). This code doesn't execute circularListRemoveFront and circularListRemoveBack (because you didn't paste their code), therefore it is likely one or both of them may be the culprit.
My code differs with circularListCreate implementation (there was no code of it pasted initially) but this is unlikely to be the issue.
EDIT:
Added circularListRemoveBack and circularListRemoveFront after you pasted their code. Code works, you must have some local issue. Please copy, paste and compile, try if it works.
output is:
6 5 4 1 2 3
5 4 1 2
2 1 4 5
#include <stdio.h>
#include <stdlib.h>
#define TYPE double
struct Link
{
double value;
struct Link * next;
struct Link * prev;
};
struct CircularList
{
int size;
struct Link* sentinel;
};
void circularListReverse(struct CircularList* list)
{
struct Link *curLink;
struct Link *tempLink;
curLink = list->sentinel;
do {
tempLink = curLink->next;
curLink->next = curLink->prev;
curLink->prev = tempLink;
curLink = tempLink;
} while (curLink != list->sentinel);
}
void circularListPrint(struct CircularList* list)
{
struct Link *newLink = list->sentinel->next;
while(newLink != list->sentinel) {
printf("%g ", newLink->value);
newLink = newLink->next;
}
printf("\n"); //This prints, so it exits the loop
}
struct Link* createLink(TYPE value)
{
struct Link *l = malloc(sizeof(struct Link));
l->value = value;
return l;
}
static void addLinkAfter(struct CircularList* list, struct Link* link, TYPE value)
{
struct Link *newLink = createLink(value);
newLink->prev = link;
newLink->next = link->next;
newLink->next->prev = newLink;
link->next = newLink;
list->size++;
}
/**
* Adds a new link with the given value to the front of the deque.
*/
void circularListAddFront(struct CircularList* list, TYPE value)
{
addLinkAfter(list, list->sentinel, value);
}
/**
* Adds a new link with the given value to the back of the deque.
*/
void circularListAddBack(struct CircularList* list, TYPE value)
{
addLinkAfter(list, list->sentinel->prev, value);
}
static void removeLink(struct CircularList *list, struct Link *link)
{
link->prev->next = link->next;
link->next->prev = link->prev;
free(link);
list->size--;
}
void circularListRemoveBack(struct CircularList* list)
{
removeLink(list, list->sentinel->prev);
}
void circularListRemoveFront(struct CircularList* list)
{
removeLink(list, list->sentinel->next);
}
struct CircularList* create()
{
struct CircularList *l = malloc(sizeof(*l));
l->sentinel = malloc(sizeof(*l->sentinel));
l->sentinel->prev = l->sentinel->next = l->sentinel;
l->size = l->sentinel->value = 0;
}
int main(void) {
struct CircularList* deque = create();
circularListAddBack(deque, (TYPE)1);
circularListAddBack(deque, (TYPE)2);
circularListAddBack(deque, (TYPE)3);
circularListAddFront(deque, (TYPE)4);
circularListAddFront(deque, (TYPE)5);
circularListAddFront(deque, (TYPE)6);
circularListPrint(deque); //Works fine
circularListRemoveFront(deque);
circularListRemoveBack(deque);
circularListPrint(deque);
circularListReverse(deque);
circularListPrint(deque); //HANGS
//Debug
printf("\nEnd of print\n"); //This does NOT print, so function never exits
return 0;
}
So I have a program that takes an int for input, and inserts the integer into a doubly linked list where the functions are createQueue, enqueue, dequeue, display, peek, and destroyQueue. I have a main.c and a queue.h file but the problem doesn't lay in there, it's in the queue.c file. The problem is when I pipeline a test12.txt file and print to an output.txt with the following commands, enqueue 0 0 display, I get a segmentation fault. If I run just enqueue 0 0 in the test12.txt file there's no problem, it works just fine. My question is, am I dereferencing temp in display when it points to nothing when I write temp = temp->prev; or is that a valid call and my problem lies in the initialization of my temp node?
queue.c file:
#include "queue.h"
Queue_ptr createQueue() {
Queue_ptr s = (Queue_ptr)malloc(sizeof(Queue));
s->front = NULL;
s->back = NULL;
return s;
}
void enqueue(Queue_ptr s, element e) {
DN_ptr n = (DN_ptr)malloc(sizeof(DLLNode));
n->e = e;
if (s->front == NULL) {
n->next = NULL;
s->front = n;
s->back = n;
}else{
s->back->next = n;
n->prev = s->back;
s->back = n;
}
}
element dequeue(Queue_ptr s) {
DN_ptr temp = s->front->next;
element e = s->front->e;
free(s->front);
s->front = temp;
s->front->next = NULL;
s->front->prev = NULL;
return e;
}
int isEmpty(Queue_ptr s) {
if (s->front == NULL)
return 1;
else
return 0;
}
element peek(Queue_ptr s) {
return s->front->e;
}
void display(Queue_ptr s) {
DN_ptr temp = s->back;
while (temp) {
printf("%d\n", temp->e);
temp = temp->prev;
}
}
void destroyQueue(Queue_ptr s) {
DN_ptr temp = s->front;
DN_ptr next;
while (temp) {
next = temp->next;
free(temp);
temp = next;
}
free(s);
}
queue.h file:
#ifndef queue_h
#define queue_h
#include "stdheader.h"
//Structures
//element is content of a node.
typedef int element;
//_DLLnode is 1 link in a doubly linked list.
struct _DLLNode {
element e;
struct _DLLNode *next;
struct _DLLNode *prev;
};
typedef struct _DLLNode DLLNode;
typedef struct _DLLNode *DN_ptr;
//DLL is a series of links tracked by the head and back of the list.
struct _DLL {
DN_ptr front;
DN_ptr back;
};
typedef struct _DLL Queue;
typedef struct _DLL *Queue_ptr;
Queue_ptr createQueue();
void enqueue(Queue_ptr, element);
element dequeue(Queue_ptr);
int isEmpty(Queue_ptr);
element peek(Queue_ptr);
void display(Queue_ptr);
void destroyQueue(Queue_ptr);
#endif /* queue_h */
You do not set n->prev in enqueue when the queue is empty, neither do you set n->next when the queue is not empty.
dequeue corrupts the queue if it has more than 2 elements, and it crashes if it has only one element.
Here is a corrected version:
void enqueue(Queue_ptr s, element e) {
DN_ptr n = (DN_ptr)malloc(sizeof(DLLNode));
n->e = e;
n->next = NULL;
if (s->front == NULL) {
n->prev = NULL;
s->front = n;
s->back = n;
} else {
s->back->next = n;
n->prev = s->back;
s->back = n;
}
}
element dequeue(Queue_ptr s) {
DN_ptr temp = s->front->next;
element e = s->front->e;
free(s->front);
s->front = temp;
if (temp) {
temp->prev = NULL;
} else {
s->back = NULL;
}
return e;
}
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;
This program is a work in progress. It is going to simulate a multiprocessor and I am programming it with producer-consumer sync.
Few problems here:
- My pending_request counter starts 1 lower than it should and goes down to -1. It should stop at 0.
- My remove_queue function also keeps removing one over. It will remove until the list is blank, but it doesn't recognize the list is empty. Then if I run remove_queue one more time, then it recognizes the list empty. SAMPLE OUTPUT AT THE BOTTOM at http://tinyurl.com/3ftytol
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
typedef struct pr_struct{
int owner;
int burst_time;
struct pr_struct *next_prcmd;
} prcmd_t;
static prcmd_t *pr_head = NULL;
static prcmd_t *pr_tail = NULL;
static int pending_request = 0;
static pthread_mutex_t prmutex = PTHREAD_MUTEX_INITIALIZER;
int add_queue(prcmd_t *node)
{ pthread_mutex_lock(&prmutex);
//code
prcmd_t *curNode = pr_head;
if(pr_head == NULL) { pr_head = node; return;}
while(curNode->next_prcmd)
{
curNode = curNode->next_prcmd;
}
curNode->next_prcmd = node;
//
pending_request++;
pthread_mutex_unlock(&prmutex);
return(0);
}
int remove_queue(prcmd_t **node)
{
pthread_mutex_lock(&prmutex);
if(pr_head == NULL)
{
//your code
printf("Queue is empty\n");
//
pthread_mutex_unlock(&prmutex);
return(-1);
}
else
{
//your code
prcmd_t *tempNode; tempNode = (prcmd_t*)malloc(sizeof(prcmd_t));
tempNode = *node;
*node = tempNode->next_prcmd;
free(tempNode);
//
pending_request--;
pthread_mutex_unlock(&prmutex);
return(0);
}
}
int get_number_request(void)
{ return pending_request; }
void display_list(prcmd_t *node)
{
if (pr_head == NULL)
{
printf("List is empty!\n\n");
}
printf("-----------\n");
while(node)
{
printf("%i %i\n", node->owner,node->burst_time);
node = node->next_prcmd;
}
int r = get_number_request();
printf("Pending requests: %i\n", r);
}
int main()
{
int i=0;
int length = 4;
prcmd_t *pr[length];
for(i =0;i<length;i++)
{
pr[i] = (prcmd_t*)malloc(sizeof(prcmd_t));
pr[i]->owner = i+1;
pr[i]->burst_time = i + 2;
add_queue(pr[i]);
}
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
remove_queue(&pr_head);
display_list(pr_head);
}
some things (although maybe not all):
There is no need for a tail pointer if the list is not doubly linked, because there is no way to go from tail to head (no previous pointer)
Why do you malloc in your remove queue?
*node = prHead;
prHead = prHead->next_prcmd;
--pending_request;
in add_queue you have to node->next_prcmd = NULL; otherwwise you will never know the end.
again, some things, but maybe not all...
Mario