List within a Tree? - c

A small query really with reference to Structs.
If I had a
Struct Node {
char *number;
struct Node *next;
}List;
and a tree Structure:
struct Node {
char *name;
char *number;
struct Node *right;
struct Node *left;
};
and I wanted to design it, such that each Node within my Tree, can each contain a LIST of Phone Numbers, is there a way in which I can do this, and if so, how exactly can I reference my struct List within my Tree?
EDIT:
Any ideas as to why this is seg faulting? Using the Structs recommended below.
TreeNode* AddNode(TreeNode *root, ListNode *list, char *name, char *phonenum) {
int comparison;
if ( root == NULL ) {
root = (TreeNode *)malloc(sizeof(TreeNode));
list = (ListNode *)malloc(sizeof(ListNode));
root->name = strdup(name); root->list->number = strdup(phonenum);
root->left = root->right = NULL;

You'd simply do it like so:
typedef struct Node {
char* name;
List* list;
struct Node *right;
struct Node *left;
} Node;
Then in order to get a local copy of the first element of the list in each node, you'd do something like the following:
Node* treenode; //this is pointing to some node in the tree
char* num_buffer = strdup(treenode->list->number);
//use num_buffer and then call free() on it when you're finished
If you wanted to get a number that was not the first number in the list, you would have to create a search function for your linked list.

Can you do something like this?
typedef struct ListNode
{
char *number;
struct ListNode *next;
} ListNode;
typedef struct TreeNode
{
char *name;
ListNode *numbers;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;

Related

Working with linked list whose member is a binary search tree (BST)

I am new to C data structures and I am working with a linked list and a binary search tree. The linked list is composed of 2 members, a string type and a binary search tree type. Here is its definition:
typedef char *String;
struct LinkedList
{
int employer_id;
EmployeeBST employees;
struct LinkedList *next;
} *LinkedList;
struct list
{
ListNodePtr head;
} EmployeeList;
The employee BST definition on the other hand
typedef char *String;
typedef struct bstNode
{
String employeeName;
struct bstNode *left;
struct bstNode *right;
} *BSTNodePtr;
typedef struct bst
{
BSTNodePtr root;
} EmployeeBST;
I want to insert new members to the linked list, here is my insert function
struct listNode *newListNode(String unit_code, EmployeeBST employees)
{
struct listNode *newNode;
newNode = malloc(sizeof(struct listNode));
newNode->employer_id = 89;
newNode->employees;
}
The problem is what value should I assign to the newMode->employees? I have the insert function for the BST which is implemented as:
struct bstNode *insert(struct bstNode *bstNode, int employer_id)
{
if(bstNode == NULL)
{
return newBstNode(employer_id);
}
// traverse right and insert the node
if(employer_id < bstNode->employer_id)
{
bstNode->left = insert(bstNode->left, employer_id);
}else
{
bstNode->right = insert(bstNode->right, employer_id);
}
return bstNode;
}

Assign a pointer to a struct that is a member of a struct of the same type to another pointer to a struct of the same type

This question sounds super confusing even for me, and it may seem obvious or already answered, but I have searched a lot and although I found interesting things, I didn't find an answer exactly for my question. Here is some C code that will show much better my doubt:
typedef struct Node_struct {
char keyLine[100];
int occurrences;
struct Node* leftChild;
struct Node* rightChild;
struct Node* parent;
} Node;
typedef struct Tree_struct {
Node* root;
} Tree;
int insertNode(Tree* myTree, Node* newNode) {
...
Node* currentNode = myTree->root;
...
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = (Node*)currentNode->leftChild;
}
...
}
Is this code correct? Since currentNode is of type Node*, and currentNode->leftChild is of type struct Node*, I had to cast (Node*)currentNode->leftChild so that it could be assigned to currentNode. But I am not sure if this is correct, necessary, or if there is a better way to do the same.
Similarly, I also have this:
Node* coverNode = NULL;
...
coverNode->leftChild = (struct Node*)newNode;
What should be written
Suppose the code in the question were written like this:
typedef struct Node { // Not Node_struct as in the question!
char keyLine[100];
int occurrences;
struct Node* leftChild;
struct Node* rightChild;
struct Node* parent;
} Node;
Then the name Node would be a synonym (alias) for struct Node. (For any typedef X Y;, Y becomes a synonym for type X — where in your case, X would be struct Node and Y would be Node.)
The cast in:
currentNode = (Node *)currentNode->leftChild;
would be unnecessary (but mostly harmless) because it would be a no-op — the types struct Node * and Node * would be two names for the same pointer type. Similarly for:
coverNode->leftChild = (struct Node *)newNode;
The cast would be unnecessary but (mostly) harmless. There would be a small risk of confusing people with the cast. It is better to avoid casts when possible, and these would be better written without the casts:
currentNode = currentNode->leftChild;
coverNode->leftChild = newNode;
What is written
typedef struct Node_struct {
char keyLine[100];
int occurrences;
struct Node* leftChild;
struct Node* rightChild;
struct Node* parent;
} Node;
Now we have three type names in play: struct Node_struct, struct Node, and Node. In this case, struct Node_struct and Node are synonyms, and struct Node is an incomplete structure type (or, at least, it is not completed by any code in the question). It is wholly unrelated to either struct Node_struct or Node except by the coincidence that it is referenced inside the structure.
With this notation, the casts are 'necessary' because you're converting between pointers to unrelated types (struct Node * and struct Node_struct *). Fortunately, there are rules that say all structure type pointers are inter-convertible and must have the same size and alignment requirements (C11 §6.2.5 Types ¶28 and §6.3.2.3 Pointers ¶7).
But you should drop the _struct part of Node_struct to make the rules of the first part of this answer apply. In C, it is (IMO) sensible to use:
typedef struct SomeTag SomeTag;
so that you can subsequently use SomeTag * etc. The first SomeTag is in the tags name space and does not conflict with the second SomeTag, which is in the ordinary identifiers name space. See C11 §6.2.3 Name spaces of identifiers.
See also:
Which part of the C standard allows this code to compile?
Does the C standard consider that there are one or two struct uperms_entry types in this code?
C style/C++ correctness — is struct, union, enum tag same as type name bad in any way?
In c++, when you say struct Node, Node [immediately] becomes a type. So, you could say:
struct Node {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
};
struct Tree {
Node *root;
};
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
But, in c, it is merely in the "tag" namespace and does not define a type. Thus, you want:
typedef struct Node {
char keyLine[100];
int occurrences;
struct Node *leftChild;
struct Node *rightChild;
struct Node *parent;
} Node;
typedef struct Tree_struct {
Node *root;
} Tree;
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
As an alternative, you can use a forward declaration:
// forward declaration
struct Node;
typedef struct Node Node;
struct Node {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
};
typedef struct Tree_struct {
Node *root;
} Tree;
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
Note that the struct name does not have to match the type name:
// forward declaration
struct Node_struct;
typedef struct Node_struct Node;
struct Node_struct {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
};
typedef struct Tree_struct {
Node *root;
} Tree;
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}
To allow cross linking of your two structs, we could do:
// forward declaration
struct Node_struct;
typedef struct Node_struct Node;
struct Tree_struct;
typedef struct Tree_struct Tree;
struct Node_struct {
char keyLine[100];
int occurrences;
Node *leftChild;
Node *rightChild;
Node *parent;
Tree *tree;
};
struct Tree_struct {
Node *root;
};
int
insertNode(Tree *myTree, Node *newNode)
{
Node *currentNode = myTree->root;
if (caseSenCmpString(newNode->keyLine, currentNode->keyLine) == -1) {
currentNode = currentNode->leftChild;
}
}

error in creating array of linked list

I have to put nodes of binary search tree of every level in a linked list. That is if the height of the tree is 'h' then 'h+1' linked lists would be created and then each linked list would have all the nodes of each level. For this I have thought of creating an array of linked list. But the nodes are not being inserted in the list I guess. The code is as follows:-
struct node{
int data;
struct node *left;
struct node *right;
};
struct linked_list
{
int data;
struct linked_list *next;
};
linkedlistofbst(struct node *new,struct linked_list *n1[], int level)
{
//printf("%d ",new->data);
if(new==NULL)
{
return;
}
if(n1[level]==NULL)
{
struct linked_list *a =(struct linked_list *)malloc(sizeof(struct linked_list));
a->data=new->data;
a->next=NULL;
n1[level]=a;
printf("%d ",a->data);
}
else
{
struct linked_list *b =(struct linked_list *)malloc(sizeof(struct linked_list));
while(n1[level]->next!=NULL)
{
n1[level]=n1[level]->next;
}
b->data=new->data;
b->next=NULL;
n1[level]=b;
}
linkedlistofbst(new->left,n1,level+1);
linkedlistofbst(new->right,n1,level+1);
}
main()
{
struct linked_list *l=(struct linked_list *)malloc((a+1)*sizeof(struct linked_list));//'a' is the height of the tree
linkedlistofbst(new,&l, 0);//new is the pointer to the root node of the tree.
}
You are right there is problem with the second argument, so do the following
Make the following changes in the main:
For defining an array of linked list of size a+1 and initializing them to NULL
struct linked_list **l=(struct linked_list **)malloc((a+1)*sizeof(struct linked_list*));
for(i=0;i<(a+1);++i)
l[i]=NULL;
Then call the method as
linkedlistofbst(new,l, 0);
Therefore your method must look like
linkedlistofbst(struct node *new,struct linked_list **l, int level)
also make the following modification in else as:
else
{
struct linked_list *ptr=n1[level];
while(ptr->next!=NULL)
{
ptr=ptr->next;
}
ptr->next=(struct linked_list *)malloc(sizeof(struct linked_list));
ptr->next->data=new->data;
ptr->next->next=NULL;
}

Wrong memory offset with polymorphic structs

I'm currently implementing a doubly-linked list in C. The purpose of the list is to be as generic as possible. Here's the node struct:
typedef struct list_node
{
struct list_node *prev;
struct list_node *next;
int nodeId;
} Node;
Now, I'm extending this into the following node:
typedef struct history_node
{
Node *node;
String *cmd;
} HistoryNode;
Where the string struct is defined as follows:
typedef struct c_string
{
char *array;
size_t size;
} String;
Now, the problem that I'm having is this: I create a new history node, and set it's string to a value, "hello" for example. I then call on my pushBack function, that is defined as follows:
void pushBack(Node *node, List *list)
{
node->next = list->tail;
node->prev = list->tail->prev;
list->tail->prev->next = node;
list->tail->prev = node;
list->size++;
}
The thing here is that when I assign node->next, instead of accessing the node part of the history node, I access the string, which results in disaster. I have no idea why this is happening. Looking at the addresses in memory, the pointer that is passed in has the correct address, but the address that is accessed in node->next corresponds to the address of cmd and not node. Any ideas?
Just in case, the code that calls this function is:
HistoryNode *node = createHistoryNode(buffer);
pushBack((Node*)node, historyList);
I have already verified that createHistoryNode works as expected, so that is not the source of the problem.
You don't want
typedef struct history_node {
Node *node;
String *cmd;
} HistoryNode;
you want
typedef struct history_node {
Node node;
String *cmd;
} HistoryNode;

EXC_BAD ACCESS in memcpy

I trying to build a BST and insert nodes in it. However while creating a new node I keep getting exc_bad access error.What can be the reason? Here is my code:
struct Node *node_create(struct BSTree *bst,void *nodeKey, struct Value *nodeVal, struct Node *rightChild, struct Node *leftChild)
{
struct Node *node = malloc(sizeof *node);
nodeKey= malloc (sizeof (bst->key_size));
nodeVal = malloc(sizeof(bst->value_size));
size_t sizeKey = sizeof(nodeKey);
memcpy(node->key, nodeKey, sizeKey); // exc_bad access
size_t sizeVal = sizeof (nodeVal);
memcpy(node->val, nodeVal, sizeVal); // exc_bad access
node->right = rightChild;
node->left = leftChild;
return node;
}
struct Node {
void *key;
struct Value *val;
struct Node *left;
struct Node *right;
};
struct BSTree {
size_t key_size, key_alignment;
size_t value_size, value_alignment;
int (*compare_func)(void *, void *);
struct Node *root;
// ... Maybe some other stuff.
};
struct Value {
char name[10];
int id;
};
Without knowing what Node, looks like, I'd say, even though you've allocated for node, you've not allocated all the members (which appear to be pointers).
Change your code to something like:
// Allocate node
struct Node *node = malloc(sizeof *node);
// Now members
node->key = malloc (sizeof (bst->key_size));
// :
If you are passing in the key and value, then do a memcpy of those values to the above locations. But hard to say without further code...
Without looking at the Node structure, I would guess what you want to do is:
if node is defined as
struct Node {
void *key;
struct Value *val;
struct Node *right;
struct Node *left;
};
then
struct Node *node_create(struct BSTree *bst,void *nodeKey, struct Value *nodeVal, struct Node *rightChild, struct Node *leftChild)
{
struct Node *node = malloc(sizeof *node);
node->key = malloc(bst->key_size); /* No sizeof here */
node->val = malloc(bst->value_size);
memcpy(node->key, nodeKey, bst->key_size);
memcpy(node->val, nodeVal, bst->value_size);
node->right = rightChild;
node->left = leftChild;
return node;
}
As you don't check for the returns of the mallocs (which is a design choice that can e justified), you can even write it simpler that way.
struct Node *node_create(struct BSTree *bst,void *nodeKey, struct Value *nodeVal, struct Node *rightChild, struct Node *leftChild)
{
struct Node *node = malloc(sizeof *node);
node->key = memcpy(malloc(bst->key_size) , nodeKey, bst->key_size);
node->val = memcpy(malloc(bst->value_size), nodeVal, bst->value_size);
node->right = rightChild;
node->left = leftChild;
return node;
}
There are people that cringe at this style but I prefer to not dilute my code too much on redundancies.

Resources