I have a very simple C code for constructing a Singly Linked list as below, in which I allocate memory for each node dynamically using malloc. At the end of code, I want to free the memory for each node allocated, was wondering how to go about it - If I start from head node first and free it, the pointers to the subsequent nodes are lost and memory leak happens.
Other way is start from head node and keep storing the node pointer in a separate array of pointers or something, traverse the list till the tail pointer while storing the node pointers, and once reach the tail node, store that also to the other array of pointers and start freeing from that array index backwards until the head node is free'ed.
Is that the only way to achieve what I am trying to do?
In case if I dont want to use second buffer, how do I go about it.
#include "stdio.h"
#include "stdlib.h"
struct lnk_lst
{
int val;
struct lnk_lst * next;
};
typedef struct lnk_lst item;
main()
{
item * curr, * head;
int i,desired_value;
head = NULL;
for(i=1;i<=10;i++)
{
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next = head;
head = curr;
}
curr = head;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next;
}
//How to free the memory for the nodes in this list?
for(i=1;i<=10;i++)
{
free()//?? What logic here
}
}
The usual way is with (pseudo-code first):
node = head # start at the head.
while node != null: # traverse entire list.
temp = node # save node pointer.
node = node.next # advance to next.
free temp # free the saved one.
head = null # finally, mark as empty list.
The basic idea is to remember the node to free in a separate variable then advance to the next before freeing it.
You only need to remember one node at a time, not the entire list as you propose.
In terms of what you need to add to your code, you can, during deletion, use head as the continuously updating list head (as it's meant to be) and curr to store the item you're currently deleting:
while ((curr = head) != NULL) { // set curr to head, stop if list empty.
head = head->next; // advance head to next element.
free (curr); // delete saved pointer.
}
This is a little shorter than the pseudo-code above simply because it takes advantage of C "shorthand" for some operations.
I use something like this:
for (p = curr; NULL != p; p = next) {
next = p->next;
free(p);
}
Your free code should be as follows:
lnk_lst temp = null;
while(head)
{
temp = head->next;
free(head);
head = temp;
}
Also I would like to add after your malloc you probably want to check whether the mem was allocated successfully.. something like
if(curr)
You traverse the list using the same logic as above. You save the curr->next pointer somewhere, free the curr struct and assign curr with the saved curr->next pointer
Content of Garbage Collector.h
#include <stdlib.h>
#include <stdint.h>
#define Stack struct _stack
#define _MALLOC_S(type,num) (type *)_GC_malloc(sizeof(type)*num)
#pragma pack(1)
//Structure for adressing alocated memory into.
Stack {
int *adress_i;
char *adress_c;
float *adress_f;
double *adress_d;
Stack *next;
};
//Safe malloc
void *_GC_malloc(size_t size)
{
void* ptr = malloc(size);
if(ptr == NULL)
return _GC_malloc(size);
else
return ptr;
}
//Push new element on Stack after every malloc
void Add_New(int *i, float *f , double *d , char *c , Stack *p)
{
Stack *q = _MALLOC_S(Stack,1);
q->adress_i = i;
q->adress_f = f;
q->adress_c = c;
q->adress_d = d;
q->next = p->next;
p->next = q;
q = NULL;
}
//before ending program remove adresses that was allocated in memory, and pop entire Stack
void Free_All(Stack *p)
{
//free head (dummy element)
Stack *Temp = p->next;
Stack *_free = p;
free(_free);
void *oslobodi;
while(Temp != NULL)
{
_free = Temp;
Temp = _free->next;
if(_free->adress_i != NULL){
oslobodi = _free->adress_i;
free((int *)oslobodi);
}
else if(_free->adress_c != NULL){
oslobodi = _free->adress_c;
free((char *)oslobodi);
}
else if(_free->adress_f != NULL){
oslobodi = _free->adress_f;
free((float *)oslobodi);
}
else{
oslobodi = _free->adress_d;
free((double *)oslobodi);
}
free(_free);
}
_free = p = Temp;
}
/*
declare variable (var) and dinamicly alocate memory with simple macro,
and add to stack of linked list
*/
#define obj_int(var) int *var = _MALLOC_S(int,1); *var = 0; Add_New(var, NULL, NULL, NULL, Head);
#define obj_char(var) char *var = _MALLOC_S(char,1); *var = 0; Add_New(NULL, NULL, NULL, var, Head);
#define obj_float(var) float *var = _MALLOC_S(float,1); *var = 0; Add_New(NULL, var, NULL, NULL, Head);
#define obj_double(var) double *var = _MALLOC_S(double,1); *var = 0; Add_New(NULL, NULL, var, NULL, Head);
#define obj_struct(_type,_name) struct _type _*name = (struct _type *)malloc(sizeof(struct _type));
#define _INIT_ROW(var,num) for(int i = 0; i < num; i++) var[i] = 0;
/*
same, but for row!
*/
#define row_int(var, num) int *var = _MALLOC_S(int,num); _INIT_ROW(var,num) Add_New(var, NULL, NULL, NULL, Head);
#define row_char(var, num) char *var = _MALLOC_S(char,num); _INIT_ROW(var,num) Add_New(NULL, NULL, NULL, var, Head);
#define row_float(var, num) float *var = _MALLOC_S(float,num); _INIT_ROW(var,num) Add_New(NULL, var, NULL, NULL, Head);
#define row_double(var, num) double *var = _MALLOC_S(double,num); _INIT_ROW(var,num) Add_New(NULL, NULL, var, NULL, Head);
#define string(var, value) row_char(var, (strlen(value)+1)) strcpy(var, value);
/* with this you create a Stack and allocate dummy element */
#define Main(_type) _type main(void) { Stack *Head = _MALLOC_S(Stack,1); Head->next = NULL; Stack *_q_struct;
/* with this macro you call function for dealocate memory (garbage collecting)*/
#define End Free_All(Head); }
/*same thing for the other functions*/
#define Function(name_function, _type, ...) _type name_function(##__VA_ARGS__) { Stack *Head = _MALLOC_S(Stack,1); Head->next = NULL;
#define End_Ret(ret_var) Free_All(Head); return (ret_var); }
#define Call(name_function, ...) name_function(##__VA_ARGS__)
#define Define_Function(name_function, _type, ...) _type name_function(##__VA_ARGS__);
Example of some_program.c
P.S. header systemIO is group of more headers like this above! :)
Main(void)
int num_elements = 10;
row_int(row_elements, num_elements); //alocating row_elements object
for(int i = 0; i < num_elements; i++)
row_elements[i] = i; //initializing row_elements
End //Garbage delete row_elements and end of program
// row_int[0] = 0, row_int[1] = 1 ....
Related
I'm attempting some homework and not sure where to go from here, or if I'm on the right path to doing this correctly. This program was given to me with the goal of creating a function to create a new node with an array large enough to hold the input "count". From there I assume I'm supposed to output the created node.
I've tried setting up the node multiple ways with different pointers, I'm not sure how to initialize the 'newnode' correctly though. And every time I try to use the input 'count' such as 'newnode->array_length = count;' I get a segmentation fault, I don't understand why though, if count is input into the function, isn't it usable in the scope of it?
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<assert.h>
typedef struct node {
struct node* previous;
struct node* next;
int array_length;
int* values;
} node;
//creates a new node with an array large enough to hold `count` values
node* create_node(int count) {
//your code here:
node* newnode;
newnode = (node*) malloc(sizeof(node));
newnode->array_length = count;
newnode->values;
newnode->next=NULL;
newnode->previous=NULL;
return newnode;
}
void append(node* a, node* b) {
assert(a);
assert(b);
a->next = b;
b->previous = a;
}
int main() {
node* a = create_node(10);
assert(a->array_length == 10);
assert(a->next == NULL);
assert(a->previous == NULL);
node* b = create_node(20);
assert(b->array_length == 20);
assert(b->next == NULL);
assert(b->previous == NULL);
append(a, b);
assert(a->next == b);
assert(b->previous == a);
assert(a->previous == NULL);
assert(b->next == NULL);
for(node* cur = a; cur != NULL; cur = cur->next) {
for(int i = 0; i < cur->array_length; i++) {
cur->values[i] = i;
}
}
}
Compilation Errors:
problem2.c: In function ‘create_node’:
problem2.c:20:30: warning: implicit declaration of function ‘size’ [-Wimplicit-function-declaration]
newnode->values = malloc(size(int) * count);
^~~~
problem2.c:20:35: error: expected expression before ‘int’
newnode->values = malloc(size(int) * count);
^~~
You're not allocating memory for values. It's set by default to whatever memory was there before, which was probably an invalid pointer. This would cause a segfault when you tried to access values.
//creates a new node with an array large enough to hold `count` values
node* create_node(int count) {
//your code here:
node* newnode = malloc(sizeof(node));
newnode->array_length = count;
newnode->values = malloc(sizeof(int) * count); // malloc memory for values
newnode->next = NULL;
newnode->previous = NULL;
return newnode;
}
I am trying to implement a stack-esque structure using a linked list in C. Eventually it will read strings of varying length from an input file, thus the need for dynamic memory. I am getting a segmentation fault at the printf in printList and I cannot figure out why. I was also getting segmentation faults in push earlier, but I seem to have fixed them. In case it's not obvious, my intent is to add elements only to the "top" of the list.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void* emalloc(size_t n);
typedef struct node {
struct node* next;
char* word;
} node;
node* head = NULL;
void* emalloc(size_t n) {
void* p;
p = malloc(n);
if(p == NULL) {
fprintf(stderr, "Failed to allocate memory.");
exit(1);
}
return p;
}
void push(char* w) {
if(head == NULL) {
head = (node*) emalloc(sizeof(node));
head->word = (char*) emalloc(strlen(w) * sizeof(char) + 1);
strncpy(head->word, w, strlen(w) + 1);
printf("Pushed a word to head.");
return;
}
node* newnode = (node*) emalloc(sizeof(node));
newnode->word = (char*) emalloc(strlen(w) * sizeof(char) + 1);
strncpy(newnode->word, w, strlen(w) + 1);
newnode->next = head;
head = newnode;
}
void printList() {
node* cur = head;
if(cur == NULL || cur->word == NULL) printf("Whoops!");
while(cur != NULL) {
printf(cur->word);
cur = cur->next;
}
}
/*
* The encode() function may remain unchanged for A#4.
*/
void main() {
char word[20] = "Hello world";
//push("Hello",head);
//push("World",head);
//push("!",head);
push(word);
printList();
}
Why copy to 1 past end of string in push()? Also, if string is too long, strncpy won't NUL it for you.
The real crash though is in the "Head" creation, the first if statement when no entries exist. It does not NULL its next pointer so therefore list traversal will will blow up on last entry as it reads a garbage pointer at the end of the list.
it worked for me, as michael Dorgan ask why did you 1 byte past the end of the string.
I recomend to use something like :
int len =strlen(w)
before
node* newnode = (node*) emalloc(sizeof(node));
newnode->word = (char*) emalloc(len * sizeof(char));
strncpy(newnode->word, w, len)[len]=0;
newnode->next = head;
this temporal variable eliminate the need of use strlen on these locations.
I want to make a function that can add new elements to double linked list in C, but I couldn't do it. Here is code.
New element should have name, group etc. Just explain me how to make name and rest of it I will do by myself.
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include <string.h>
typedef struct inform
{
char name[20];
char group[20];
char form[20];
int day;
int month;
int year;
int srok;
} INF_BLOK;
typedef struct list_elem
{
INF_BLOK inf;
struct list_elem *next, *prev;
} APTEKA;
APTEKA *head, *tail;
int InputData(INF_BLOK* inf);
int main()
{
return 0;
}
I tried to implement a function that inserts an element based on an given index. Note, that i changed your list_item struct a bit so that it contains a pointer to your data-elements.
Here is the implementation:
/**************************************************************
* Function: insert_index
* Parameters: APTEKA* head, INF_BLOK* data, int index
* Return value: Returns NULL on failure, a pointer to the head
* on success
* Description: Inserts a APTEKA* element based on an given
* index
***************************************************************/
APTEKA* insert_index(APTEKA* head, INF_BLOK* data, int index) {
// Local variable for index
int ind = 1;
APTEKA* new_node = (APTEKA*)malloc(sizeof(APTEKA));
new_node->inf = data;
// Check if head exists, the malloc call was successfull and the index is
// in allowed range
// NOTE: Index for head starts at position 1
if(head && new_node && index) {
// If index is one, set a new head
if(index == 1) {
// The previous node is of course NULL
new_node->prev = NULL;
new_node->next = head->next;
if(head->next)
head->next->prev = new_node;
head->next = new_node;
// In a full implementation you need to free the memory for head and the data field in the
// structure. free(...)
// Return a pointer to the new head of the list
return new_node;
} else {
APTEKA* current_node = head->next;
// Loop through all positions before the desired index
for(; ind < (index - 1); ++ind)
current_node = current_node->next;
new_node->prev = current_node;
new_node->next = current_node->next;
if(current_node->next)
current_node->next->prev = new_node;
current_node->next = new_node;
}
}
else {
// Return NULL on failure
return NULL;
}
// Return an pointer to the head
return head;
}
Explanation:
First the function creates a new node named new_node and sets the pointer of the inf data field to the given parameter. Before actually inserting i basically check for that everything is right.
I then divide into two cases: first one to replace the head (index == 1) and second one is for any other index.
If the head should be replaced i change the dependecies and return a pointer to the newly created node. For any other case i iterate to the element before the index and then try to insert it.
When i tested it with this main function, it seemed to work:
int main()
{
/* Only used for testing purposes */
APTEKA* head = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* first = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* tail = (APTEKA*)malloc(sizeof(APTEKA));
head->next = first, head->prev = NULL;
first->next = tail, first->prev = head;
tail->next = NULL, tail->prev = first;
/* Information for head node */
INF_BLOK* block_head = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_head->name, "Head", 5);
/* Information for tail node */
INF_BLOK* block_tail = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_tail->name, "Tail", 5);
/* Information for first block */
INF_BLOK* block_first = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_first->name, "First", 6);
/* Information for block to add */
INF_BLOK* block_sec = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_sec->name, "Second", 7);
head->inf = block_head, first->inf = block_first, tail->inf = block_tail;
if(!insert_index(head, block_sec, 2))
fprintf(stderr, "Error inserting element\n");
APTEKA* element = head;
/* Print out name-data of nodes */
while(element) {
puts(element->inf->name);
element = element->next;
}
element = head;
// Freeing everything
while (element) {
APTEKA* next = element->next;
free(element->inf), free(element);
element = next;
}
return 0;
}
Hopefully, my answer gives you the desired insights. If i did something wrong, please correct me :)
NOTE: For this answer i only used the name attribute of your data-item structure. For storing the group, form, etc. you will need another procedure setting those values.
I'm writing a simple C program to manage a linked list defined as follow:
typedef struct node {
int value;
struct node *next;
} *List;
I reviewed the code and it seems okay but when printing results something is not working well.
My main, with problems on comments:
int main(void) {
List n = list_create(1);
insert(n, 2);
insert(n, 3);
insert(n, 5);
insert(n, 4);
//something here does not work properly. It produces the following output:
//Value: 1
//Value: 2
//Value: 3
//Value: 4
//where is value 5?
print_list(n);
delete(n, 3);
print_list(n);
return 0;
}
I don't know where am I destroying list structure. These are my functions, to debug, if you are too kind.
List list_create(int value) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = NULL;
return new;
}
List new_node(int value, List next_node) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = next_node;
return new;
}
void print_list(List l) {
List *aux;
for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
printf("Valor: %d\n", (*aux)->value);
}
void insert(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value > value) {
List tmp = *p;
List new = new_node(value, tmp);
*p = new;
break;
}
*p = new_node(value, NULL);
}
void delete(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value == value) {
List del = (*p);
(*p) = ((*p)->next);
free(del);
break;
}
}
This code has (at least) two bugs:
The line
if ((*p)->value > value){
means that if you start the list with 1 as the first value and then try to insert 2,3,4..., the body of the 'if' statement never runs, so nothing ever gets inserted.
If you insert a value below the starting value, you have to modify the list pointer itself. However, as #EOF alluded, you are trying to modify a value passed to a function by taking its address. This won't work. &l does not give you the address of the List you passed, it gives you the address of the local copy on insert()'s stack. You are better off modifying the values of first element of the list 'in place'. If you really want to make the List parameter mutable, you'll need to pass it as a List *, and call the function with the address of the list (e.g. insert(&n,2); ) Your delete() function suffers from the same problem - try deleting the first element of the list.
Try this for your insert function:
void insert(List l, int value)
{
List p;
// Find end of list or highest item less than value
for(p = l; p->next != NULL && p->next->value < value; p = p->next);
if (p->value >= value) {
// Over-write p with new value, and insert p as a new one after.
// This saves having to modify l itself.
int tmpval = p->value;
p->value = value;
p->next = new_node(tmpval, p->next);
} else {
// Insert new item after p
p->next = new_node(value, p->next);
}
}
A comment: it is possible the way you are using pointers is not helping the debugging process.
For example, your print_list() could be re-written like this:
void print_list(List l){
List aux;
for(aux = l; aux != NULL; aux = aux->next)
printf("Valor: %d\n", aux->value);
}
and still behave the same. It is generally good practice not to 'hide' the pointer-like nature of a pointer by including a '*' in the typedef.
For example, if you define your list like this:
typedef struct node{
int value;
struct node *next;
} List
And pass it to functions like this:
my_func(List *l, ...)
then it'll make some of these issues more apparent. Hope this helps.
There are many problems in your code:
Hiding pointers behind typedefs is a bad idea, it leads to confusion for both the programmer and the reader.
You must decide whether the initial node is a dummy node or if the empty list is simply a NULL pointer. The latter is much simpler to handle but you must pass the address of the head node to insert and delete so they can change the head node.
printlist does not need an indirect pointer, especially starting from the address of the pointer passed as an argument. Simplify by using the Node pointer directly.
in insert you correctly insert the new node before the next higher node but you should then return from the function. Instead, you break out of the switch and the code for appending is executed, replacing the inserted node with a new node with the same value and a NULL next pointer. This is the reason 5 gets removed and lost when you insert 4. Furthermore, you should pass the address of the head node so a node can be inserted before the first.
delete starts from the address of the argument. It cannot delete the head node because the pointer in the caller space does not get updated. You should pass the address of the head node.
You should avoid using C++ keywords such as new and delete in C code: while not illegal, it confuses readers used to C++, confuses the syntax highlighter and prevents compilation by C++ compilers.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *new_node(int value, Node *next_node) {
Node *node = malloc(sizeof(*node));
if (node != NULL) {
node->value = value;
node->next = next_node;
}
return node;
}
void print_list(Node *list) {
for (; list != NULL; list = list->next)
printf("Valor: %d\n", list->value);
}
void insert_node(Node **p, int value) {
while ((*p) != NULL && (*p)->value < value)
p = &(*p)->next;
*p = new_node(value, *p);
}
void delete_node(Node **p, int value) {
while (*p != NULL) {
if ((*p)->value == value) {
Node *found = *p;
*p = (*p)->next;
free(found);
// return unless delete() is supposed to remove all occurrences
return;
} else {
p = &(*p)->next;
}
}
}
int main(void) {
Node *n = NULL;
insert_node(&n, 2);
insert_node(&n, 3);
insert_node(&n, 5);
insert_node(&n, 4);
insert_node(&n, 1);
print_list(n);
delete_node(&n, 3);
print_list(n);
delete_node(&n, 1);
print_list(n);
return 0;
}
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;