segfault when accessing function in struct - c

I am trying to implement sets on top of red-black trees. My trees are defined with the following struct:
typedef struct rb_tree {
int (*compare)(const void* a, const void* b);
void (*destroy_key)(void* a);
void (*destroy_info)(void* a);
void (*print_key)(const void* a);
void (*print_info)(void* a);
rb_node* root;
rb_node* nil;
} rb_tree;
Whenever I try to access the compare function I get a segfault. e.g in the comparisons in the if statements in this helper function:
void tree_insert_help(rb_tree* tree, rb_node* z) {
rb_node* x;
rb_node* y;
rb_node* nil = tree->nil;
z->left = z->right = nil;
y = tree->root;
x = tree->root->left;
while( x != nil) {
y = x;
if (1 == tree->compare(x->key, z->key)) { /* x.key > z.key */
x = x->left;
} else { /* x,key < = z.key */
x = x->right;
}
}
z->parent = y;
if ( (y == tree->root) || (1 == tree->compare(y->key, z->key))) { /* y.key > z.key */
y->left = z;
} else {
y->right = z;
}
}
This is the code that I am using to test and am getting the segfault from. Note that I have
typedef struct rb_tree *set;
typedef struct rb_node *element;
in set.h
#include "set.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {;
int int_comp(const void* a,const void* b) {
if( *(int*)a > *(int*)b) return(1);
if( *(int*)a < *(int*)b) return(-1);
return(0);
}
void dfunc(void * a){
free((int*)a);
}
void dinfo(void* a){
;
}
void print_int(int* a){
printf("%d",*a);
}
set seta = new_set(int_comp, dfunc, dinfo, print_int, null_function);
int x = 10;
int y = 9;
int z = 12;
insert_element(seta, &x);
insert_element(seta, &y);
insert_element(seta, &z);
print_set(seta);
}
This code fails on the second insert, since it calls tree->compare. Using GDB to do a stack trace I get the following:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffffffde1b8 in ?? ()
(gdb) bt
#0 0x00007ffffffde1b8 in ?? ()
#1 0x0000000000400ce1 in TreeInsertHelp (tree=0x604010, z=0x604360) at red_black_tree.c:185
#2 0x0000000000400dce in RBTreeInsert (tree=0x604010, key=0x7ffffffde160, info=0x604340) at red_black_tree.c:233
#3 0x000000000040096b in insert_element (seta=0x604010, key=0x7ffffffde160) at set.c:22
#4 0x0000000000400848 in main (argc=1, argv=0x7ffffffde2c8) at test.c:38
Furthermore, this actually runs completely fine in valgrind. This is the first time I have used functions in structs in c. I have tried to lookup this issue elsewhere and have made little progress debugging it. Why would I get a segfault when I try to access the compare function in the tree struct?
EDIT:
New set is a wrapper for the following function which creates a new tree.
rb_tree* rb_tree_create( int (*comp_func) (const void*, const void*),
void (*dest_func) (void*),
void (*info_dest_func) (void*),
void (*print_func) (const void*),
void (*print_info)(void*)) {
rb_tree* new_tree;
rb_node* temp;
new_tree = (rb_tree*) safe_malloc(sizeof(rb_tree));
new_tree->compare = comp_func;
new_tree->destroy_key = dest_func;
new_tree->print_key = print_func;
new_tree->print_info = print_info;
new_tree->destroy_info = info_dest_func;
temp = (rb_node*) safe_malloc(sizeof(rb_node));
new_tree->nil = temp;
temp->parent = temp;
temp->left = temp;
temp->right = temp;
temp->red = 0;
temp->key = 0;
temp = (rb_node*) safe_malloc(sizeof(rb_node));
new_tree->root = temp;
temp->parent = new_tree->nil;
temp->left = new_tree->nil;
temp->right = new_tree->nil;
temp->key = 0;
temp->red = 0;
return(new_tree);
}
EDIT 2:
I resolved my problem. The functions which I was passing the pointers of to new_set were defined within the main function. When I moved them outside the the main function it stopped segfaulting.

