How would I declare a new struct in this case? - c

This is what I have right now for my code (just a simple BST)
typedef struct bsn{
int val;
struct bsn *left, *right;
} bsn_t;
typedef struct bst{
bsn_t *root;
int size;
} bst_t;
My question is that for the functions which I'll use, the input is an address like this
void init( bst_t * tree )
How would I use this? This is what I have right now but I'm not sure if it's correct or not
tree->size = 0;
tree->root = NULL;
Also for other functions like
bool insert( bst_t *tree, int val )
I want to declare a temp node to use. Does this work?
bsn_t temp = (bsn_t *) malloc (sizeof (bsn_t));
And my last question is that how would I check if a node is null or not. I tried
bsn_t visitor = (bsn_t*)malloc(sizeof(bsn_t));
visitor = *tree->root;
Then doing
if (visitor != NULL)
But when I compile it says that
'!=': illegal for struct
Please help..

In your tree, the connections between the nodes and the connection from outside, i.e the root, are all pointers. They point to nodes that are allocated on the heap with malloc.
If you define a local variable like:
bsn_t temp;
you get a node on the stack that will be invalid after the returning from the function. In your case, you should never need to create nodes on the stack. You should work with pointers to nodes throughout, which point to existing nodes, to frshly allocated nodes or to nothing (NULL).
So:
bsn_t *temp = malloc (sizeof (bsn_t));
(I've removed the cast to (bsn_t *). It is strange that in the original code, you have cast the return value from malloc to a pointer type when assigning to a struct.)
As for your second question, your code:
bsn_t visitor = (bsn_t*)malloc(sizeof(bsn_t));
visitor = *tree->root;
is wrong in several places. First, as above, the visitor should be a pointer to a node, not a node struct.
Then the visitor is supposed to travel from the root down the tree. By doing so, it does not create any new nodes, so there is no need to malloc at all. Remember, malloc gives you new memory on the heap, in effect creating a node. The visitor just points to existing objects. One object can have more pointers pointing to them.
Even if malloc were the right ting to do, you shouldn't malloc and then overwrite the pointer that holds the (so far only) handle to the ne memory.
You've also got the * wrong. The visitor is a pointer ans tree->root is a pointer, too, so there's no need to dereference. What you have done is to copy the contents of the root to your local struct.
What you want to do is someting like this:
bsn_t *visitor = tree->root;
while (visitor != NULL) {
// Do stuff
visitor = visitor->right; // or left, whatever
}
The use of asterisks in declaration and use may be confusing. In a declaration, you use a start to make a thing a pointer:
bsn_t node; // uninitialised node struct on the stack
bsn_t *pnode; // uninitialised pointer to node
After that, when you use the pointer variable, the unadorned name refers to the the pointer. An asterisk means that you dereference it to get at what the pointer points to. When you work with structures, you usually won't see many stars, because the -> syntax is preferred, but node->left is essentially the same as (*node).left.

You can't assign memory addresses (The return value from a malloc call) to struct typed variables. You need to assign these to pointer typed variables.
bsn_t *temp = (bsn_t *) malloc (sizeof (bsn_t));
bsn_t *visitor = (bsn_t*)malloc(sizeof(bsn_t));
Then you won't have compile time errors.

How would I use this? This is what I have right now but I'm not sure if it's correct or not
tree->size = 0;
tree->root = NULL;
Yes this is the right way to use it. If you have a pointer you can access the struct elements with(->) operator otherwise, use . (dot) operator.
bsn_t temp = (bsn_t *) malloc (sizeof (bsn_t));
Yes this is the right way as well but you are missing a '*' before temp on left hand side which states that this is a pointer type variable. Remember, it will allocate the object in heap so you have to explicitly free that memory when you no longer need it. Also, note that casting the newly allocated memory to (bsn_t *) is optional, if you don't do, compiler will implicitly do it for you depending upon your l-value type.
bsn_t visitor = (bsn_t*)malloc(sizeof(bsn_t));
Again, it should be bsn_t *visitor on your left hand side.
visitor = *tree->root;
Following that it should be *visitor = *tree->root;
Also, try to make your code more readable by writing *(temp->root) instead of *temp->root.
if (visitor != NULL) Now you should be able to use this since visitor is a pointer now.

Related

Error with malloc while creating memory for list of struct pointers

For some reason, while trying to create an array of pointers of a struct called Node, I keep getting an error:
Node ret[2] = (struct Node*)malloc(2*sizeof(Node));
error: invalid initializer
Can someone please help me with that?
Node ret[2] = (struct Node*)malloc(2*sizeof(Node));
should probably be:
Node *ret = malloc(2 * sizeof(*ret));
That's because you need a pointer to the memory, not an array. With an array, it's initialisation, which would require a braced init list. Note that this only provides memory for the pointers, not the things they point at - they need to be allocated separately if you wish to use them.
You'll probably notice two other changes as well:
I've removed the cast on the malloc return value. This serves no purpose in C since the void* returned can be implicitly cast to other pointer types. In fact, there are situations where explicit casts can lead to subtle problems.
I've used *ret as the variable to get the size rather than the type. This is just habit of mine so that, if I change the type to (for example) tNode, I only have to change it in one place on that line - yes, I'm basically lazy :-) Note that this is just a preference, doing it the original way has no adverse effect on the program itself, just developer maintenance.
I think your struct is typedef ed
Node ret[2] = ( struct Node* ) malloc( 2 * sizeof(Node) );
it should be
Node *rec[2] = { malloc(sizeof(Node)) , malloc(sizeof(Node)) };
or
Node *rec = malloc(2*sizeof(Node));

