I'm writing a simple parser in C and I'm not sure which is the best way to pass results up my tree as it gets evaluated.
Here's my current code, the node struct and the walk function to evaluate the tree.
typedef struct node {
struct node* left;
struct node* right;
void* data;
Symbol type;
} node;
void* walk(node* n) {
if (n != NULL) {
if (n->type == plus) {
int x = 0;
int a = *(int*)walk(n->left);
int b = *(int*)walk(n->right);
x = a + b;
return &x;
} else if (n->type == number) {
return (int*)n->data;
}
}
return NULL;
}
From the code you can see when I add two numbers together I'm storing the result in a local variable and returning the address to that variable, I know this is undefined behaviour, so I thought about using malloc and changing my code to this:
int* x = malloc(1 * sizeof(int));
int a = *(int*)walk(n->left);
int b = *(int*)walk(n->right);
*x = a + b;
return x;
But the problem with this code is, I'm not sure what is the best way to free this memory I just malloc'd.
Should I walk the tree a second time and free all of the memory that way or is the a better way to free the memory when I'm done or is there a better way to propagate values through my tree?
No need to traverse the tree for second time. Notice that you do not need values of a and b after summing them into x. so you can free them after addition which is shown in #flu's answer. More over, you can do it without using extra memory for flag.
Note: this code will through runtime error for invalid input. to handle this errors check for NULL pointers before accessing a pointer.
void* walk(node* n) {
if (n != NULL) {
if (n->type == plus) {
int * x = malloc(sizeof(int));
int * a = (int*)walk(n->left);
int * b = (int*)walk(n->right);
*x = *a + *b;
free(a);
free(b);
return x;
} else if (n->type == number) {
int * val = malloc(sizeof(int)); //allocate dynamic memory for the leaf node so that all nodes can be freed without checking.
*val = n->data;
return val;
}
}
return NULL;
}
You could add an extra argument needToFree to inform the caller to free the returned pointer.
void* walk(node* n, bool* needToFree) {
if (n != NULL) {
if (n->type == plus) {
bool needToFreeA;
bool needToFreeB;
int * x = malloc(sizeof(int));
int * a = (int*)walk(n->left, &needToFreeA);
int * b = (int*)walk(n->right, &needToFreeB);
*x = *a + *b;
if( needToFreeA ) free(a);
if( needToFreeB ) free(b);
*needToFree = true;
return x;
} else if (n->type == number) {
*needToFree = false;
return (int*)n->data;
}
}
*needToFree = false;
return NULL;
}
Related
I'm getting a segmentation fault when trying to access data stored in my TreeNode. Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct NodeTag{
int value;
struct NodeTag *LLink;
struct NodeTag *RLink;
} TreeNode;
void inOrder(TreeNode * n){
if(n->LLink != NULL)
inOrder(n->LLink);
printf("%d ", n->value);
if(n->RLink != NULL)
inOrder(n->RLink);
}
void newNode(TreeNode * n, int v){
n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
}
void addValue(TreeNode * r, int value){
if(value < r->value){
if(r->LLink == NULL){
newNode(r->LLink, value);
} else {
addValue(r->LLink, value);
}
} else if (value > r->value) {
if(r->RLink == NULL){
newNode(r->RLink, value);
} else {
addValue(r->RLink, value);
}
}
}
int main(){
TreeNode * root = 0;
newNode(root, 1);
printf("%d\n", root->value); //<--This is where I get the fault
//addValue(root, 3);
//addValue(root, 10);
//addValue(root, 2);
//inOrder(root);
return 0;
}
If anyone can explain to me why I'm getting this error it would be greatly appreciated. I'm a student learning C and I'm not too familiar with pointers and such.
void newNode(TreeNode * n, int v){
n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
}
In this code, n is a pointer to a TreeNode struct but if you assign something to n, this is not visible outside of the function as the pointer is passed by value.
void writeToA ( int a ) {
a = 5;
}
int main ( ) {
int x = 10;
writeToA(x)
printf("%d\n", x);
}
What will this code print? It will print 10, not 5. That's because the value of x is passed to the function, not a reference to x. Changing that value within the function will not change the value of x outside the function.
A pointer is also a value, basically it is an int and the int value is a memory address:
void writeToPtr1 ( int * a ) {
int i = 10;
a = &i; // `a` now points to the memory address of i
}
void writeToPtr2 ( int * a ) {
*a = 5; // This doesn't change where `a` points to,
// it writes 5 to the memory address to that `a` points to.
}
int main ( ) {
int x = 10;
int *ptr = &x; // ptr now points to the memory address of x!
writeToPtr1(ptr);
// ptr still points to the memory address of x!
// As not a reference to ptr was passed, the memory
// address of x was passed to the function!
writeToPtr2(ptr);
// ptr still points to the memory address of x!
// But this memory now has the value 5 and not 10 anymore.
}
You need to return the result of the allocation:
TreeNode * newNode ( int v ) {
TreeNode * n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
return n;
}
int main ( ) {
TreeNode * root = newNode(1);
printf("%d\n", root->value);
return 0;
}
Or you need to pass a reference to the pointer and then change the value the pointer points to:
void newNode ( TreeNode ** outNode, int v ) {
// TreeNode ** is a pointer to a pointer to a TreeNode!
TreeNode * n = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
*outNode = n; // Make the pointer point to `n`
}
int main ( ) {
TreeNode * root = NULL;
newNode(&root, 1); // Pass a pointer to root
printf("%d\n", root->value);
return 0;
}
newNode shall either return a pointer to allocated memory or you can send double pointer to the function and allocate memory there.
TreeNode* newNode(int v){
TreeNode *new_node = malloc(sizeof(TreeNode));
n->value = v;
n->LLink = NULL;
n->RLink = NULL;
return new_node
}
or
void newNode(TreeNode ** n, int v){
*n = malloc(sizeof(TreeNode));
(*n)->value = v;
(*n)->LLink = NULL;
(*n)->RLink = NULL;
}
In C arguments are passed by value. Calling newNode(r->LLink, value) will therefore not modify r->LLink.
Consider this simple function:
void Foo(int x)
{
x = x * 2 ;
}
Will calling Foo(n) multiply n by 2 ? No.
You would either need this:
void Foo(int *x)
{
*x = *x * 2 ;
}
and call Foo(&n);
or:
void Foo(int x)
{
return x * 2 ;
}
and call n = Foo(n);
I try to write a function which return an array of integers containing the node values of the binary tree in preorder that is a node value must appear before the values of its left and right child.
if root is NULL, return NULL
for every node left child comes before right child
For example;
int *a = preorder(bt1);
for (i=0; i<3; i++)
printf("%d ", a[i]);
>2_1_3_
Here is my work, but it doesn't work, where could be the problem in my code?
int* preorder(TreeNode *root) {
int *a = malloc(sizeof(int)*50);
int i=0;
if(root == NULL)
return NULL;
else {
if(root != NULL) {
a[i] = root->val;
i++;
preorder(root->left);
preorder(root->right);
return a;
}
}
}
You have two issues in the code:
You have to allocate the array for results once. Before calling preorder
You have to keep i outside of preorder to allow it to change between calls
One example is the following code:
int *a = malloc(sizeof(int)*50);
int inx = 0;
preorder(bt1, a, &inx);
void preorder(TreeNode *root, int* a, int* inx) {
if(root == NULL)
return;
else {
if(root != NULL) {
a[*inx] = root->val;
*inx = *inx + 1;
preorder(root->left, a, inx);
preorder(root->right, a, inx);
}
}
}
In each recursive call of this function you will allocate:
int *a = malloc(sizeof(int)*50);
You need to allocate space for array once and then use that same array. Same thing is for using i = 0. You need to use one counter.
You may want create array in main function, and then pass array as function argument. Or you could use global array, and access it that way. Same thing for counter variable.
Note: I don't see point of memory allocation in your example. You should better use static array if you're sure that tree won't have more then ARRAY SIZE nodes.
With the wanted function signature of preorder() a solution is not possible. Therefore you need a helper function for the root == NULL case and a traversal function which a pointer to the current position in the array. It also returns a pointer to the next free slot in the array. A solution could look like:
#include <stdio.h>
#include <malloc.h>
struct TreeNode {
int val;
struct TreeNode* left, * right;
};
int tree_size(/*struct TreeNode* tree*/) { return 7; }
int* preorder_(struct TreeNode* tn, int* v) {
*v++ = tn->val;
if (tn->left) v = preorder_(tn->left, v);
if (tn->right) v = preorder_(tn->right, v);
return v;
}
int* preorder(struct TreeNode* tn) {
if (tn) {
int* v = malloc(tree_size(/*tn*/) * sizeof(int));
preorder_(tn, v);
return v;
} else {
return NULL;
}
}
int main(void) {
// 4
// 2 5
// 1 3 6 7
struct TreeNode
left = {2, &{1}, &{3]},
right = {5, &{6}, &{7}},
root = {4, &left, &right};
int *v, i;
v = preorder(&root);
for (i = 0; i < tree_size(/*tn*/); i++) {
printf("%d ", v[i]); // 4 2 1 3 5 6 7
}
free(v);
return 0;
}
Live Demo
I'm currently dealing with a generic Tree with this structure:
typedef struct NODE {
//node's keys
unsigned short *transboard;
int depth;
unsigned int i;
unsigned int j;
int player;
int value;
struct NODE *leftchild; //points to the first child from the left
struct NODE *rightbrothers; //linked list of brothers from the current node
}NODE;
static NODE *GameTree = NULL;
While the function that allocates the different nodes is (don't bother too much at the keys' values, basically allocates the children-nodes. If there aren't any the new child goes to leftchild, otherwise it goes at the end of the list "node->leftchild->rightbrothers"):
static int AllocateChildren(NODE **T, int depth, unsigned int i, unsigned int j, int player, unsigned short *transboard) {
NODE *tmp = NULL;
if ((*T)->leftchild == NULL) {
if( (tmp = (NODE*)malloc(sizeof(NODE)) )== NULL) return 0;
else {
tmp->i = i;
tmp->j = j;
tmp->depth = depth;
(player == MAX ) ? (tmp->value = 2 ): (tmp->value = -2);
tmp->player = player;
tmp->transboard = transboard;
tmp->leftchild = NULL;
tmp->rightbrothers = NULL;
(*T)->leftchild = tmp;
}
}
else {
NODE *scorri = (*T)->leftchild;
while (scorri->rightbrothers != NULL)
scorri = scorri->rightbrothers;
if( ( tmp = (NODE*)malloc(sizeof(NODE)) )== NULL) return 0;
else {
tmp->i = i;
tmp->j = j;
tmp->depth = depth;
(player == MAX) ? (tmp->value = 2) : (tmp->value = -2);
tmp->player = player;
tmp->transboard = transboard;
tmp->leftchild = NULL;
tmp->rightbrothers = NULL;
}
scorri->rightbrothers = tmp;
}
return 1;
}
I need to come up with a function, possibly recursive, that deallocates the whole tree, so far I've come up with this:
void DeleteTree(NODE **T) {
if((*T) != NULL) {
NODE *tmp;
for(tmp = (*T)->children; tmp->brother != NULL; tmp = tmp->brother) {
DeleteTree(&tmp);
}
free(*T);
}
}
But it doesn't seem working, it doesn't even deallocate a single node of memory.
Any ideas of where I am being wrong or how can it be implemented?
P.s. I've gotten the idea of the recursive function from this pseudocode from my teacher. However I'm not sure I've translated it correctly in C with my kind of Tree.
Pseudocode:
1: function DeleteTree(T)
2: if T != NULL then
3: for c ∈ Children(T) do
4: DeleteTree(c)
5: end for
6: Delete(T)
7: end if
8: end function
One thing I like doing if I'm allocating lots of tree nodes, that are going to go away at the same time, is to allocate them in 'batches'. I malloc then as an array of nodes and dole them out from a special nodealloc function after saving a pointer to the array (in a function like below). To drop the tree I just make sure I'm not keeping any references and then call the free routine (also like below).
This can also reduce the amount of RAM you allocate if you're lucky (or very smart) with your initial malloc or can trust realloc not to move the block when you shrink it.
struct freecell { struct freecell * next; void * memp; } * saved_pointers = 0;
static void
save_ptr_for_free(void * memp)
{
struct freecell * n = malloc(sizeof*n);
if (!n) {perror("malloc"); return; }
n->next = saved_pointers;
n->memp = memp;
saved_pointers = n;
}
static void
free_saved_memory(void)
{
while(saved_pointers) {
struct freecell * n = saved_pointers;
saved_pointers = saved_pointers->next;
free(n->memp);
free(n);
}
}
I've just realized my BIG mistake in the code and I'll just answer myself since no one had found the answer.
The error lies in this piece of code:
for(tmp = (*T)->children; tmp->brother != NULL; tmp = tmp->brother) {
DeleteTree(&tmp);
}
First of all Ami Tavory was right about the for condition, i need to continue as long as tmp != NULL
Basically it won't just work because after the DeleteTree(&tmp), I can no longer access the memory in tmp because it's obviously deleted, so after the first cycle of for ends I can't do tmp = tmp->rightbrother to move on the next node to delete because tmp->rightbrother no longer exists as I just deleted it.
In order to fix it I just needed to save the tmp->brother somewhere else:
void DeleteTree(NODE **T) {
if((*T) != NULL) {
NODE *tmp, *deletenode, *nextbrother;
for(tmp = (*T)->children; tmp != NULL; tmp = nextbrother) {
nextbrother = tmp->rightbrother;
DeleteTree(&tmp);
}
canc = (*T);
free(*T);
(*T) = NULL;
}
}
Just for the sake of completeness I want to add my version of DeleteTree
void DeleteTree(NODE *T) {
if(T != NULL) {
DeleteTree(T->rightbrothers);
DeleteTree(T->leftchild);
free(T);
}
}
I think it is much less obscure and much easier to read. Basically it solves the issue in DeleteTree but through eliminating the loop.
Since we free the nodes recursively we might as well do the whole process recursively.
typedef struct student *std_ptr;
struct student
{
int number;
std_ptr next;
};
typedef std_ptr STACK;
create_stack(void)
{
STACK S;
S = (STACK) malloc( sizeof( struct student ) );
if(S == NULL) printf("out of space!");
return S;
}
void push(int x, STACK S)
{
std_ptr tmp;
tmp = (std_ptr) malloc(sizeof(struct student));
if(tmp == NULL) printf("out of space!");
else
{
tmp -> number = x;
tmp -> next = S -> next;
S -> next = tmp;
}
}
int main()
{
push(12058010,STACK S);
return 0;
}
Im trying to call function and I get error: expected expression before stack.I also tried to call the function like that
int main()
{
push(12058010,S);
return 0;
}
This time I get error: 'S' undeclared(first use in this function)
Thank you for your help!
Define the variable s by doing:
STACK s;
Initialise it:
s = create_stack();
Test whether the initialisation succeeded:
if (NULL == s)
{
return EXIT_FAILURE;
}
Use it by calling push() like this:
push(12058010, s);
All together this could look like this:
int main(void)
{
STACK s = create_stack(); /* This merges step 1 and 2. */
if (NULL == s)
{
return EXIT_FAILURE;
}
push(12058010, s);
return EXIT_SUCCES;
}
S is neither in the global scope nor in the scope of main().
I suspect you meant to write STACK S = create_stack(); as the first statement in main().
Don't forget to free the allocated memory as well.
I have the following data structure:
struct scoreentry_node {
struct scoreentry_node *next;
int score;
char name[1];
};
typedef struct scoreentry_node *score_entry;
I am trying to create a function that consumes my structure in order and arranges them in ascending order based on the name. I want to modify the input without allocating any memory or freeing anything:
I've tried your suggestions:
void selectionsort(score_entry *a) {
for (; *a != NULL; *a = (*a)->next) {
score_entry *minafteri = a;
// find position of minimal element
for (score_entry j = (*a)->next; j != NULL; j = j->next) {
if (strcmp(j->name, (*minafteri)->name) == -1) {
*minafteri = j;
}
}
// swap minimal element to front
score_entry tmp = *a;
a = minafteri;
*minafteri = tmp;
}
}
I'm testing the above code with the following:
score_entry x = add(8, "bob", (add( 8 , "jill", (add (2, "alfred", NULL)))));
iprint("",x);
selectionsort(&x);
iprint("", x);
clear(x); //Frees the whole list
iprint() prints the score and name fields in the struct. My add function is as follows:
score_entry add(int in, char *n, score_entry en) {
score_entry r = malloc(sizeof(struct scoreentry_node) + strlen(n));
r->score = in;
strcpy(r->name, n);
r->next = en;
return r;
}
I'm getting heap errors and my second print doesn't print the sorted list, it prints nothing. What am I doing wrong, and what can I do to fix it?
besides passing the pointer by address (see comments below) you also need to fix the way you swap elements too
void selectionsort(score_entry *a) {
for (; *a != NULL; *a = (*a)->next)
{
score_entry *minafteri = a;
// find position of minimal element
for (score_entry j = (*a)->next; j != NULL; j = j->next) {
if (strcmp(j->name, (*minafteri)->name) == -1) {
*minafteri = j;
}
}
// swap minimal element to front
score_entry tmp = *a;
a = minafteri; // put the minimal node to current position
tmp->next = (*a)->next ; //fix the links
(*minafteri)->next=tmp; //fix the links
}
}
You have to pass the argument to selectionsort by reference:
void selectionsort(score_entry *a) {
for (; *a != NULL; *a = (*a)->next)
{
score_entry *minafteri = a;
// find position of minimal element
for (score_entry j = (*a)->next; j != NULL; j = j->next) {
if (strcmp(j->name, (*minafteri)->name) == -1) {
*minafteri = j;
}
}
// swap minimal element to front
score_entry tmp = *a;
a = minafteri;
*minafteri = tmp;
}
}
This code is hideous! Not only have you not provided us with all of the necessities to reproduce your problem (we can't compile this!), but you've hidden pointer abstractions behind typedef (also a nightmare for us). Generally speaking, one shouldn't even use linked lists in C anymore let alone sort them...
Nonetheless, there are two answers here.
*minafteri = j; found within your find loop actually modifies your list! Why should your find loop be modifying your list?
Answer: it shouldn't! By instead assigning minafteri = &j->next, you won't be modifying the list with your find loop...
Alternatively, you could perform the swap inside of that loop.
*minafteri = j; would need to swap the following, in this order:
(*minafteri)->next and j->next
*minafteri and j
Do you think that single line of code is capable of performing those two swaps? Well, it gets half way through one of them... and removes a heap of elements from your list in the process!
The following appears to be a faulty attempt swapping elements:
score_entry *minafteri = a; // half of assigning `a` to `a`
/* SNIP!
* Nothing assigns to `minafteri` in this snippet.
* To assign to `minafteri` write something like `minafteri = fubar;` */
score_entry tmp = *a; // half of assigning `*a` to `*a`
a = minafteri; // rest of assigning `a` to `a`
*minafteri = tmp; // rest of assigning `*a` to `*a`
It's really just assigning *a to *a and a to a... Do you think you need to do that?
I'd have thought you'd notice that when you were creating your MCVE... Ohh, wait a minute! Shame on you!
Focus on swapping two nodes within a list as a smaller task. Once you've done that, consider taking on this task.
There are multiple problems in your code:
if (strcmp(j->name, (*minafteri)->name) == -1) { is incorrect: strcmp() does not necessarily return -1 when the first string is less than the second, it can return any negative value.
The way you adjust the links in order to move the lower entry is incorrect: you cannot update the link from the previous node to the one you move to the start. The list is corrupted.
Here is an improved version:
void selectionsort(score_entry *a) {
for (; *a != NULL; a = &(*a)->next) {
// find position of minimal element
score_entry *least = a;
for (score_entry *b = &(*a)->next; *b != NULL; b = &(*b)->next) {
if (strcmp((*b)->name, (*least)->name) < 0) {
least = b;
}
}
if (least != a) {
// swap minimal element to front
score_entry n = *least;
*least = n->next; /* unlink node */
n->next = *a; /* insert node at start */
*a = n;
}
}
}
Here is the Java Implementation of Selection Sort on Linked List:
Time Complexity: O(n^2)
Space Complexity: O(1) - Selection sort is In-Place sorting algorithm
class Solution
{
public ListNode selectionSortList(ListNode head)
{
if(head != null)
{
swap(head, findMinimumNode(head));
selectionSortList(head.next);
}
return head;
}
private void swap(ListNode x, ListNode y)
{
if(x != y)
{
int temp = x.val;
x.val = y.val;
y.val = temp;
}
}
private ListNode findMinimumNode(ListNode head)
{
if(head.next == null)
return head;
ListNode minimumNode = head;
for(ListNode current = head.next; current != null; current = current.next)
{
if(minimumNode.val > current.val)
minimumNode = current;
}
return minimumNode;
}
}