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.
Related
I've decided to go through all of D&R's exercises and in doing so I have encountered a peculiar event. Based on the book's own addtree function I modified it for my own structure:
struct gnode {
char **words;
int count;
struct gnode *left;
struct gnode *right;
};
And it now is:
struct gnode *addtree(struct gnode *p, char *w) {
int cond;
if (p == NULL) {
printf("init null node\n");
p = (struct gnode *)malloc(sizeof(struct gnode));
//MISTAKE I WAS MAKING:
// struct gnode *p =(struct gnode *)malloc(sizeof(struct gnode));
//p would be NULL every time.
p->count = 1;
p->words = malloc(8);
p->words[0] = strdup2(w);
p->left = p->right = NULL;
} else
if ((cond = compare(w, p->words[0])) == 0) {
printf("comp hit\n");
p->count++;
p->words = realloc(p->words, p->count * 8);
p->words[p->count] = strdup2(w);
} else
if (cond < 0)
p->left = addtree(p->left, w);
else
p->right = addtree(p->right, w);
return p;
}
I would like to know why if a local pointer with the same name as the argument is returned, it is NULL every time.
There are multiple issues in your code:
when the tree is empty, the line in the original code struct gnode *p = (struct gnode *)malloc(sizeof(struct gnode)); allocates a new gnode object, but also defines a new identifier p with a local scope, effectively shadowing the argument name. Hence the argument variable p is not updated and ultimately the original value (a null pointer) is returned by return p; at the end of the function.
You can prevent this type of silly mistake by increasing the compiler warning level: gcc -Wall -Wextra or clang -Weverything
the allocation p->words = malloc(8); is not portable. You should use:
p->words = malloc(sizeof(*p->words));
same for p->words = realloc(p->words, p->count * 8), it should be
p->words = realloc(p->words, p->count * sizeof(*p->words));
furthermore, since p->count was already incremented, setting the duplicate word should use:
p->words[p->count - 1] = strdup2(w);
why use strdup2(w) instead of strdup(w)?
w should probably be defined as const char *w.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct gnode {
char **words;
int count;
struct gnode *left;
struct gnode *right;
};
struct gnode *addtree(struct gnode *p, const char *w) {
int cond;
if (p == NULL) {
printf("init null node\n");
p = malloc(sizeof(*p));
p->count = 1;
p->words = malloc(sizeof(*p->words));
p->words[0] = strdup2(w);
p->left = p->right = NULL;
} else
if ((cond = compare(w, p->words[0])) == 0) {
printf("comp hit\n");
p->count++;
p->words = realloc(p->words, p->count * sizeof(*p->words));
p->words[p->count - 1] = strdup2(w);
} else
if (cond < 0) {
p->left = addtree(p->left, w);
} else {
p->right = addtree(p->right, w);
}
return p;
}
I would like to know why if a local pointer with the same name as the argument is returned, it is NULL everytime.
You weren't returning a local variable.
You created a local variable, set it to allocated space, and used it to set some fields.
Then its scope ended at the end of the if block. It no longer shadowed the outer variable.
The outer variable p was never modified from its original null value.
You can avoid this by not shadowing variables.
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.
I am coding a data structure involving a set of two linked lists, stacked on top of each other. When trying to initialize the set in my test harness, I get a segmentation error. I've commented out all value setters to test to see if I could figure out the error myself, but I could not.
Prototype for init method:
Test Harness:
int
main( )
{
list the_list;
int used = 0;
int values[MAX_VALUES];
char input[LINE_LEN];
char command;
int argument;
int num_found;
bool result;
set_t lower;
set_t upper;
the_list->lower = lower;
the_list->upper = upper;
input[0] = '\0';
input[LINE_LEN-1] = '\0';
fgets( input, LINE_LEN, stdin );
while (*input != 'q') {
num_found = sscanf( input, "%c %d", &command, &argument );
if (num_found > 0) {
switch (command) {
case 'i':
printf ("Request to initialize the set\n");
if (num_found == 1) {
result = set_init( &the_list );
} else {
result = set_init( NULL );
}
printf ("Returned as %d\n", result);
break;
34,0-1 8%
Init method:
bool
set_init( list *the_list )
{
bool initialized = false;
if (the_list !=NULL ) {
/* We have space to initialize. */
the_list->lower->set_size = 0;
/* the_list->lower->head = NULL;
the_list->lower->tail = NULL;
the_list->lower->set_level = 1;
the_list->lower->ready = true;
the_list->upper->set_size = 0;
the_list->upper->head = NULL;
the_list->upper->tail = NULL;
the_list->upper->set_level = 2;
the_list->upper->ready = true;*/
initialized = true;
}
return initialized;
}
Also my struct definitions for my set, linked list, and node structs:
typedef struct _set_node_t {
test_type_t *data;
struct _set_node_t *next;
struct _set_node_t *below;
} set_node_t;
/* the set itself keeps track of the head and the tail of the linked list */
typedef struct {
int set_size;
bool ready;
set_node_t *head;
set_node_t *tail;
int set_level;
} set_t;
typedef struct {
set_t *lower;
set_t *upper;
}list;
The only thing that could be crashing here is this line:
the_list->lower->set_size = 0;
Either the_list or the_list->lower must be uninitialized or NULL or be pointing to invalid or inaccessible memory.
Edit: Yeah this line will crash because you don't initialize the_list.lower:
result = set_init( &the_list );
And this line will crash because you're passing NULL:
result = set_init( NULL );
I'm trying to build a binary search tree , that store word/definition pairs.
so my struct is like this :
struct BinarySearchTree_t
{
char *word,*def;
struct BinarySearchTree_t *left;
struct BinarySearchTree_t *right;
};
typedef struct BinarySearchTree_t BinarySearchTree;
So I've been blocked in insertWord function that inserts a word/definition pair in a binary search tree. Neither the word nor the definition may be NULL. NULL is considered as a special value. If the word already exists then this function replaces the current definition by the new one and returns the old one.
This is the function:
char* insertWord(BinarySearchTree *tree, char *word, char *definition)
{
int r;
char* a;
if((tree==NULL))
{
BinarySearchTree* tmp;
tmp = malloc( sizeof( BinarySearchTree ) );
tmp->word= malloc((strlen(word)+1)*sizeof(char));
tmp->def = malloc((strlen(definition)+1)*sizeof(char));
strcpy(tmp->word, word);
strcpy(tmp->def , definition);
tmp->left = NULL;
tmp->right = NULL;
*tree = *tmp;
return NULL;
}
else
{
a= tree->word;
r= strcmp(a,word);
if(r = 0)
{
char* ret= tree->def;
strcpy(tree->word, word);
strcpy(tree->def , definition);
return ret;
}
else if(r<0)
return insertWord((tree->right),word,definition);
else
return insertWord((tree->left),word,definition);
}
}
What is the problem?
Edited : the correct function:
char* insertWord(BinarySearchTree **tree, char *word, char *definition)
{
int r;
char* a;
if(((*tree)==NULL) || ((*tree)!=NULL && (*tree)->mot==NULL))
{
BinarySearchTree* tmp;
tmp = malloc( sizeof( BinarySearchTree ) );
tmp->left = NULL;
tmp->right = NULL;
tmp->mot = malloc((strlen(word)+1)*sizeof(char));
tmp->def = malloc((strlen(definition)+1)*sizeof(char));
strcpy(tmp->mot , word);
strcpy(tmp->def , definition);
*tree = tmp;
return NULL;
}
else
{
a= (*tree)->mot;
r= strcmp(a,word);
if(r == 0)
{
char* ret= (*tree)->def;
strcpy((*tree)->mot , word);
strcpy((*tree)->def , definition);
return ret;
}
else if(r<0)
return insertWord(&((*tree)->right),word,definition);
else
return insertWord(&((*tree)->left),word,definition);
}
}
So, you are trying to initialize the pointer to root of your SearchTree, the first time it's accessed, right? The problem is that you are modifying a local copy of the pointer *tree and not the actual pointer that's present in the parent (calling) function. If you plan to modify the pointer to your SearchTree inside the called function, you should pass a pointer to the *tree in call to insertWord (i.e. a pointer to pointer).
You should change the definition to:
char* insertWord(BinarySearchTree **tree, char *word, char *definition)
Accordingly you should modify all accesses of tree inside your insertWord function.
Alternative working code — given a clean bill of health by valgrind:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct BinarySearchTree_t
{
char *word, *def;
struct BinarySearchTree_t *left;
struct BinarySearchTree_t *right;
};
typedef struct BinarySearchTree_t BinarySearchTree;
static void freeTree(BinarySearchTree *root);
static void dump_tree(BinarySearchTree *root);
extern char *insertWord(BinarySearchTree **ptree, char *word, char *definition);
char *insertWord(BinarySearchTree **ptree, char *word, char *definition)
{
if (*ptree == NULL)
{
BinarySearchTree *tmp = malloc(sizeof(*tmp));
tmp->word = strdup(word);
tmp->def = strdup(definition);
tmp->left = NULL;
tmp->right = NULL;
*ptree = tmp;
return tmp->def;
}
else
{
BinarySearchTree *tree = *ptree;
int r = strcmp(tree->word, word);
if (r == 0)
{
free(tree->def);
tree->def = strdup(definition);
return tree->def;
}
else if (r < 0)
return insertWord(&tree->right, word, definition);
else
return insertWord(&tree->left, word, definition);
}
}
int main(void)
{
char *word_defs[][2] =
{
{ "cat", "feline" },
{ "dog", "canine" },
{ "box", "carton" },
{ "cat", "purring critter" },
};
BinarySearchTree *root = 0;
for (size_t i = 0; i < sizeof(word_defs) / sizeof(word_defs[0]); i++)
{
printf("%zu: Add %s => %s\n", i, word_defs[i][0], word_defs[i][1]);
char *def = insertWord(&root, word_defs[i][0], word_defs[i][1]);
dump_tree(root);
printf("New definition: %s\n", def);
}
freeTree(root);
return 0;
}
static void freeTree(BinarySearchTree *root)
{
if (root != 0)
{
freeTree(root->left);
freeTree(root->right);
free(root->word);
free(root->def);
free(root);
}
}
static void dump_tree(BinarySearchTree *root)
{
if (root->left != 0)
dump_tree(root->left);
printf("%p: %s => %s\n", (void *)root, root->word, root->def);
if (root->right != 0)
dump_tree(root->right);
}
This version reports the new definition of the word. The original code may have been reporting the old definition; it is not hard to fix this code so that it reports the old definition (but it requires a modicum of care to ensure that the old definition is actually released, and null pointers aren't printed).
I am creating a binary tree from a bitstring in c. ie 1100100 creates a tree:
1
/ \
1 1
I decided to use a recursive function to build this tree however i keep getting the error
Debug assertion failed...
Expression : CrtIsValidHeapPointer(pUserData)
here is a fragment of my code
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
char string[1000];
int i = 0;
void insertRecursivePreorder(Node **node)
{
Node* parent = *node;
if(string[i] == '0')
{
parent = NULL;
i++;
}
else
{
Node *newn = (Node*)malloc(sizeof(Node));
newn->key = string[i];
parent = newn;
i++;
insertRecursivePreorder(&newn->left); //errors occur here
insertRecursivePreorder(&newn->right); //errors occur here
free(newn);
free(parent);
}
}
int main(void)
{
void printTree(Node* node);
Node* root = NULL;
scanf("%s", string);
insertRecursivePreorder(&root);
//... do other junk
}
i was wondering why this error comes about and what i can do to fix it.
The immediate problem is likely to be calling free on a pointer twice. In insertRecursivePreorder, you set parent to newn, and then call free on both. As an example of this, the following program fails (but works if you comment out one of the free(..)s):
#include <stdlib.h>
int main() {
int *a = malloc(sizeof(int)),
*b = a;
free(a);
free(b);
return 0;
}
However, there are several problems with your logic here. You should only call free when you have completely finished with the pointer, so if you are using your tree later you can't free it as you construct it. You should create a second function, recursiveDestroyTree, that goes through and calls free on the tree (from the bottom up!).
And, you probably want *node = newn rather than parent = newn, since the latter is the only one that actually modifies node.
(You could also change your function to return a Node * pointer, and then just go:
root = insertRecursivePreorder();
and
newn->left = insertRecursivePreorder();
newn->right = insertRecursivePreorder();
instead of trying to keep track of pointers to pointers etc.)
(Furthermore, on a stylistic point, using global variables is often bad practice, so you could have your insertRecursivePreorder take int i and char * string parameters and use them instead of global variables.)
The problem was: you were never assigning to the double pointer in 'insertRecursivePreorder', so root always stayed NULL.
#include <stdio.h>
#include <stdlib.h>
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
/* slightly changed the syntax for the str
** ; now '.' indicates a NULL pointer, values represent themselves.
*/
char *string = "12..3.." ;
/* Removed the global index 'i' */
void printTree(Node* node, int level);
unsigned insertRecursivePreorder(Node **pp, char *str);
unsigned insertRecursivePreorder(Node **pp, char *str)
{
unsigned pos =1;
if (!*str) { *pp = NULL; return 0; } /* safeguard for end of string */
if (*str == '.') { *pp = NULL; return pos; }
*pp = malloc(sizeof **pp);
(*pp)->key = *str;
pos += insertRecursivePreorder(&(*pp)->left, str+pos);
pos += insertRecursivePreorder(&(*pp)->right, str+pos);
return pos;
}
void printTree(Node* node, int level)
{
unsigned pos,len;
len = level> 0 ? level : -level;
for (pos =0; pos < len; pos++) putchar (' ');
if (!level) printf ("Root=");
else if (level<0) printf ("Left=");
else printf ("Right=");
if (!node) { printf( "Null\n" ); return; }
printf("Key=%c\n", node->key );
printTree(node->left, -(len+1) ) ;
printTree(node->right, len+1) ;
}
int main(void)
{
Node *root = NULL;
unsigned result = 0;
result = insertRecursivePreorder(&root, string);
printf( "Result=%u\n", result);
printTree(root, 0);
return 0; printTree(root, 0);
}
Output:
Result=7
Root=Key=1
Left=Key=2
Left=Null
Right=Null
Right=Key=3
Left=Null
Right=Null