You've created a struct, "compare" is a pointer to function. But it's pointing nowhere.
It should be set in your "new_set" function, but you didn't show it.
In your "new_set" function you should do something like this:
... // new_set_struct is a struct that you've created and returning from new_set function
new_set_struct->compare = &int_comp;
... // all other new_set_struct initial configuration is following
return new_set_struct;

Related

Why does pointer to custom struct doesn't work here?

Why pointer to custom struct doesn't work in that code?
Why I'm getting warning in that line with p->x = x?
Why I'm getting second warning in line with strcpy_s?
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct sptr {
int x;
char* s;
struct sptr* next;
} ptr;
void add(ptr* p, int x, const char* s) {
ptr* o = p;
p = (ptr*) malloc(sizeof(ptr));
p->x = x; // warning
p->s = (char*)malloc(20 * sizeof(char));
strcpy_s(p->s, 20, (char*)s); // warning
p->next = o;
}
void show(ptr* p) {
ptr* o = p;
while (o != NULL) {
printf("%d %s\n", o -> x, o -> s);
o = o->next;
}
}
int main() {
ptr* p = NULL;
add(p, 5, "xcvxvxv");
add(p, 7, "adadad");
show(p);
return 0;
}
Pointers are values.
add is receiving a copy of the NULL pointer value. Changing the local variable p, in add, to a new pointer value returned by malloc does not change the separate, local variable p in main.
Just as if you wanted to change the value of an int in the caller's scope, you'd use an int * argument:
void change(int *val)
{
*val = 10;
}
int main(void)
{
int a = 5;
change(&a);
}
Changing the value of an int * in the caller's scope would require an int ** argument.
#include <stdlib.h>
void change(int **val)
{
*val = malloc(sizeof **val);
}
int main(void)
{
int *a;
change(&a);
}
This extends to any type.
malloc can fail, and return NULL. Performing indirection on a NULL pointer value is Undefined Behaviour.
You must guard against this happening by checking the return value of malloc.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
int x;
char *s;
struct node *next;
} Node;
void add(Node **p, int x, const char *s) {
Node *new_node = malloc(sizeof *new_node);
if (!new_node) {
perror("allocating node");
exit(EXIT_FAILURE);
}
new_node->s = malloc(1 + strlen(s));
if (!new_node->s) {
perror("allocating node string");
exit(EXIT_FAILURE);
}
new_node->x = x;
strcpy(new_node->s, s);
new_node->next = *p;
*p = new_node;
}
void show(Node *p) {
while (p) {
printf("%d %s\n", p->x, p->s);
p = p->next;
}
}
int main(void) {
Node *list = NULL;
add(&list, 5, "xcvxvxv");
add(&list, 7, "adadad");
show(list);
}
Why pointer to custom struct doesn't work in that code?
TBD
Why I'm getting warning in that line with p->x = x?
Why I'm getting second warning in line with strcpy_s?
2 warnings occur because code de-referenced the pointer from malloc() without first checking if the pointer might be NULL.

Pass values up through a tree in C

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;
}

Binary tree implementation gives me segmentation fault in C

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);

Segmentation (core dumped)

