Struct with a member that is the struct itself - c

I have a struct with several members and one of them is the same struct itself. What I want to do is have a pointer to a struct related to that same struct but is of the same type. The compiler does not recognize the type when reading the struct members since it is still to be defined. Is there any alternative way to do what I want to happen?
typedef struct _panels
{
int id;
// Dimensions
double length;
double height;
// Global coordinates of origin of LCS
double origX;
double origY;
double origZ;
// Orientation of local x-axis wrt global X-axis
double angle;
// Panel reinforcement
int nReinforcement;
double *xReinf; // arbitrary spacing
double sx; // fixed spacing
double xReinf0; // x-coordinate of first rebar
// CHB unit
CHBUnit *chb;
// Openings
int nOpenings;
CHBOpening *openings;
// Pointer to adjacent panels
CHBPanel * left; int leftPanelID;
CHBPanel * right; int rightPanelID;
}CHBPanel;

You should use the defined (incomplete in the definition of the structure) type struct _panels instead of CHBPanel, which is not defined yet, to declare pointers to the structure itself.
The last part
CHBPanel * left; int leftPanelID;
CHBPanel * right; int rightPanelID;
should be
struct _panels * left; int leftPanelID;
struct _panels * right; int rightPanelID;
Alternative way: You can do the typedef before the declaration of the structure.
typedef struct _panels CHBPanel;
struct _panels
{
int id;
/* snipped */
// Pointer to adjacent panels
CHBPanel * left; int leftPanelID;
CHBPanel * right; int rightPanelID;
};

Related

Declaring object classes in C?

I declared a few geometric figures types such as:
typedef struct s_sphere{
t_tuple origin;
double radius;
} t_sphere;
typedef struct s_cylinder{
t_tuple origin;
double height;
double radius;
} t_cylinder;
typedef struct s_triangle{
t_tuple A;
t_tuple B;
t_tuple C;
} t_triangle;
etc...
Now, I would like to declare an intersection type which will contain two doubles and a geometric figure. I will then store all my intersections in a chained list:
// I do not know what type to give to geometric_figure
typedef struct s_intersection{
double t1;
double t2;
// what_type geometric_figure;
} t_intersection;
typedef struct s_intersection_list{
t_intersection intersection;
struct s_intersection_list *next;
} t_intersection_list;
I could use void* geometric_figure but I would like to avoid the most mallocs possible.
Is there a handy way of getting where I want without allocating geometric_object ?
type which will contain two doubles and a geometric figure.
Consider union with an identifier.
typedef struct s_intersection{
double t1;
double t2;
int id; // some id to know what type follows
union {
t_sphere sph;
t_cylinder cyl;
t_triangle tri;
} u;
} t_intersection;
If t_intersection is to be allocated, consider a flexible member array to right size the allocation.
typedef struct s_intersection{
double t1;
double t2;
int id; // some id to know what type follows
union {
t_sphere sph;
t_cylinder cyl;
t_triangle tri;
} u[]; // FAM
} t_intersection;
Example: allocate a triangle.
t_intersection *p = malloc(sizeof *p + sizeof p->u[0].tri);

Access struct in struct

I am working on a tree algorithm. These are the structures in my program:
typedef struct{
double m;
double x[DIM];
double v[DIM];
} Particle;
typedef struct{
double lower[DIM];
double upper[DIM];
} Box;
typedef struct Node{
Particle p;
Box box;
struct Node *son[4];
} Node;
Now I have written a function myFunctA() which is given by:
void myFunctA(Particle *p, Node *t){
int b=soNum(&t->box, &t->son->box, p); // Why does "&t->son->box" not work?
// do stuff ...
}
Within function myFunctA() I want to pass the box of t and the box of the son of t to the function soNum(). soNum() is given by
int soNum(Box *box, Box *sonbox, Particle *p){
// do stuff ...
}
I am trying to do this by using &t->son->box which does not work. I also tried (&t->son)->box. The error I get is always:
error: request for member ‘box’ in something not a structure or union
int b=soNum(&t->box, &t->son->box, p);
I think this is easy, but I am still quite new to C and find it somehow difficult to see it. I hope someone can help me!
Operator -> applies to a pointer, not to a struct. t is a pointer so t->son is correct. However, son is not a pointer, it is an array of pointers. Therefore
t->son->box
needs to be
t->son[someIndex]->box
where someIndex is an expression evaluating to an int between zero and three, inclusive.
t->son->box needs to be something like t->son[INDEX]->box (son is an array of node pointers).
This compiles:
#define DIM 3
typedef struct{
double m;
double x[DIM];
double v[DIM];
} Particle;
typedef struct{
double lower[DIM];
double upper[DIM];
} Box;
typedef struct Node{
Particle p;
Box box;
struct Node *son[4];
} Node;
int soNum(Box *box, Box *sonbox, Particle *p){
// do stuff ...
return 0;
}
void myFunctA(Particle *p, Node *t){
int b=soNum(&t->box, &t->son[0]->box, p); // Why does "&t->son->box" not work?
// do stuff ...
}

