I'm getting a SegFault when passing a function pointer through a couple of structs and I can't figure out what I'm doing wrong. Here's the code:
typedef int (*CompareFuncT)( void *, void * );
typedef void (*DestructFuncT)( void * );
struct AVL
{
void * obj;
struct AVL * parent;
struct AVL * leftChild;
struct AVL * rightChild;
};
typedef struct AVL * AVLPtr;
struct SortedList
{
AVLPtr root;
CompareFuncT comp;
DestructFuncT dest;
};
typedef struct SortedList * SortedListPtr;
SortedListPtr SLCreate(CompareFuncT cf, DestructFuncT df){
SortedListPtr slp = malloc(sizeof(struct SortedList));
if(slp == NULL){
printf("Not enough space for list\n");
return NULL;
}
slp->root = NULL;
slp->comp = cf;
slp->dest = df;
return slp;
}
AVLPtr avl_insert(AVLPtr root, AVLPtr parent, void * obj, int (*compare)( void *, void * )){
int s = 5;
int k = 6;
compare(&s, &k);
if(root == NULL){
root = malloc(sizeof(struct AVL));
if(root == NULL){
printf ("Out of memory - creating AVL node\n");
return NULL;
}
root->obj = obj;
root->parent = parent;
root->leftChild = NULL;
root->rightChild = NULL;
return root;
}
else if (compare(obj, root->obj) < 0){
root->leftChild = avl_insert(root->leftChild, root, obj, compare);
root = balance(root);
}
else if (compare(obj, root->obj) >= 0){
root->rightChild = avl_insert(root->rightChild, root, obj, compare);
root = balance(root);
}
return root;
}
int SLInsert(SortedListPtr list, void * newObj){
list->root = avl_insert(list->root, newObj, list->comp);
if(list->root == NULL)
return 0;
return 1;
}
int compareInts(void *p1, void *p2)
{
int i1 = *(int*)p1;
int i2 = *(int*)p2;
return i1 - i2;
}
void destroyBasicTypeNoAlloc(void *p) {
return;
}
int main(int argc, char **argv) {
int s = 9;
SortedListPtr list = SLCreate(compareInts, destroyBasicTypeNoAlloc);
SLInsert(list, &s);
return 0;
}
There's obviously more parameters going through the function, but this is the propagation of my compare function. I'm getting a SegFault on the compare in avl_insert. I have a feeling I'm just not passing a pointer where I should be, but I just can't find it.
The error is your call of malloc:
SortedListPtr slp = malloc(sizeof(SortedListPtr));
You are allocating the number of bytes that a pointer takes up, which is incorrect. It should be:
SortedListPtr slp = malloc(sizeof(struct SortedList));
Related
Firstly, forgive me if i do something wrong here since its my first time posting a question.
Can anyone tell me what i am doing incorrectly. When i attempt to iterate through a kd tree and print off all of my points, the 'pnt' attribute to the node i pass in changes its value to a memory address. I am looking at the 'print' and 'printPasser' function (both are located at the bottom). I know i'm doing something wrong with pointers but i just don't know what. If anyone spots something else wrong, please do comment
'''
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char axis;
struct node *left;
struct node *right;
unsigned int val;
struct point *pnt;
//struct point pnt;
} Node;
typedef Node * NodePtr;
typedef struct point
{
unsigned int xVal;
unsigned int yVal;
char *Datum;
} Point;
typedef Point * PointPtr;
typedef struct kdtree
{
struct node *root;
unsigned int xBound;
unsigned int yBound;
} kdTree;
typedef kdTree *kdTreePtr;
//|--------------------------------------------------
kdTreePtr create();
void insert(kdTree * tree, struct point pntInsert);
void insertVal(kdTree * tree, unsigned int xIn, unsigned int yIn, char * Datum);
struct point repeater(struct node * tmp, struct point * pnt);
void delete(kdTree * tree, struct point * pnt);
void destroy(kdTree * tree);
struct point pop(kdTree * tree);
void print(kdTree * tree);
void printPasser(struct node * root);
void insertAlt(kdTree * tree, struct point pntInsert);
void insertPasser(Node * root, struct point pntInsert);
struct point nearestNeighbor(kdTree * tree, struct point * pntInit);
struct point nearestNicestNeighbor(kdTree * tree, struct point * pntInit);
void scale(kdTree * tree, unsigned int xScaler, unsigned int yScaler);
void resize(kdTree * tree, unsigned int xBound, unsigned int yBound);
void analyze(struct node *root);
//|--------------------------------------------------
int main(void)
{
kdTree * basic;
basic = malloc(sizeof(kdTreePtr));
basic = create();
resize(basic, 30, 30);
//Point pntr;
Point pnt1;
Point* pntr1 = &pnt1;
pntr1->xVal = 2;
pntr1->yVal = 7;
pntr1->Datum = "Big";
Point pnt2;
Point* pntr2 = &pnt2;
pntr2->xVal = 3;
pntr2->yVal = 8;
pntr2->Datum = "Bigger";
print(basic);
insertAlt(basic, pnt1);
printf("Point: (%u,%u) main tester\n", basic->root->pnt->xVal, basic->root->pnt->yVal);
print(basic);
insert(basic, pnt2);
print(basic);
return 0;
}
kdTreePtr create()
{
kdTreePtr newTree = malloc(sizeof(kdTree));
newTree->xBound = 0;
newTree->yBound = 0;
newTree->root = malloc(sizeof(NodePtr));
newTree->root->left = NULL;
newTree->root->right = NULL;
newTree->root->pnt = NULL;
return newTree;
}
void resize(kdTree * tree, unsigned int xBound, unsigned int yBound)
{
tree->xBound = xBound;
tree->yBound = yBound;
}
void insertAlt(kdTree * tree, struct point pntInsert)
{
if (tree->root->pnt == NULL && tree->root->left == NULL && tree->root->right == NULL)
{
puts("empty");
//if(tree->root->pnt != NULL)
// printf("Point: (%u,%u) root\n", tree->root->pnt->xVal, tree->root->pnt->yVal);
tree->root->pnt = &pntInsert;
printf("Point: (%u,%u) root end\n", tree->root->pnt->xVal, tree->root->pnt->yVal);
}
else
{
puts("Iterate");
insertPasser(tree->root, pntInsert);
}
}
void insertPasser(Node * root, struct point pntInsert)
{
if (root->pnt == NULL && root->left != NULL && root->right != NULL)
{
if (root->axis == 'y')
{
if (pntInsert.yVal >= root->pnt->yVal)
insertPasser(root->right, pntInsert);
else
insertPasser(root->left, pntInsert);
}
else
{
if (pntInsert.xVal >= root->pnt->xVal)
insertPasser(root->right, pntInsert);
else
insertPasser(root->left, pntInsert);
}
}
else
{
Node *leftChild;
Node *rightChild;
rightChild = malloc(sizeof(NodePtr));
leftChild = malloc(sizeof(NodePtr));
unsigned int lower;
unsigned int xDif,yDif;
if (pntInsert.xVal >= root->pnt->xVal)
{
xDif = abs(pntInsert.xVal - root->pnt->xVal);
lower = root->pnt->xVal;
}
else
{
xDif = abs(root->pnt->xVal - pntInsert.xVal);
lower = pntInsert.xVal;
}
if (pntInsert.yVal >= root->pnt->yVal)
{
yDif = abs(pntInsert.yVal - root->pnt->yVal) ;
lower = root->pnt->yVal;
}
else
{
yDif = abs(root->pnt->yVal - pntInsert.yVal) ;
lower = pntInsert.yVal;
}
if (xDif >= yDif)
{
root->axis = 'y';
root->val = ((unsigned int)xDif / 2) + lower;
if (pntInsert.xVal >= root->pnt->xVal)
{
puts("test 1");
rightChild->pnt = &pntInsert;
leftChild->pnt = root->pnt;
root->right = rightChild;
root->left = leftChild;
root->pnt = NULL;
}
else
{
puts("test 2");
rightChild->pnt = root->pnt;
leftChild->pnt = &pntInsert;
*(root->right) = *rightChild;
*(root->left) = *leftChild;
root->pnt = NULL;
}
}
else
{
root->axis = 'x';
root->val = ((unsigned int)yDif / 2) + lower;
if (pntInsert.yVal >= root->pnt->yVal)
{
puts("test 3");
rightChild->pnt = &pntInsert;
leftChild->pnt = root->pnt;
root->right = rightChild;
root->left = leftChild;
root->pnt = NULL;
}
else
{
puts("test 4");
rightChild->pnt = root->pnt;
leftChild->pnt = &pntInsert;
root->right = rightChild;
root->left = leftChild;
root->pnt = NULL;
}
}
}
}
void insertVal(kdTree * tree, unsigned int xIn, unsigned int yIn, char * Datum)
{
Point pntInsert;
PointPtr pntInsertPtr = &pntInsert;
pntInsert.xVal = xIn;
pntInsert.yVal = yIn;
pntInsert.Datum = Datum;
insertAlt(tree, pntInsert);
//printf("%u,", tree->root->pnt->xVal);
//printf("%u\n", tree->root->pnt->yVal);
//printf("%u,", tree->root->pnt->yVal);
//printf("%u\n", tree->root->pnt->xVal);
}
void print(kdTree * tree)
{
if (tree->root->pnt == NULL && tree->root->left == NULL && tree->root->right == NULL)
puts("blank");
else
{
printf("Point: (%u,%u) \n", tree->root->pnt->xVal, tree->root->pnt->yVal);
printPasser(tree->root);
}
}
void printPasser(struct node * root)
{
printf("Point: (%u,%u) \n", root->pnt->xVal, root->pnt->yVal);
//PointPtr rootHolder =
if (root->left == NULL && root->right == NULL && root->pnt != NULL)
{
printf("Point: (%u,%u) \n", root->pnt->xVal, root->pnt->yVal);
}
else
{
printPasser(root->left);
printPasser(root->right);
}
}
'''
everything looks alright until i pass the node pointer into the 'printPasser' function where i take the point of root and get a new value that just looks to be the pointer values cast to an unsigned int.
I identified the following memory-related issues in your code:
kdTree * basic;
basic = malloc(sizeof(kdTreePtr));
basic = create();
You initialize basic twice. This is not a problem in itself, but it results in a memory leak of size kdTreePtr. Remove the first assignment.
newTree->root = malloc(sizeof(NodePtr));
Whenever you allocate an new Node, you only allocate a pointer-sized chunk of memory, not the size appropriate for a Node. You need to allocated sizeof(Node) bytes. There are multiple occurrences.
After fixing those, your code does not trigger a segmentation fault anymore (when compiling with optimizations enabled) and the output remains stable.
I have written the following code:
typedef struct List {
struct List* next;
void *value;
} List;
void freeList(List* list, void destroyElement(void*)) {
while(list != NULL) {
destroyElement(list->value);
struct List* n = list;
list = list->next;
free(n);
}
}
struct List* arr2list(void** array, int length, void* cpyElement(void*), void (*destroyElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
printf("array[%d] = %d\n",i,*(((int*)array)+i));
if (*tail == NULL) {
freeList(head, destroyElement);
return NULL;
}
tail[0]->value = cpyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
void printList(List* list, void echoElement(void*)) {
while (list != NULL) {
echoElement(list->value);
list = list->next;
}
}
void destroyElement(void* el) {
if (el != NULL) {
struct List* node = el;
node->next = NULL;
free(node);
}
}
void* cpyElement(void* el) {
int *p = malloc(sizeof(*p));
*p = *(int *) el;
return p;
}
void echoElement(void* el) {
if (el != NULL) {
printf("%d ", *(int *) el);
}
}
int main(int argc, char** argv) {
int array_length = argc - 1;
int* array = (int*) malloc(sizeof(*array) * array_length);
for (int i = 0; i < array_length; i++){
*(array + i) = atoi(argv[i + 1]);
}
struct List* root = arr2list((void*) array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
freeList(root,destroyElement);
free(array);
return 0;
}
The problem is with tail[0]->value = cpyElement(array[i]);. I get a segmentation fault error for this part. If I write it cpyElement(((int*)array)+i); it works but I want the function arr2list to be generic and not to mention int. How can I solve it? I think that I understand it's impossible to convert void* to int* because it does not know which size to use so is it possible to hear some suggestions on how to approach this issue so it will work? Maybe change the array argument?
You need to create an array of pointers to ints and then pass that. Yes, it's a lot of malloc calls, but it's necessary (since you're using void *).
int main(int argc, char** argv) {
struct List *root;
int i, array_length = argc - 1;
int** array = malloc(sizeof(*array) * array_length);
for (i = 0; i < array_length; i++){
array[i] = malloc(sizeof(*array[i]));
*array[i] = atoi(argv[i + 1]);
}
root = arr2list((void **)array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
freeList(root,destroyElement);
free(array);
return 0;
}
This code:
void destroyElement(void* el) {
if (el != NULL) {
struct List* node = el;
node->next = NULL;
free(node);
}
}
will then need to be changed to (in fact, it only worked before due to a platform-specific bug):
void destroyElement(void* el) {
free(el);
}
Also, do not cast the result of malloc. That means no (int *)malloc(...). Just use malloc(...), it's safer and doesn't cover up errors.
The problem with void * is that while you can freely convert other pointer types to void * and back again and get the original pointer back, you need to do that directly -- you can't pass a void ** where it points at anything other than void *'s and expect it to work.
Even worse, in your case, you're passing an array of int where an array of void * are expected. You can deal with this by casting yout ints to intptr_t and thence to void * to store in your list -- you'll have to do that double-cast back again to get them out again:
void echoElement(void* el) {
printf("%d ", (int)(intptr_t)el);
}
int main(int argc, char** argv) {
int array_length = argc - 1;
void *array = malloc(sizeof(*array) * array_length);
for (int i = 0; i < array_length; i++) {
array[i] = (void *)(intptr_t)atoi(argv[i + 1]);
}
struct List* root = arr2list((void*) array,array_length,cpyElement, destroyElement);
printList(root,echoElement);
It runs ok in my Xcode so can anyone tell me what's the problem?
I tested and the problem is in reallocing space for stack but I don't understand the error..
The test case is [1,null,2,3] so 1 is root, 2 is 1's right child, 3 is 2's left child. The solution should return the array [1,2,3].
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*
**
* Return an array of size *returnSize.
* Note: The returned array must be malloced, assume caller calls free().
*/
struct TreeNode* cercaRoot(struct TreeNode* root, struct TreeNode** stack, int* stackSize){
if (root->left){
*stackSize += 1;
stack = realloc(stack, (*stackSize)*sizeof(struct TreeNode*));
stack[*stackSize-1] = root;
return root->left;
} else if (root->right){
return root->right;
} else{
while(*stackSize){
root = stack[*stackSize-1];
if (root->right) {
*stackSize -= 1;
stack = realloc(stack, (*stackSize)*sizeof(struct TreeNode*));
return root->right;
} else {
*stackSize -= 1;
stack = realloc(stack, (*stackSize)*sizeof(struct TreeNode*));
}
}
return NULL;
}
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize = 0;
if (root==NULL) return NULL;
int* array = calloc(1, sizeof(int));
array[0]=root->val;
*returnSize += 1;
int stackSize = 0;
struct TreeNode** stack = calloc(1, sizeof(struct TreeNode*));
root = cercaRoot(root, stack, &stackSize);
while (root){
array = realloc(array, (*returnSize+1)*sizeof(int));
array[*returnSize]=root->val;
*returnSize+=1;
root = cercaRoot(root, stack, &stackSize);
}
//free(stack);
return array;
}
I'm not getting any error with this code
Output is:
ret[0] = 1
ret[1] = 2
ret[2] = 3
#include <stdio.h>
#include <stdlib.h>
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
/*
**
* Return an array of size *returnSize.
* Note: The returned array must be malloced, assume caller calls free().
*/
struct TreeNode* cercaRoot(struct TreeNode* root, struct TreeNode** stack, int* stackSize){
if (root->left){
*stackSize += 1;
stack = realloc(stack, (*stackSize)*sizeof(struct TreeNode*));
stack[*stackSize-1] = root;
return root->left;
} else if (root->right){
return root->right;
} else{
while(*stackSize){
root = stack[*stackSize-1];
if (root->right) {
*stackSize -= 1;
stack = realloc(stack, (*stackSize)*sizeof(struct TreeNode*));
return root->right;
} else {
*stackSize -= 1;
stack = realloc(stack, (*stackSize)*sizeof(struct TreeNode*));
}
}
return NULL;
}
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize = 0;
if (root==NULL) return NULL;
int* array = calloc(1, sizeof(int));
array[0]=root->val;
*returnSize += 1;
int stackSize = 0;
struct TreeNode** stack = calloc(1, sizeof(struct TreeNode*));
root = cercaRoot(root, stack, &stackSize);
while (root){
array = realloc(array, (*returnSize+1)*sizeof(int));
array[*returnSize]=root->val;
*returnSize+=1;
root = cercaRoot(root, stack, &stackSize);
}
free(stack);
return array;
}
struct TreeNode* nodeRoot;
int main(int argc, char** argv) {
int stackSize = 0;
int returnSize = 0;
nodeRoot = malloc(sizeof(nodeRoot));
struct TreeNode* nodeLeft = malloc(sizeof(nodeLeft));
struct TreeNode* nodeRight = malloc(sizeof(nodeRight));
nodeRoot->left = nodeLeft;
nodeRoot->right = nodeRight;
nodeRoot->val = 1;
nodeRoot->left = NULL;
nodeRoot->right->val = 2;
nodeRoot->right->left = malloc(sizeof(nodeLeft));
nodeRoot->right->left->val = 3;
int* ret = preorderTraversal(nodeRoot, &returnSize);
if(ret != NULL){
for(int i = 0; i < 3; i++){
printf("ret[i] = %d\n",ret[i]);
}
}
return (EXIT_SUCCESS);
}
If I use sizeof(ret) in the for loop then I get:
ret[0] = 1
ret[1] = 2
ret[2] = 3
ret[3] = 0
ret[4] = 0
ret[5] = 0
ret[6] = 33
ret[7] = 0
Which is expected given the number of valid nodes assigned to the array.
Anyway, the logic seems fine. My first question would be how are you declaring your test case?
I'm implementing a graph traversal breadth-first search that I found here. However, their implementation involves integers and without any linked list. I was playing around with it a little bit I have no luck in getting any results because it doesn't seem to work as intended.
This is the code that I currently have:
(main.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct s_list
{
struct s_list *next;
void *content;
} t_list;
typedef struct s_queue
{
t_list *first;
t_list *last;
} t_queue;
typedef struct s_node
{
struct s_node *next;
int vertex;
} t_node;
typedef struct s_graph
{
t_node **adj_lists;
int *visited;
int total_vertices;
} t_graph;
/*Graph functions*/
t_node *create_node(int vertex);
t_graph *create_graph(int vertices);
void add_edge(t_graph *graph, int src, int dst);
void bfs(t_graph *graph, int start_vertex);
/*Misc functions*/
void my_putstr(char *str);
void *my_memalloc(size_t size);
void *my_memset(void *ptr, int value, size_t num);
void my_bzero(void *s, size_t n);
/*Queue functions*/
t_queue *init_queue(void);
void enqueue(t_queue *queue, void *content);
void *dequeue(t_queue *queue);
void *peek_queue(t_queue *queue);
int is_empty(t_queue *queue);
void my_print_queue(t_queue *queue);
t_node *create_node(int val)
{
t_node *new_node;
new_node = (t_node*)my_memalloc(sizeof(t_node));
new_node->vertex = val;
new_node->next = NULL;
return (new_node);
}
t_graph *create_graph(int vertices)
{
int i;
t_graph *graph;
i = 0;
graph = my_memalloc(sizeof(t_graph));
graph->total_vertices = vertices;
printf("graph->total_vertices: %d\n", vertices);
graph->adj_lists = (t_node**)my_memalloc(sizeof(t_node));
graph->visited = my_memalloc(sizeof(int) * vertices);
while (i < vertices)
{
graph->adj_lists[i] = NULL;
graph->visited[i] = 0;
i++;
}
return (graph);
}
void add_edge(t_graph *graph, int src, int dst)
{
t_node *new_node;
new_node = create_node(dst);
new_node->next = graph->adj_lists[src];
graph->adj_lists[src] = new_node;
new_node = create_node(src);
new_node->next = graph->adj_lists[dst];
graph->adj_lists[dst] = new_node;
}
void bfs(t_graph *graph, int start_vertex)
{
t_queue *queue;
queue = init_queue();
graph->visited[start_vertex] = 1;
printf("start_vertex before enqueue %d\n", start_vertex);
my_print_queue(queue);
enqueue(queue, &start_vertex);
printf("start_vertex after enqueue %d\n", start_vertex);
while (!is_empty(queue))
{
my_print_queue(queue);
int current_vertex;
t_node *tmp;
current_vertex = (int)dequeue(queue);
printf("Visited %d nodes\n", current_vertex);
tmp = graph->adj_lists[current_vertex];
while (tmp)
{
int adj_vertex;
adj_vertex = tmp->vertex;
if (graph->visited[adj_vertex] == 0)
{
graph->visited[adj_vertex] = 1;
printf("%d\n", graph->visited[adj_vertex]);
enqueue(queue, &adj_vertex);
my_print_queue(queue);
}
tmp = tmp->next;
}
}
}
t_queue *init_queue(void)
{
t_queue *node;
node = (t_queue *)my_memalloc(sizeof(t_queue));
node->first = NULL;
node->last = NULL;
return (node);
}
void enqueue(t_queue *queue, void *content)
{
t_list *node;
node = (t_list *)my_memalloc(sizeof(t_list));
node->content = content;
node->next = NULL;
if (!queue->last)
{
queue->last = node;
queue->first = node;
}
else
{
queue->last->next = node;
queue->last = queue->last->next;
}
return ;
}
void *dequeue(t_queue *queue)
{
t_list *tmp;
tmp = queue->first;
if (!tmp)
return (NULL);
else
{
queue->first = tmp->next;
return (tmp->content);
}
}
void *peek_queue(t_queue *queue)
{
if (queue->first == NULL)
return (NULL);
return (queue->first->content);
}
int is_empty(t_queue *queue)
{
return (queue->first == NULL);
}
void my_print_queue(t_queue *queue)
{
if (is_empty(queue))
my_putstr("Empty queue\n");
else
{
while (!is_empty(queue))
{
int val = *(int *)queue->first->content;
printf("%d \n", val);
dequeue(queue);
}
}
}
void my_putstr(char *str)
{
int i;
i = 0;
while (str[i])
write(1, &str[i++], 1);
}
void *my_memalloc(size_t size)
{
char *str;
str = ((void*)malloc(size));
if (!str)
return (NULL);
my_bzero(str, size);
return (str);
}
void *my_memset(void *ptr, int value, size_t num)
{
unsigned char *uptr;
uptr = (unsigned char*)ptr;
while (num--)
*uptr++ = (unsigned char)value;
return (ptr);
}
void my_bzero(void *s, size_t n)
{
my_memset(s, 0, n);
}
int main(void)
{
t_graph *graph;
graph = create_graph(3);
add_edge(graph, 0, 1);
add_edge(graph, 0, 2);
add_edge(graph, 2, 4);
bfs(graph, 2);
return (0);
}
I did some research like type-casting a void pointer to make it into a char or int, or any other data type. What happens is that the create graph does it's creation after calling it; but, when it comes to the bfs, it doesn't show the correct output after. It never prints the visited vertices. I'm getting a result of
graph->total_vertices: 3
start_vertex before enqueue 2
Empty queue
start_vertex after enqueue 2
2
Visited 0 nodes
The expected output should be something like this:
Queue contains
0 Resetting queueVisited 0
Queue contains
2 1 Visited 2
Queue contains
1 4 Visited 1
Queue contains
4 Resetting queueVisited 4
I've been trying to figure out by myself to the point that I'm burning out. What am I doing wrong in here?
While posting this, I will keep debugging on my side and see what it does with a couple print statements.
I can point out the following mistakes:
my_print_queue destroys your queue. So anything after it's call works with empty queue.
You don't fill visited with to zeroes. By default their values is pretty much arbitrary. Since you compare their values with 0, it makes sense that comparison fails.
at the moment I'm working on an implementation of a balanced B-Tree in C. I decided to use doubly linked lists but I have run into some problems. At the moment I get warnings for line 94, 95 and 96 because apparently the pointer types are incompatible.
I really don't see how and any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int data1;
int data2;
int data2exists; // no: 0 , yes: 1
struct node * parent;
struct node * left;
struct node * middle;
struct node * right;
} node;
node * insert(int *, node *, node *);
void getInput(int *);
node * createNode(int *);
void quickSwap(node *, int *, int *, int *, int *);
node * splitLeaf(int *, int *, int *, node *, node *);
void printTree(node *);
void main() {
int input;
getInput(&input);
node * root = createNode(&input);
getInput(&input);
insert(&input, root, root); // returns current pos
getInput(&input);
insert(&input, root, root); // returns current pos
getInput(&input);
insert(&input, root, root); // returns current pos
printTree(root);
}
node * insert(int * input, node * root, node * currentPos) {
printf("data1: [%i], data2: [%i], d2exists: [%i], input: [%i]\n", currentPos->data1, currentPos->data2, currentPos->data2exists, *input);
if (currentPos->left == NULL && currentPos->middle == NULL && currentPos->right == NULL) {
// no children
if (*input > currentPos->data1 && currentPos->data2exists == 0) {
// data1 < input, no data2
currentPos->data2 = *input;
currentPos->data2exists = 1;
return(currentPos);
// printf("CASE1: data1 < input, no data2, no children\n");
}
if (*input < currentPos->data1 && currentPos->data2exists == 0) {
// data1 > input, no data2
currentPos->data2 = currentPos->data1;
currentPos->data1 = *input;
currentPos->data2exists = 1;
return(currentPos);
// printf("CASE2: data1 > input, no data2, no children\n");
}
if (currentPos->data2exists == 1) {
// data2 exists
int smallest;
int middle;
int largest;
quickSwap(currentPos, input, &smallest, &middle, &largest);
printf("s: [%i] m: [%i] l: [%i]\n", smallest, middle, largest);
root = splitLeaf(&smallest, &middle, &largest, currentPos, root);
}
}
return(currentPos);
}
void printTree(node * root) {
if (root->parent != NULL) {
printf("printTree() did not receive root!!!!\n");
return;
}
else {
printf("%i || %i", root->data1, root->data2);
printf("\n");
// printf("%i || %i", root->left->data1, root->left->data2);
// printf("\t\t");
// printf("%i || %i", root->middle->data1, root->middle->data2);
// printf("\t\t");
// printf("%i || %i", root->right->data1, root->right->data2);
// printf("\n");
}
}
node * splitLeaf(int * smallest, int * middle, int * largest, node * currentPos, node * root) {
// this function needs to return root!
if (currentPos->parent == NULL) {
// currentPos is root
// create a parent with median
node * root = createNode(middle);
node * left = createNode(smallest);
node * middle = createNode(largest);
// genau hier gehts weiter! hier müssen root, left und, middle verknüpft werden!
root->left = left;
root->middle = middle;
left->parent = middle->parent = root;
// printf("root-addr: %i, left->parent: %i\n", root, left->parent);
return(root);
}
}
void quickSwap(node * currentPos, int * input, int * smallest, int * middle, int * largest) {
// writes values to *smallest, *middle and *largest ordered by size
if (currentPos->data1 > currentPos->data2) {
*smallest = currentPos->data2;
*middle = currentPos->data1;
}
else {
*smallest = currentPos->data1;
*middle = currentPos->data2;
}
if (*input < *smallest) {
*largest = *middle;
*middle = *smallest;
*smallest = *input;
}
else if (*input < *middle) {
*largest = *middle;
*middle = *input;
}
else {
*largest = *input;
}
}
node * createNode(int * input) {
node * ptr = (node*) malloc(sizeof(node));
ptr->data1 = * input;
ptr->data2 = 0;
ptr->data2exists = 0;
ptr->parent = NULL;
ptr->left = NULL;
ptr->middle = NULL;
ptr->right = NULL;
return(ptr);
}
void getInput(int * input) {
printf("Enter a number\n");
scanf(" %i",input);
}
Aha! The problem is a tricky one. It has to do with the definition of your node struct. The members parent, left, middle and right are of type struct node but you typedefed the struct to be node directly. My guess is that GCC ignores the undefined struct node and hopes it's defined somewhere else.
In other words: the type node exists, but struct node doesn't. Therefore when you try to assign a node to a struct node GCC doesn't know what to do. So change
typedef struct {
...
} node;
to
typedef struct node {
...
} node;
Although it might be wiser to use another name for the struct node than the type node.
Some nitpicks:
GCC complains that main doesn't return an int (just return 0;)
In splitLeaf you're redeclaring the arguments int * middle to node * middle and the same with root.
splitLeaf doesn't return anything when currentPos->parent isn't NULL (though maybe you haven't finished the function yet)