I have been working on a post fix calculator for standard input and after working on it I ended up getting a saying segmentation fault (core dumped) it doesn't say where it occurs or what caused it and after looking for an explanation of what it means I couldn't really find anything that would help me fix it. So I decided I might as well ask here this is all of the stuff I have so far.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stack
{
int data;
struct stack *up;
};
void push( struct stack * ptr, int value)
{
struct stack * tmp;
tmp = malloc(sizeof(value));
tmp -> data = value;
tmp -> up = NULL;
}
int pop(struct stack * ptr)
{
int value;
struct stack * tmp;
tmp = ptr;
value = tmp-> data;
ptr = tmp -> up;
free(tmp);
return value;
}
int evaluate(int argc,const char * argv[],struct stack * ptr)
{
int h;
int i;
for (i = 0; i <= argc - 1; i++)
{
if (strcmp(argv[i], "M") == 0)
{
int a = pop(ptr);
int b = pop(ptr);
h = b*a;
push(ptr,h);
}
else if (strcmp(argv[i], "A") == 0)
{
printf("%s\n", "error \0");
int a = pop(ptr);
int b = pop(ptr);
h = b+a;
push(ptr,h);
}
else if (strcmp(argv[i], "D") == 0)
{
int a = pop(ptr);
int b = pop(ptr);
h = b/a;
push(ptr,h);
}
else if (strcmp(argv[i], "S") == 0)
{
int a = pop(ptr);
int b = pop(ptr);
h = b-a;
push(ptr,h);
}
else
{
printf("%s", "Not an operator");
}
}
return pop(ptr);
}
int main(int argc, const char *argv[])
{
struct stack s;
struct stack *ptr = s.up;
evaluate(argc,argv,ptr);
return EXIT_SUCCESS;
}
In main you create struct stack s; and don't initialize it.
Then you pass s.up as the third argument of evaluate.
And evaluate eventually calls pop on s.up, which calls free on s.up. But s.up is still uninitialized, so it crashes.
It's because you are allocating the structs wrong, here
tmp = malloc(sizeof(value));
you are allocating enough space for a int value, so the code that follows invokes undefined behavior leading in your case to a segmentation fault, try it this way
tmp = malloc(sizeof(struct stack));
or
tmp = malloc(sizeof(*tmp));
also, always check the success of malloc() before dereferencing the pointer, like this
void push(struct stack *ptr, int value)
{
struct stack *tmp;
tmp = malloc(sizeof(*tmp));
if (tmp == NULL)
return;
tmp->data = value;
tmp->up = NULL;
}

Implementing a Graph DFS

I am trying to implement a graph and perform DFS in C. but the dfs operation causes the bug that w gets allocated a random value once the pointer x runs off the queue of adjacent nodes. The condition !=NULL doesnt seem to do anything. I want it to break as soon as the queue empties, how to achieve this?
Also I wanted to know, how to implement a runtime version of the number of nodes? I believe that C does not support dynamic instance of arrays. Should I declare a very large array and use that?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct node {
int data;
struct node* next;
};
void add(struct node **bag, int data) {
struct node *newnode = malloc(sizeof(struct node));
newnode->data = data;
newnode->next = *bag;
*bag = newnode;
}
int V;
struct node *adj[7];
bool marked[7];
int edgeTo[7 * 6];
void initialize() {
int i = 0;
for (i = 0; i < 7; ++i) {
adj[i] = malloc(sizeof(struct node));
marked[i] = false;
}
}
void addEdge(int v, int w) {
add(&adj[v], w);
add(&adj[w], v);
}
void dfs(int v) {
printf("%d ", v);
marked[v] = true;
struct node *x = adj[v];
while (x != NULL) {
int w = x->data;
if (marked[w] == false) {
dfs(w);
}
x = x->next;
}
}
int main(int argc, char **argv) {
initialize();
addEdge(0, 1);
addEdge(0, 2);
addEdge(0, 5);
addEdge(1, 4);
addEdge(3, 2);
addEdge(3, 4);
addEdge(3, 5);
addEdge(3, 6);
addEdge(5, 2);
addEdge(6, 0);
addEdge(6, 4);
dfs(0);
printf("done");
return 0;
}
You haven't coded your initialize method correctly. Make sure you initialize your next to null adj[i]->next = NULL;
void initialize() {
int i = 0;
for (i = 0; i < 7; ++i) {
adj[i] = (node*)malloc(sizeof(struct node));
marked[i] = false;
adj[i]->data = 0;
adj[i]->next = NULL;
}
}

Resources