Warning: assignment from incompatible pointer type (Pointers and structures)

I have below two structures defined for my maze robot.
struct mazecells{
char type;
int reachable;
int visited;
};
typedef struct maze {
struct mazecells **M;
int startx, starty;
int numrows, numcolumns;
int initdir;
}maze_t;
void ReadMaze(maze_t *maze) {
char **mazeValue;
... remaining declaration and logic ...
Inside mazevalue I have read the maze input and then I am trying to assign it to you struct maze_t using maze->M = mazeValue. I'm getting below warning:
warning: assignment from incompatible pointer type
maze->M = mazeValue;
Am I misunderstanding or missing something?
Maybe I'm missing it but why don't you make mazeValue a mazecells?
struct mazecells{
char type;
int reachable;
int visited;
};
typedef struct maze {
struct mazecells **M;
int startx, starty;
int numrows, numcolumns;
int initdir;
}maze_t;
void ReadMaze(maze_t *maze) {
struct mazecells **mazeValue;
...
Take a look at these two lines:
struct mazecells **M;
char **mazeValue;
As you can clearly see, these two variables have different types, and because of that, you're getting warning: assignment from incompatible pointer type when you're trying to assing this value maze->M = mazeValue;
mazeValue is of type char ** (i.e. pointer to pointer to char) while maze->M is of type struct mazecells ** (i.e. pointer to pointer to struct mazecells).
The warning states that these two variables are of different types of pointers, and you are assigning one to the other, which could lead to unexpected results.
Depending on how you read the values, you might want to change the type of mazeValue.
Types must match each other. The following is a clean compile without warnings that hopefully has something you can use.
#include <stdio.h>
struct mazecells {
char type;
int reachable;
int visited;
};
typedef struct maze {
struct mazecells **M;
int startx, starty;
int numrows, numcolumns;
int initdir;
} maze_t;
int main() {
maze_t maze1 = { .startx = 1, .starty = 1 };
struct mazecells mz = { .type = 'A', .reachable = 1, .visited = 1 };
struct mazecells * mptr = &mz;
struct mazecells ** mptr2 = &mptr;
maze1.M = mptr2;
struct mazecells * structmazecells = * maze1.M;
printf("%d", structmazecells->visited);
return 0;
}

Is it possible to do inheritance from an abstract/base struct or simulate something along those lines in C?

I am currently working with a C program that uses structs composed of xyz coordinates, but sometimes these coordinate may refer to vectors (Force/velocity type, not the data structure) while at other times it may be referring to position. I know its possible to simply use one struct for all of these different conditions since they all use mostly the same data type (float), but to simply keep my math better organized (plus variable and struct names) and keep things from getting mixed up, is there a way to define a base struct that defines itself as having three floats, be inherited by another struct that more specifically defines what the struct is supposed to be (such as position instead of velocity, etc. etc.)? I know C is not OOP, but it seems like it could be possible to do this Here is what the base struct would be like:
struct ThreeDCartesianData
{
float x;
float y;
float z;
};
A more specific struct would inherit from that and perhaps define extra variables, or use different names for the variables. There will be multiple position structs being used, but I think only one velocity struct for each set of data. I have seen similar questions to this, but they all seem to be referring to a higher level language (C++, C#, etc. etc.)
You can use a union for this. Your main struct would contain a union of the "derived" structs as well as a "flag" field telling you which member of the union is valid:
enum { DERIVED11, DERIVED2, DERIVED3 };
struct derived1 { int x1; };
struct derived2 { char x2; };
struct derived3 { float x3; };
struct ThreeDCartesianData
{
float x;
float y;
float z;
int derivedType;
union {
struct derived1 d1;
struct derived2 d2;
struct derived3 d3;
} derived;
};
Then you can use them like this:
struct ThreeDCartesianData data1;
data1.x=0;
data1.y=0;
data1.z=0;
data1.derivedType = DERIVED1;
data1.derived.d1.x1 = 4;
You could alternately define them like this:
struct common
{
int type;
float x;
float y;
float z;
};
struct derived1
{
int type;
float x;
float y;
float z;
int x1;
};
struct derived2
{
int type;
float x;
float y;
float z;
char x2;
};
struct derived3
{
int type;
float x;
float y;
float z;
float x3;
};
union ThreeDCartesianData {
struct common c;
struct derived1 d1;
struct derived2 d2;
struct derived3 d3;
};
And use them like this:
union ThreeDCartesianData data1;
data1.c.type=DERIVED1;
data1.d1.x=0;
data1.d1.y=0;
data1.d1.z=0;
data1.d1.x1 = 4;
If all the structs in a union have an initial list elements of the same type in the same order, the standard allows you to access those fields from any of the sub-structs safely.
What about using typedefs?
typedef struct general3d {
float x;
float y;
float z;
} general3d_t;
typedef general3d position;
typedef general3d velocity;
This way, when you come across something that's a velocity type, you encode that into the variable type, but under the hood, it's still just 3 points, x, y, z. Then, readers of the code will know you're talking about a velocity and not a position. If you want to get really crazy with it, you hide general3d away in some implementation file, so a user can never instantiate a general3d on their own, since they should be using either position or velocity as the situation requires; this may or may not be reasonable for your task at hand/worth the extra effort.
EDIT: I'm not positive about variable-renaming or about adding more variables directly to the same struct, but I would start to head in the direction of a different design at that point.
On the one hand, if you have two structs that have the same underlying types but require different names, you probably just have two separate structs. For example:
struct point3d {
float x;
float y;
float z;
};
struct person {
float age;
float weight;
float salary;
};
Yes, those are both 3 floats, but their understanding is very different, and they should be able to vary on their own if one or the other changes. Perhaps I want to add a name field to the person, but there's no reasonable analogue for a char * on point3d. Just define them separately if they mean different things.
As for adding more variables, that sounds like structs that contain other structs:
struct point3d {
float x;
float y;
float z;
};
struct person {
point3d position;
float age;
float weight;
float salary;
};
// access like:
person.position.x;
I've done this sort of thing before. I embed a copy of the base type at the front of the derived type struct. This more closely mimics what c++ might do. Here are two methods I've used.
Using simple type:
#define XYZDEF \
int type; \
float x; \
float y; \
float z
// base type
struct xyzdata {
XYZDEF;
};
// derived type 1
struct vector {
XYZDEF;
int vector_info;
...
};
// derived type 2
struct position {
XYZDEF;
int position_info;
...
};
#define BASEOF(_ptr) \
((struct xyzdata *) (_ptr))
// vector_rotate -- rotate a vector
void
vector_rotate(vector *ptr)
{
}
// position_rotate -- rotate a position
void
position_rotate(position *ptr)
{
}
// xyzrotate -- rotate
void
xyzrotate(xyzdata *ptr)
{
switch (ptr->type) {
case TYPE_POSITION:
vector_rotate((vector *) ptr);
break;
case TYPE_VECTOR:
position_rotate((position *) ptr);
break;
}
}
Using a virtual function table pointer:
#define XYZDEF \
int type; \
vtbl *vtbl; \
float x; \
float y; \
float z
// forward definitions
struct xyzdata;
struct vector;
struct position;
// virtual function table
struct vtbl {
void (*rotate)(struct xyzdata *);
};
// base type
struct xyzdata {
XYZDEF;
};
// derived type 1
struct vector {
XYZDEF;
int vector_info;
...
};
// derived type 2
struct position {
XYZDEF;
int position_info;
...
};
#define BASEOF(_ptr) \
((struct xyzdata *) (_ptr))
// vector_rotate -- rotate a vector
void
vector_rotate(struct xyzdata *ptr)
{
struct vector *vec = (void *) ptr;
...
}
// position_rotate -- rotate a position
void
position_rotate(struct xyzdata *ptr)
{
struct position *pos = (void *) ptr;
...
}
// xyzrotate -- rotate
void
xyzrotate(xyzdata *ptr)
{
ptr->vtbl->rotate(ptr);
}

Assignment to pointer to structure from pointer within a different structure type

I am currently trying to assign a pointer to a structure called totheright (which is a linked list node). The pointer to the structure/list is currently within another structure called rectangles. I am encountering an error when I attempt to do so.
currect->right = malloc(sizeof(totheright));
righthead = current->right;
The following are the declarations in function:
rect *currect = NULL;
totheright *righthead = NULL;
Structure definitions in header:
typedef struct _totheright {
int rect;
struct _totheright *right;
} totheright;
typedef struct _rect {
int thisrect;
struct totheright *right;
int left;
double width;
double height;
double xcord;
double ycord;
struct _rect *next;
} rect;
Field right in structure rect should not have struct before totheright or struct _totheright should be used:
typedef struct _rect {
int thisrect;
//struct totheright *right; // was
totheright *right; // fixed
//struct _totheright *right; // that would be ok as well
int left;
double width;
double height;
double xcord;
double ycord;
struct _rect *next;
} rect;

Resources