insertion in linked list -

I was reading Skeina's book. I could not understand this code. Basically what is the use of double pointer. And what is the use of *l = p? Can anyone please explain by diagram.
void insert_list(list **l, item_type x) {
list *p; /* temporary pointer */
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
You shouldn't call it a "double pointer" because that would be a pointer to a double. It is a pointer to a pointer, and it is used to allow the function to alter the value of an argument which happens to be a pointer. If you're familiar with C#, it's like an out argument. In this situation the l argument used to get both IN and OUT behavior, but you may often see this used for output only.
Since this function returns type void it very well could have been written without the use of the pointer to a pointer like this:
list * insert_list(list *l, item_type x) {
{
list *p; /* temporary pointer */
p = malloc(sizeof(list));
p->item = x;
p->next = l; // note that this is not *l here
return p;
}
This change would require the code that calls the function to update it's own handle to the list since the head of the list is what's being changed.
This function performs a very simple task: it inserts a list node at
the position for which it receives a pointer. There is nothing
special about double pointers, they are just pointers to pointers. They hold the address of a pointer, which contains the address of an object.
void **l contains the address of a list * pointer. *l retrieves
this address and *l = p stores it.
malloc is used to allocate a
list structure, p receives the address of the allocated structure.
The code is somewhat sloppy as p is not checked for NULL before
dereferencing it. If malloc fails because of lack of memory, the
program will invoke undefined behaviour, hopefully stopping with a
segmentation fault or something potentially worse.
The node is initialized, its next pointer is set to the node pointed
to by the l argument, and finally the new node's address is stored
at the address passed as the l argument. The effect is simple: the node is inserted at *l.
This method is clever ad it allows the same function to insert a new node anywhere is a list. For example:
list *head = NULL;
...
/* Insert a LIST_A node at the beginning of the list */
insert_list(&head, LIST_A);
...
/* insert a LIST_B element as the second node in the list */
insert_list(&head->next, LIST_B);
...
/* find the end of the list */
list *node;
for (node = head; node->next; node = node->next)
continue;
/* insert a LIST_Z node at the end of the list */
insert_list(&node->next, LIST_Z);
The only tricky thing above is the concept of pointer itself, here is a simple overview:
Memory can be conceptualized as a (large) array of bytes, addresses are offsets in this array.
char variables by definition are single bytes,
int variables occupies a number of bytes specific to the architecture of the system, typically 4 or 8 bytes in current hardware.
Think of pointers as variables holding the address in memory of another variable. They need to be large enough to hold any valid address in the system, in current systems with more than 4 GB of physical and addressable memory, they are 64 bit long and occupy 8 bytes.
There is a special address value NULL which represents no object and is used to specify that a given pointer does not point to any real object. The address 0 is used for this purpose. malloc will return NULL if it cannot allocate the memory requested, the return value should be tested, as storing a value at this address is forbidden and usually caught as an invalid access (segmentation fault).
This summary is purposely simplistic. I used the term variable instead of object to avoid the confusion with OOP concepts.

Memory allocation of fixed size array inside a struct

I have the following tree node struct that holds pointers to other tree nodes:
struct node {
// ...
struct node* children[20];
}
The idea is that I want to check whether there is node* inside the children and based and that go deeper into the tree. So when I allocate the node I want to have children with 20 NULL values.
Currently I am not doin
How should I allocate this array in order to not get errors like Conditional jump or move depends on uninitialised value(s) (Valgrind)?
Would it be better to use struct node** children and allocate fixed size each time I allocate a new node?
EDIT: Example of one place where Valgrind complains:
for(int i=0;i<20;i++)
if(node->children[i] != NULL)
do_something_with_the_node(node->children[i]);
When you allocate a new instance of struct node, you must set the contained pointers to NULL to mark them as "not pointing anywhere". This will make the Valgrind warning go away, since the pointers will no longer be uninitialized.
Something like this:
struct node * node_new(void)
{
struct node *n = malloc(sizeof *n);
if(n != NULL)
{
for(size_t i = 0; i < sizeof n->children / sizeof *n->children; ++i)
n->children[i] = NULL;
}
return n;
}
You cannot portably use either memset() on n->children nor calloc(), since those will give you "all bits zero" which is not the same as "pointer NULL".
Your struct definition is valid (although it's hard to tell without more context if it fits your requirements).
Valgrind doesn't complain about your struct definition, it probably complains about how you instantiate variables of that type. Ensure that all of the array members get initialized and the complaints will most likely go away.
The problem is that you are using an unintialized value in an if condition.
When you instantiate a struct node, its member struct node* children[20]; is an array of 20 struct node *, all of which are uninitialized.
It would be no different from this:
char *x;
if (x == NULL) {
/* Stuff */
}
At this point, x may have literally any value. In your example, any element of an array may have any value.
To fix this, you need to initialize the elements of an array before using them, for example like this:
for (int i = 0; i < 20; ++i) {
node->children[i] = NULL;
}
Or shorter:
memset(node->children, 0, 20);
If you changed the member to, as you've suggested, node **children, the situation wouldn't be much different - you'll still need to initialize all the members, including array's elements. You could make it shorter by using calloc, which will initialize all bytes to 0; then again, you'll need some code for correct deallocation (and remember to do it), so I think the tradeoff's not worth it.

Homework, Assigning pointers within a struct in C

I'm making a Binary Tree as a part of my homework.
This is the given struct:
typedef struct TreeNode {
int data;
struct TreeNode* left;
struct TreeNode* right;
}
My build_tree function is recursive, and this is the prototype:
void build_tree(TreeNode** root, const int elements[], const int count);
The homework is meant to partly test dynamically allocated memory. So my problem keeps happening when I try to assign a value to one of the pointers inside the struct. I have seen questions similar to this, but it never seems to be this question exactly, but still involves structs and pointers. If I misunderstood, I apologize for duplicating questions.
The build_tree method has to be done recursively
This is my code for when an element should be inserted to the right of the root:
if(elements[0] > (*root)->data){
TreeNode newnode = {elements[0], NULL, NULL}; //make a node to add
*((*root)->right) = newnode; //dereference the root.right pointer, and set to newnode (GIVES COMPILE ERROR HERE)
struct TreeNode **rightptrptr = malloc(sizeof((*root)->right)); //allocate a pointer to a pointer
*rightptrptr = (*root)->right; //dereference pointer to a pointer, assign to root.right pointer
build_tree(rightptrptr, new_elems, count - 1);
}
If it's important, the root node has been initialized to {an integer, NULL, NULL}.
My understanding of pointers isn't all that sophisticated, so please forgive me if this code is horrendous.
There are many issues here, I'll try to point them out:
TreeNode newnode = {elements[0], NULL, NULL};, this allocates the struct on the stack, which means that the address of newnode (&newnode) won't be valid anymore when exiting the scope of the function.
if you need to build the tree by dynamically allocating the nodes TreeNode newnode = {elements[0], NULL, NULL} is not what you are looking for. This is not a dynamically allocated object, it's on the stack and the only thing you can do it with it to copy the content to an allocated node. You need always to allocate TreeNode* node = calloc(sizeof(TreeNode)) in your situation
((*root)->right) = newnode, here you dereference the pointer to assign newnode to it. It could work but only if right points to allocated memory, which is not the case since your root initializes it to NULL. You should instead allocate directly the pointer, eg root->right = calloc(sizeof(TreeNode))
struct TreeNode **rightptrptr = malloc(sizeof((*root)->right)), here you allocate a pointer to a pointer to a TreeNode because the recursive function expects this but your approach is wrong. You should pass the pointer to an existing subtree, not allocating one with no purpose, you can do it by doing, for example &root->right.

Basic Malloc/Free

If I have a snippit of my program like this:
struct Node *node;
while(...){
node = malloc(100);
//do stuff with node
}
This means that every time I loop through the while loop I newly allocate 100 bytes that is pointed to by the node pointer right?
If this is true, then how do I free up all the memory that I have made with all the loops if I only have a pointer left pointing to the last malloc that happened?
Thanks!
Please allocate exactly the size you need: malloc(sizeof *node); -- if you move to a 64-bit platform that doubles the size of all your members, your old 96-byte structure might take 192 bytes in the new environment.
If you don't have any pointers to any of the struct Nodes you have created, then I don't think you should be allocating them with malloc(3) in the first place. malloc(3) is best if your application requires the data to persist outside the calling scope of the current function. I expect that you could re-write your function like this:
struct Node node;
while(...){
//do stuff with node
}
or
while(...){
struct Node node;
//do stuff with node
}
depending if you want access to the last node (the first version) or not (the second version).
Of course, if you actually need those structures outside this piece of code, then you need to store references to them somewhere. Add them to a global list keeping track of struct Node objects, or add each one to the next pointer of the previous struct Node, or add each one to a corresponding struct User that refers to them, whatever is best for your application.
If you set node = NULL before the loop and then use free(node) before node = malloc(100) you should be OK. You will also need to do a free(node) after the loop exits. But then again, it all depends on what "//do stuff with node" actually does. As others have pointed out, malloc(100) is not a good idea. What I would use is malloc(sizeof(*node)). That way, if the type of node changes, you don't have to change the malloc line.
If you don't need the malloc'ed space at the end of one iteration anymore, you should free it right away.
To keep track of the allocated nodes you could save them in a dynamically growing list:
#include <stdlib.h>
int main() {
int i;
void *node;
int prt_len = 0;
void **ptrs = NULL;
for (i = 0; i < 10; i++) {
node = malloc(100);
ptrs = realloc(ptrs, sizeof(void*) * ++prt_len);
ptrs[prt_len-1] = node;
/* code */
}
for (i = 0; i < prt_len; i++) {
free(ptrs[i]);
}
free(ptrs);
return 0;
}
Note: You should probably re-think your algorithm if you need to employ such methods!
Otherwise see sarnold's answer.
then how do I free up all the memory that I have made with all the loops if I only have a pointer left pointing to the last malloc that happened?
You can't. You just created a giant memory leak.
You have to keep track of every chunk of memory you malloc() and free() it when you're done using it.
You can not. You need to store all the pointer to free the memory. if you are saving those pointer somewhere then only you can free the memory.

Resources