I would like to allocate a structure on the heap, initialize it and return a pointer to it from a function. I'm wondering if there's a way for me to initialize const members of a struct in this scenario:
#include <stdlib.h>
typedef struct {
const int x;
const int y;
} ImmutablePoint;
ImmutablePoint * make_immutable_point(int x, int y)
{
ImmutablePoint *p = (ImmutablePoint *)malloc(sizeof(ImmutablePoint));
if (p == NULL) abort();
// How to initialize members x and y?
return p;
}
Should I conclude from this that it is impossible to allocate and initialize a struct on the heap which contains const members?
Like so:
ImmutablePoint *make_immutable_point(int x, int y)
{
ImmutablePoint init = { .x = x, .y = y };
ImmutablePoint *p = malloc(sizeof *p);
if (p == NULL) abort();
memcpy(p, &init, sizeof *p);
return p;
}
(Note that unlike C++, there is no need to cast the return value of malloc in C, and it is often considered bad form because it can hide other errors).
If this is C and not C++, I see no solution other than to subvert the type system.
ImmutablePoint * make_immutable_point(int x, int y)
{
ImmutablePoint *p = malloc(sizeof(ImmutablePoint));
if (p == NULL) abort();
// this
ImmutablePoint temp = {x, y};
memcpy(p, &temp, sizeof(temp));
// or this
*(int*)&p->x = x;
*(int*)&p->y = y;
return p;
}
If you insist on keeping the const in the structure, you are going to have to do some casting to get around that:
int *cheat_x = (int *)&p->x;
*cheat_x = 3;
I like caf's approach, but this occured to me too
ImmutablePoint* newImmutablePoint(int x, int y){
struct unconstpoint {
int x;
int y;
} *p = malloc(sizeof(struct unconstpoint));
if (p) { // guard against malloc failure
*p.x = x;
*p.y = y;
}
return (ImmutablePoint*)p;
}
Related
I was wondering if I have a code like this:
struct something{
int x;
float y;
};
int main(void)
{
struct something *p;
p = malloc(sizeof(struct something));
p->x = 2;
p->y = 5.6;
return 0;
}
what's the content of *p (with *) if called somewhere? Is it the address of the structure or what?
Here's an example of the usage of *p - that is, dereferencing the pointer:
#include <stdio.h>
#include <stdlib.h>
struct something {
int x;
float y;
};
int main(void) {
struct something *p;
p = malloc(sizeof *p);
p->x = 2;
p->y = 5.6;
struct something s;
s = *p; // dereference p and copy into s
free(p);
// now check s:
printf("%d, %.1f\n", s.x, s.y); // prints 2, 5.6
}
p is a pointer to struct something. *p will dereference that pointer to give the struct itself. But, here is the catch: struct (*p) is a composite data type, you need to use a . operator to get its member.
(*p).x = 2;
(*p).y = 5.6;
This can also be done without using the indirection operator (*) (as you did):
p->x = 2;
p->y = 5.6;
This question already has answers here:
How to initialize const in a struct in C (with malloc)
(6 answers)
Closed 2 years ago.
I have a point struct:
struct Point
{
const int x;
const int y;
};
In my code I have many of these points so I'd like to create pointers to them so I don't see them copied over and over while I work on them.
Knowing that you can initialize constant members of structs like so:
struct Point my_point = { .x = 1, .y = 2};
I thought I could do the same with dynamically allocated structures. But it doesn't appear to be the case:
struct Point *point = malloc(sizeof(struct Point));
*point = (struct Point){.x = 1, .y = 2};
However I get
main.c: In function ‘main’:
main.c:23:8: error: assignment of read-only location ‘*point’
*point = (struct Point){.x = 1, .y = 2};
When using GCC 7.1.1. On clang I get
prog.c:23:8: error: cannot assign to lvalue with const-qualified data member 'x'
*point = (struct Point){.x = 1, .y = 2};
~~~~~~ ^
prog.c:14:15: note: data member 'x' declared const here
const int x;
~~~~~~~~~~^
prog.c:15:15: note: data member 'y' declared const here
const int y;
~~~~~~~~~~^
1 error generated.
Is there a method to do this?
example
#include <stdio.h>
#include <stdlib.h>
struct Point
{
const int x;
const int y;
};
int main()
{
struct Point *point = malloc(sizeof(struct Point));
*point = (struct Point){.x = 1, .y = 2};
return 0;
}
I cannot really see a good way around this. In C++ you would have solved this with constructors and private members.
But you can use memcpy, which is safe:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Point {
const int x;
const int y;
};
int main(void){
struct Point *p = malloc(sizeof *p);
memcpy(p, &(struct Point) {.x=1, .y=2 }, sizeof *p);
printf("%d %d\n", (*p).x, (*p).y);
}
It's possible to use variables for this:
int x=1; int y=2;
memcpy(p, &(struct Point) {.x=x, .y=y }, sizeof *p);
If you're using gcc, you could use a compiler extension:
memcpy(p, &(typeof(*p)) {.x=1, .y=2 }, sizeof *p);
But I do expect that the following would be a better approach in most situations:
struct Point
{
int x; // Remove const here
int y;
};
int main(void)
{
// Allocate and assign a non const object
struct Point *tmp_ptr = malloc(sizeof *tmp_ptr);
*tmp_ptr = (struct Point) {.x=1, .y=2};
// Create a new const pointer
const struct Point *p = tmp_ptr;
// This will invoke compiler error
(*p).x = 42;
}
The best solution is to const-qualify the struct as whole, not individual members. You can wrap the allocation and initialization inside a "constructor", which returns a read-only pointer:
typedef struct
{
int x;
int y;
} point_t;
const point_t* point_create (void)
{
point_t* obj = malloc(sizeof *obj);
if(obj == NULL)
return NULL;
*obj = (point_t){.x = 1, .y = 2};
return obj;
}
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;
}
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;
A struct like the following works fine, I can use t after calling malloc(sizeof(mystruct)):
struct mystruct {
MyDef *t[5];
};
I want to be able to dynamically set the length of the array of MyDef, like the following:
struct mystruct {
MyDef **t;
int size;
};
What do I need to do additionally to malloc(sizeof(mystruct)) to get this to work, so I can do TestStruct->t[3] = something? Just getting a segmentation fault!
Thanks!
EDIT with code that causes seg fault, unless I'm blind this seems to be what the answers are so far:
#include <stdio.h>
typedef struct mydef {
int t;
int y;
int k;
} MyDef;
typedef struct mystruct {
MyDef **t;
int size;
} MyStruct;
int main(){
MyStruct *m;
if (m = (MyStruct *)malloc(sizeof(MyStruct)) == NULL)
return 0;
m->size = 11; //seg fault
if (m->t = malloc(m->size * sizeof(*m->t)) == NULL)
return 0;
return 0;
}
struct mystruct *s = malloc(sizeof(*s));
s->size = 5;
s->t = malloc(sizeof(*s->t) * s->size);
m = (MyStruct*)malloc(sizeof(MyStruct)) == NULL
What that does. Calls malloc, compares return of malloc to NULL. Then assigns the result of that comparison(a boolean value) to m.
The reason it does that is because '==' has a higher precedence than '='.
What you want:
if ( (m = (MyStruct *)malloc(sizeof(MyStruct))) == NULL)
...
if ( (m->t = malloc(m->size * sizeof(*m->t))) == NULL)
That happens because you do not allocate memory for array itself, only for pointer to this array.
So, first you have to allocate mystruct:
struct_instance = malloc(sizeof(mystruct));
and then you have to allocate memory for array of pointers to MyDef and initialize pointer in your struct
struct_instance->size = 123;
struct_instance->t = malloc(sizeof(MyDef*) * struct_instance->size);