I am using nested structures to create a BST but I have a problem while inserting because I use a comparison function to do so!
here is my comparison function
int compare_doubles(const void* a, const void* b)
{
const double* a_ = (const double*)a;
const double* b_ = (const double*)b;
return (*a_ > *b_) - (*a_ < *b_);
}
int compare_int(const void* a, const void* b)
{
const int* a_ = (const int*)a;
const int* b_ = (const int*)b;
return (*a_ > *b_) - (*a_ < *b_);
}
and here is the structures
typedef struct tree_t BinarySearchTree; //opaque structure declared on BinarySearchTree.h
struct tree_t{
int (*comparison)(const void *, const void *);
struct tree_t* lchild;
struct tree_t* rchild;
struct t_node* noeud;
};
struct t_node{
const void *key;
const void *data;
City *city;
};
and this is my function to create a new BST
BinarySearchTree* newBST(int comparison_fn_t(const void *, const void *))
{
BinarySearchTree *t = (struct tree_t *)malloc(sizeof(struct tree_t));
t->comparison = comparison_fn_t;
t->lchild = t->rchild = NULL;
t->noeud = NULL;
return t;
}
This is my insertion function
BinarySearchTree* insertInBST(BinarySearchTree* bst, const void* key, const void* value) {
BinarySearchTree *t = bst;
if (bst->noeud == NULL)
{
struct t_node* n = (struct t_node *)malloc(sizeof(struct t_node));
t->noeud = n;
t->noeud->data = value;
t->noeud->key = key;
return t;
}
if ((bst->comparison(&key,&(bst->noeud->key))) < 0){
bst->lchild = insertInBST(bst->lchild, key, value);
}
else if ((bst->comparison(&key,&(bst->noeud->key))) >= 0){ // handle duplicate keys
bst->rchild = insertInBST(bst->rchild, key, value);
}
return bst;
}
when I try to run my code using these tests I get segfault (core dumped)
this is my main function
int main()
{
int *t =15;
int *g = 13;
int *j =15;
int *k = 13;
BinarySearchTree *root = newBST(&compare_doubles);
insertInBST(root, k,j);
insertInBST(root, t, g);
}```
Your comparison function is overly complicated (*a_ > *b_) - (*a_ < *b_) as you mix comparison (<, >) and arithmetic (-) operations. #WhozCraig suggested (a < b) ? -1 : (b < a).
You need to define struct City.
You need to #include <stdlib.h> for malloc.
In main you are casting integers to pointers. The compiler warning for the first case is:
warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
As in int t = 15; int g = 13 and later insertInBST(root, &t, &g)
In main you use the wrong compare function (doubles instead of int).
I ran your code through gdb and it crashes in if (bst->noeud == 0) because insertInBST(root, t, g) invokes bst->rchild = insertInBST(bst->rchild, key, value) but bst->rchild is NULL.
In insertInBST, you only need to do the comparison once to figure out if you need the left or right branch.
Related
So I have a struct that I want to sort by each element, ascending and descending.
I'm creating 14 different sort function because I don't know how to pass struct element as a function argument.
I want to cut it to 2 sort function ascending & descending, so I don't have 14 functions.
How do I deal with this?? Thanks in advance!
struct propertySales{
unsigned int tanggal[3];
char pelanggan[30];
char jenisProperty[30];
char namaProperty[30];
int jumlahProperty;
double hargaProperty;
double totalPembayaran;
}Arr[100], compare[100], temp;
void sort_totalPembayaran_descending(){
int currentIndex=index_counter();
for(int i=0; i<(currentIndex-1); i++){
for (int j=0; j<(currentIndex-i-1); j++){
if (compare[j].totalPembayaran < compare[j+1].totalPembayaran){
swap(&compare[j], &compare[j+1]);
}
}
}
system("cls");
printf("Sorting berdasarkan total pembayaran (Descending)\n");
print_column();
print_data(compare);
}
If you wish to sort by the totalPembayaran field, then you want to create a comparison function which takes two void pointers to propertySales structs.
int compare_totalPembayaran_asc(const void *a, const void *b) {
struct propertySales *c = (struct propertySales *)a;
struct propertySales *d = (struct propertySales *)b;
if (c->totalPembayaran < d->totalPembayaran)
return -1;
else if (c->totalPembayaran > d->totalPembayaran)
return 1;
else
return 0;
}
Now you can provide this to qsort to sort your array in ascending order.
qsort(arr, 100, sizeof(propertySales), compare_totalPembayaran_asc);
Comparing in descending order just requires writing another comparison function and changing the values returned.
int compare_totalPembayaran_desc(const void *a, const void *b) {
struct propertySales *c = (struct propertySales *)a;
struct propertySales *d = (struct propertySales *)b;
if (c->totalPembayaran < d->totalPembayaran)
return ...;
else if (c->totalPembayaran > d->totalPembayaran)
return ...;
else
return 0;
}
In my code, there is a binary tree struct defined as :
typedef struct bintreestruct *bintree;
struct bintreestruct
{
double num;
char *s;
bintree l, r;
};
I wanted to insert a node into this binary search tree. Here is the function:
void insbintree(double i, char *s, bintree *t)
{
if (t == NULL)
{
bintree temp = (struct bintreestruct *)malloc(sizeof(struct bintreestruct));
temp->s = s;
temp->num = i;
temp->l = temp->r = NULL;
return temp;
}
if (strcmp(s, t->s) < 0)
t->l = insert(t->l, s);
else if (strcmp(s, t->s) >= 0)
t->r = insert(t->r, s);
return t;
}
I am getting the error error: ‘*t’ is a pointer; did you mean to use ‘->’? 62 | if (strcmp(s, t->s) < 0)
Either I am creating the new node incorrectly or accessing the elements inside in
the wrong way using pointers. Not sure how to correct this error
It seems you are trying to write a recursive function because it calls itself.
As the function has return statements with expressions then its return type shall not be void.
Also this parameter declaration bintree *t is equivalent to struct bintreestruct ** due to this typedef
typedef struct bintreestruct *bintree;
But within the function you are trying to use it as having the type struct bintreestruct *.
And in these calls of the function itself
t->l = insert(t->l, s);
t->r = insert(t->r, s);
there are used incomplete and not correctly ordered lists of arguments.
Taking all this into account the function can be declared and defined at least the following way
bintree insbintree(double i, char *s, bintree t)
{
if (t == NULL)
{
t = malloc( sizeof( struct bintreestruct ) );
t->s = s;
t->num = i;
t->l = t->r = NULL;
}
else if ( strcmp(s, t->s) < 0 )
{
t->l = insert(i, s, t->l);
}
else
{
t->r = insert(i, s, t->r );
}
return t;
}
Pay attention to that using the typedef declaration for the pointer type is a bad idea. It only confuses readers of the code.
I have generic link list in C that know how to push struct to list.
The problem is the I can't implement generic search in those link list:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct Node
{
void *data;
struct Node *next;
};
void push(struct Node** head_ref, void *new_data, size_t data_size)
{
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = malloc(data_size);
new_node->next = (*head_ref);
int i;
for (i=0; i<data_size; i++)
*(char *)(new_node->data + i) = *(char *)(new_data + i);
(*head_ref) = new_node;
}
struct A
{
int a1;
long a2;
};
struct B
{
long b1;
int b2;
};
void find_a1_in_a_list (int desire_a1 , struct Node *a_list)
{
struct A *a;
while(NULL != a_list)
{
a = (struct A*) a_list->data;
if(a->a1 == desire_a1)
printf("found!\n");
a_list = a_list->next;
}
}
void find_b1_in_b_list (long desire_b1 , struct Node *b_list)
{
struct B *b;
while(NULL != b_list)
{
b = (struct B*) b_list->data;
if(b->b1 == desire_b1)
printf("found!\n");
b_list = b_list->next;
}
}
void find_generic (void* desire_value,int off,struct Node *list)
{
while(NULL != list)
{
void* check_value_void = list->data + off;
int check_value_cast = *(int *) check_value_void; //How to know if cast to int or long ?????
if(check_value_cast == *(int *)desire_value) //How to know if cast to int or long ?????
printf("found generic!\n");
list = list->next;
}
}
void main()
{
struct Node *a_list = NULL;
struct A a;
a.a1=1;
a.a2=2;
push(&a_list, &a, sizeof(struct A));
find_a1_in_a_list(1,a_list);
struct Node *b_list = NULL;
struct B b;
b.b1=1;
b.b2=2;
push(&b_list, &b, sizeof(struct B));
find_b1_in_b_list(1,b_list);
//tried to make it generic
int search = 3;
find_generic(&search,offsetof(struct A, a2),a_list);
}
As you can I tried to makes generic search in function find_generic by passing the offset to the value in struct, that code works but only for int
but how can I pass to this generic function if I want to search int or long ,so I will know how to makes cast ?
Is there any way to cast void * by size so I can pass sizeof(int) or sizeof(long) and makes the casting by this value? or maybe another way?
Passing the compare function directly instead of playing with offsetof/sizeof will be more flexible:
struct Node *find_generic (struct Node *list,
int (*fn_cmp)(void const *a, void const *b),
void const *data)
{
while (list) {
if (fn_cmp(list->data, data) == 0)
break;
list = list->next;
}
return list;
}
and then create custom compare functions
static int cmp_A(void const *a_, void const *b_)
{
struct A const *a = a_;
struct A const *b = b_;
if (a->a1 == b->a1 && a->a2 == b->a2)
return 0;
return 1;
}
and call it like
struct A key = {
.a1 = 23,
.a2 = 42,
};
find_generic(a_list, cmp_A, &key);
I'm trying to create cluster with dynamic array objects.
Struct definitions are following:
struct obj_t {
int id;
float x;
float y;
};
struct cluster_t {
int size;
int capacity;
struct obj_t *obj;
};
Function for adding object to cluster is:
void append_cluster(struct cluster_t *c, struct obj_t obj)
{
if(c->capacity < (c->size + 1))
{
c = resize_cluster(c, c->size + 1);
}
if(c == NULL)
return;
c->obj[c->size] = obj; //at this point program crashes.
c->size++;
}
EDIT: Here is resize_cluster() function:
struct cluster_t *resize_cluster(struct cluster_t *c, int new_cap)
{
if (c->capacity >= new_cap)
return c;
size_t size = sizeof(struct obj_t) * new_cap;
void *arr = realloc(c->obj, size);
if (arr == NULL)
return NULL;
c->obj = (struct obj_t*)arr;
c->capacity = new_cap;
return c;
}
EDIT 2: Here is cluster initialization:
void init_cluster(struct cluster_t *c, int cap)
{
c = malloc(sizeof(struct cluster_t));
c->size = 0;
c->capacity = cap;
c->obj = (struct obj_t*)malloc(cap * sizeof(struct obj_t));
}
I can't figure out why program crashes when I try to add the object to the array in cluster. Is accessing array this way wrong? If so, how should I access it?
The issue is the call to init_cluster(). The c parameter is passed-by-value, so whatever you are sending remains unmodified:
struct cluster_t * c;
init_cluster(c, 1);
// c is uninitialized!
One fix would be to pass a pointer to an object:
struct cluster_t c;
init_cluster(&c, 1);
Then remove c = malloc(sizeof(struct cluster_t)); from init_cluster();
Or, you could create an alloc_cluster function:
struct cluster_t * alloc_cluster(int cap)
{
c = malloc(sizeof(struct cluster_t));
c->size = 0;
c->capacity = cap;
c->obj = malloc(cap * sizeof(struct obj_t));
return c;
}
And call it like:
struct cluster_t *c = init_cluster(1);
I want to get any types of variables in my code, so I did a void * type to accept others. But I can get in char * but not in int values. And I don't understand how I can did it.
Here my code :
void insertion(t_liste *liste, void *newValue) {
t_element *new = malloc(sizeof(void *));
int i;
int *j = &i;
if (liste == NULL || new == NULL) {
exit(EXIT_FAILURE);
}
if (newValue == j || (char *)newValue) {
new->value = newValue;
new->suivant = liste->premier;
liste->premier = new;
liste->taille++;
new->index = liste->taille;
}
}
In my main I did
insertion(maListe, 5);
it didn't work, but if I did this:
insertion(maListe, "test");
It works.
But I want both works !
Here my .h
typedef struct s_element t_element;
typedef struct s_liste t_liste;
struct s_element{
int index;
void *value;
t_element *suivant;
t_element *precedent;
};
struct s_liste{
t_element *premier;
t_element *dernier;
int taille;
};
Any idea ?
OK! In your function
void insertion(t_liste *liste, void *newValue)
you are taking a argument of type void* . In the first case when you send a string(char *) the base address of the string is passed , so address is taken to newValue,but in case when you pass a number,say 5 ,integer is passed to newValue where it expects an address.