So I have a piece of code, where I have to add a node to a BST. My struct is the following:
typedef struct _CC_TREE {
// Members
int Value;
struct _CC_TREE* LChild;
struct _CC_TREE* RChild;
} CC_TREE;
The insert function in the header file looks like this:
int TreeInsert(CC_TREE *Tree, int Value);
where I have to return the status of the insert.
I tried doing it with another function and add it to the Tree
CC_TREE* InsertNewNode(CC_TREE* Tree, int Value)
{
if (NULL == Tree)
{
Tree = (CC_TREE*)malloc(sizeof(CC_TREE));
Tree->LChild = NULL;
Tree->RChild = NULL;
Tree->Value = Value;
return Tree;
}
if (Value <= Tree->Value)
{
Tree->LChild = InsertNewNode(Tree->LChild, Value);
}
else if (Value >= Tree->Value)
{
Tree->RChild = InsertNewNode(Tree->RChild, Value);
}
return Tree;
}
int TreeInsert(CC_TREE *Tree, int Value)
{
CC_UNREFERENCED_PARAMETER(Tree);
CC_UNREFERENCED_PARAMETER(Value);
Tree = InsertNewNode(Tree, Value);
return 0;
}
I try and construct the tree in my main function:
int retVal = -1;
CC_TREE* usedTree = NULL;
retVal = TreeCreate(&usedTree);
if (0 != retVal)
{
printf("TreeCreate failed!\n");
goto cleanup;
}
retVal = TreeInsert(usedTree, 20);
if (0 != retVal)
{
printf("TreeInsert failed!\n");
}
but for some reason the usedTree remains null. I know that I should use CC_TREE** Tree in the insert function, but I am not allowed to.
The insert function in the header file looks like this:
int TreeInsert(CC_TREE *Tree, int Value);
If you cannot change the function signature or (ew!) use a global variable to return the root pointer to the caller, then your best alternative is probably to use a dummy tree root. That would look something like this:
int TreeInsert(CC_TREE *Tree, int Value) {
// Tree points to a dummy root node containing no data.
// Tree->LChild is the actual root pointer
CC_TREE *root = Tree->LChild;
int status = 0;
// ... perform insertion, possibly resulting in a different value for the
// root pointer ...
Tree->LChild = root;
return status;
}
That assumes that the first argument to TreeInsert() is always a valid pointer to a CC_TREE. If you do this, then all other tree functions should work analogously.
You would use that from main() like so:
int retVal;
CC_TREE dummy_tree_root = { 0 };
retVal = TreeInsert(&dummy_tree_root, 42);
Note that this approach in effect uses a double pointer via an indirect route (no pun intended). A CC_TREE * is not itself a double pointer, but there are still two levels of indirection between that pointer and either the left or the right child of the node to which it points.
Note also that a cleaner way of doing this would involve providing a wrapper structure representing the overall tree instead of using a bare tree node or tree node pointer for the purpose. The data structures would be something like this:
struct node {
int value;
struct node *left;
struct node *right;
};
struct tree {
struct node *root;
// optionally other data, such as size, height, etc.
};
typedef struct sTree {
int key;
struct sTree* p;
struct sTree* left;
struct sTree* right;
} sTree;
typedef sTree* tree;
void treeInsert(tree* root);
int main(){
srand((unsigned)time(NULL));
tree *root = NULL;
treeInsert(&root);
return 0;
}
void treeInsert(tree* root){
......
}
I don't understand why I have to pass '&' when calling tree insert (&root instead of root).
I've created a struct representing a node of binary tree and I declared a pointer to the root of the tree as 'tree*'.
So 'root' is double pointer. The function 'treeInsert' expects a double pointer. If I pass simply 'root' it takes the value (NULL) else with the operator '&' it points correctly to the root. The problem is:
passing '&root' I'm not passing a triple pointer? Can someone explain why?
regarding:
treeInsert(&root);
the need for the & is because the function: treeInsert() will need to modify the contents of the pointer. Without the & any assignment to that passed parameter will only change the parameter on the call stack and not the the contents of the parameter in main()
regarding:
tree *root = NULL;
Since tree is already a pointer, this results in (effectively)
tree ** root = NULL;
which will not accomplish what is needed.
A prime example of why a pointer should NOT be hidden in a typedef statement
the following proposed code is clear about what is wanted:
struct sTree
{
int key;
struct sTree* p;
struct sTree* left;
struct sTree* right;
};
typedef struct sTree tree;
void treeInsert(tree** root);
int main( void )
{
srand((unsigned)time(NULL));
tree *root = NULL;
treeInsert(&root);
return 0;
}
void treeInsert(tree** root)
{
tree *localroot = *root; // now 'localroot' is a pointer to the variable `root` in function: `main()`
......
}
I am completely noob when I work with C. Very weak with pointers.
I have written a struct for a binary search tree. But when I try to access it from code it throws an error:
Process terminating with default action of signal 11 (SIGSEGV).
Bad permissions for mapped region at address 0x0`.
Here is my struct (in bst.h):
typedef struct tree Tree;
typedef struct tree{
Node * root;
Data * (*insert)(Tree * bst, Data value); //i get error in main when I make a call
Data * (*search)(Tree * bst, Data value);
void (*sort)(Tree *, Data *);
int (*compare)(Tree *t, Tree * copy);
Tree * (*clone)(Tree *t);
void (*delete)(Tree *bst);
void (*removeData)(Tree * bst, Data value);
}Tree;
Member functions (in bst.c):
Node * newNode(Data data, Node * parent) {
printf("inside new node\n");
Node * node = malloc(sizeof(Node));
if(parent!=NULL) {
if((parent->data.value)> data.value) {
parent->left=node;
}
else {
parent->right=node;
}
}
node->parent=parent;
node->left=NULL;
node->right=NULL;
node->data=data;
printf("after inside newNode\n");
return node;
}
Tree * newTree() {
Tree *tree;
tree = (Tree*)malloc(sizeof(Tree));
tree->root=NULL;
return tree;
}
// not getting inside in this function
Data * insert(Tree * tree, Data data) {
if(tree->root==NULL) {
tree->root = newNode(data,NULL);
} else{
return insertNode(tree->root,data);
}
return NULL;
}
Here is my main() that calls this function (in main.c):
Tree *bst = newTree();
assert(bst->root == NULL);
printf("1.");
for (i = 0; i < num_data; i++){
bst->insert(bst, (Data){d[i]});
printf("inside for loop");
}
I am not sure whether this is the right way to make function pointers as members of struct.
In newTree(), you are not assigning your functions to the function-pointers inside of the allocated tree struct.
Data* insert(Tree* tree, Data data);
// other function declarations as needed...
Tree* newTree() {
Tree *tree = (Tree*) malloc(sizeof(Tree));
if (!tree) return NULL;
tree->root = NULL;
tree->insert = &insert; // <-- ADD THIS!
// and do the same for your other function pointers...
tree->search = ...;
tree->sort = ...;
tree->compare = ...;
tree->clone = ...;
tree->delete = ...;
tree->removeData = ...;
return tree;
}
I'm trying to create a generic list that will allow any type to be entered. However, I am having problems with the comparism in the is_element_of function (since I am making use of void pointers). Any help?
typedef struct Item{
void* data;
} Item;
typedef struct Node{
Item Item;
struct Node* next;
struct Node* previous;
} Node;
typedef Node* List;
bool is_element_of(Item Item, List *pointertolist) {
bool isinlist = false;
Node *scan = *pointertolist;
while (scan->next != NULL) {
if ((scan->Item.data) == (Item.data)) {
printf("Match!");
isinlist = true;
} else {
printf("No Match!");
isinlist = false;
}
scan = scan->next;
}
return isinlist;
}
You'll need to delegate type-aware operations to a separate function, then attach that function to your list via a function pointer. I've taken the liberty of changing your struct type definitions to something I've used before that I feel is a little more natural. Feel free to disagree.
struct Node {
void *data;
struct Node *prev;
struct Node *next;
};
Unless you intend for the Item struct type to hold anything other than a void *, then get rid of it. Abstraction is a Good Thing, but there is such a thing as going overboard. Personally, I think it's cleaner to not create a bunch of typedefs, and I really don't like typedef'ing pointer types (pointer semantics are special and should not be hidden). Of course, YMMV.
struct List {
struct Node *head;
struct Node *tail;
int (*cmp)( const void *, const void *);
};
I've modified your List type to contain your head and tail pointers, as well as a pointer to a comparison function. You can use this structure to create lists of any type; all you need to do is create a comparison function for that type and attach it to the list. For example, if you want your list to contain integers:
int compareInt( const void *lhs, const void *rhs )
{
const int *llhs = (const int *) lhs;
const int *lhrs = (const int *) rhs;
if ( *llhs < *lrhs )
return -1;
else if ( *llhs > *lrhs )
return 1;
return 0;
}
The comparison function follows the same model as those used by qsort; it takes two parameters of const void * and returns an int value -- -1 if lhs < rhs, 1 if lhs > rhs, and 0 if lhs == rhs.
struct List intList = { NULL, NULL, compareInt };
bool contains( const Item data, struct List *l )
{
bool result = false;
assert( l != NULL && l->cmp != NULL);
struct Node *cur = l->head;
while ( cur != NULL )
{
if ( l->cmp( cur->data, data ) == 0 )
{
result = true;
break;
}
cur = cur->next;
}
return result;
}
So your function will walk through the list and compare values, returning true if it finds a match, false otherwise.
Now, this approach has a lot of drawbacks; it's complex, it's messy, it can be hard to follow, it can involve a lot of memory management, and you lose any pretense of type safety. There's nothing to stop you from associating the wrong function with a list, or mixing up types within the list. But, it does allow you to create "generic" containers that can handle any type, and you can add new types without having to hack the basic container logic. You only need to implement a new comparison function for each type.
Although, to be honest, you should implement not only comparison functions, but assignment, copy, display, and deallocation functions as well, attaching them to the list in the same way, along with a lightweight, type-aware interface for each type. It's more code, but it will save you heartburn in the long run.
You should set isInList to false at the start and only mark it to true when you find a match. Then terminate the loop:
typedef struct Item
{
void* data;
} Item;
typedef struct Node
{
Item Item;
struct Node* next;
struct Node* previous;
} Node;
typedef Node* List;
bool is_element_of(Item Item, List *pointertolist)
{
bool isInList = false;
Node *scan = *pointertolist;
while (scan != NULL && !isInList)
{
if ((scan->Item.data) == (Item.data))
{
printf("Match!\n");
isInList = true;
}
scan = scan->next;
}
if(!isInList)
printf("No Match!\n");
return isInList;
}
Test Function:
void testit()
{
Node n1;
Node n2;
Node n3;
Item item;
n1.Item.data = (void*)0x23;
n2.Item.data = (void*)0x24;
n3.Item.data = (void*)0x25;
n1.next = &n2;
n2.next = &n3;
n3.next = NULL;
List list = &n1;
item.data = (void*)0x23;
is_element_of(item, &list);
item.data = (void*)0x24;
is_element_of(item, &list);
item.data = (void*)0x25;
is_element_of(item, &list);
item.data = (void*)0x26;
is_element_of(item, &list);
}
Output Result:
Match!
Match!
Match!
No Match!
You cannot de-reference a void* and compare the value because it could be of any size (ex: how would you compare a int and a short?
Without more knowledge of you data (yes, its always about the input data ;-), its hard to give a more definite answer. But here are two trails you may pursue...
[edit] I assume that your list may contain data of any type within the same list. People often use void * because they want to link different types together.
The short (bad) answer
you have to choose between comparing values, or comparing pointers. if you don't mind comparing only pointers then you could simply set your Item by giving it the address of your data:
node.Item.data = &myval;
in which case you can see if you've already added this location in ram to your nodes. But this will not allow you to compare the same value in two different locations in your app. Thus if x and y in the following have the same value you wouldn't be able to compare that you have two nodes which point to 1.
x = 1;
y = 1;
node.Item.data = &x;
node2.Item.data = &y;
Furthermore, if you added any node which was allocated on the stack, you will quickly shovel yourself into a grave (as nodes may eventually refer to addresses which are not valid on the stack anymore)!
The longer (better) answer
When I have a generic accumulator system like this, instead of using a void *, I use a union.
enum {
tp_int = 0x0001,
tp_short = 0x0002,
tp_vptr = 0x0004, // void pointer
tp_sptr = 0x0008 // string pointer (whatever type you use
// for your strings... ? char *)
// ... add other types, including structs you may want to compare...
};
typedef struct Item {
int type; // <- essential!
union data {
int i;
short s;
void *ptr; // all pointer types can use the same, unless you want to compare
// compound values (a struct member?) where you'd then use the
// tp_xxx to properly select which
// comparison to use ... as below.
};
} Item;
typedef struct Node{
Item Item;
struct Node* next;
struct Node* previous;
} Node;
typedef Node* List;
bool is_element_of(Item Item, List *pointertolist) {
bool isinlist = false;
Node *scan = *pointertolist;
while (scan->next != NULL) {
//isinlist = false;
if (scan->Item.type == Item.type){
if (Item.type & (tp_vptr | tp_sptr)){
// compare pointer types
if ((scan->Item.ptr) == (Item.ptr)){
printf("pointer Match!");
isinlist = true;
break;
}
} else if (Item.type == tp_int){
// compare integers (4 bytes?)
if ((void *)(scan->Item.i) == (void *)(Item.i)){
printf("integer Match!");
isinlist = true;
break;
}
} else if (Item.type == tp_short){
// compare shorts (2 bytes?)
if ((scan->Item.s) == (Item.s)){
printf("short Match!");
isinlist = true;
break;
}
}
}
scan = scan->next;
}
return isinlist;
}
Note the above code may have one or two odd errors in it, I am not set up to compile it at the moment.
Here you can select which comparison to use. It also allows you to properly and safely use value types (like ints and shorts).
if you had more complex structs, you can easily compare them using their data instead of their pointers, so you could see if you had equivalent data.
You could even extend the above to check for similar strings, even if they have different memory locations. (when Item.type is tp_sptr :-)
I'm trying to create a small list for each element in a main list. I have the main list working fine but I don't know how to access and add elements to the small list.
struct smallList
{
char data;
struct smallList *next;
};
struct bigList
{
char data;
struct bigList *next;
struct smallList *head;
} *root;
When I add stuff to the main list, I declare for each new node:
newNode->head = NULL;
I use this function to get the current pointer to an element in main list:
struct bigList *pointer = getPointer(root, value);
Then, to add stuff to its smallList| using that pointer. I pass alongpointer->head` to this function. And its not working.
insert(pointer->head, value)
As WhozCraig suggests, you can resolve your problem using a pointer to a pointer. Something like this:
void insert(struct smallList **head, char value)
{
*head = newSmallList(value, *head);
}
newSmallList would be something like:
struct smallList *newSmallList(char value, struct smallList *rest)
{
struct smallList *result = malloc(sizeof(struct smallList));
result->next = rest;
result->data = value;
return result;
}
The problem with your current setup is that you are passing the value of the pointer->head field (which happens to be null) to the function, when what you want is to alter what is stored in the field. Here is a program using integers that illustrates a similar mistake:
void setFive(int i)
{
i = 5;
}
int main(void)
{
int myInt = 7;
setFive(myInt);
printf("%d\n", myInt); /* still 7! */
return 0;
}