Best way to store different structs in same array in c - arrays

If I have multiple structs which have a common method like this:
typedef struct s sphere;
typedef struct s{
point3 center;
double radius;
bool (*hit)(sphere, const ray*, double, double, hit_record*);
} sphere;
typedef struct b box;
typedef struct b{
point3 center;
double radius;
bool (*hit)(box, const ray*, double, double, hit_record*);
} box;
Is it possible for me to create some type of array such that it can store both of these structs and loop through it calling the method like this:
objects shapes[50]; // Where objects is something that can let shapes hold both structs
//Pretend shapes has a mixture of Boxes and Spheres
int number_of_shapes = 20;
for (int i = 0; i < number_of_shapes;i++){
if shapes[i].hit(shapes[i], r, t, t, red) { //random variables
;// do something
}
}
I just started learning c yesterday so I am not really sure what to do. I tried using void pointers but that also failed miserably.

Void pointers are the right way to do that, but it requires that your objects are persistent in memory, because an array of pointers won't retain them. I give you an example :
EDIT : I update the example to do the job using function pointers and simulate the behavior of methods.
#include <stdio.h>
#include <stdlib.h>
// Type your code here, or load an example.
enum { TypeSphere, TypeBox };
typedef struct s sphere;
typedef struct b box;
typedef char (*hit)(void *object, void *ray, double x, double y, void*hit_record);
// Starts both structure with a common function pointer type
typedef struct s{
hit method;
double center;
double radius;
} sphere;
typedef struct b{
hit method;
double center;
double radius;
} box;
// Implementation of a method for each type
char sphereMethod(void *s, void *ray, double x, double y, void *hit_record) {
printf("A sphere\n");
}
char boxMethod(void *b, void *ray, double x, double y, void *hit_record) {
printf("A box\n");
}
int main() {
void* objects[50];
// Allocates 25 objects of each type for the example
for(int i=0; i<50; i+=2) {
objects[i] = malloc(sizeof(sphere));
// Sets the implementation here
((sphere *)objects[i])->method = sphereMethod;
objects[i+1] = malloc(sizeof(box));
((box *)objects[i+1])->method = boxMethod;
}
// Loops through objects and calls the methods
for(int i=0; i<50; i++) {
hit method = *((hit *)objects[i]);
method(objects[i], NULL, 0, 0, NULL);
}
// Frees them
for(int i=0; i<50; i++) { free(objects[i]); }
}

Here is a rough cut of how you might achieve your objective...
enum { BOX, SPHERE } types;
typedef struct sphere {
point3 center;
double radius;
} sphere_t;
typedef struct box {
point3 center;
double len, wid, dpth;
double rotX, rotY, rotZ;
} box_t;
typedef object {
int type;
union {
sphere_t sphere;
box_t box;
};
} object_t;
int main() {
object_t objs[ 50 ];
/* ... */
for( int i = 0; i < numObjs; i++ )
switch( objs[ i ].type ) {
case BOX:
hndlr_Box( objs[i].box );
break;
case SPHERE:
hndlr_Sphere( objs[i].sphere );
break;
/* ... */
}
}
Looking back at that, it might be even better to use a linked list of objects instead of an array.
AND, each object instance in the array will consume as much memory as is required for the largest of the union. It may be better to use pointers to separately allocated blocks, each storing only its particular attributes.

If you create a sufficiently complicated enough object, you should be able to accomplish something pretty close to your goal. Below, I sketch out a solution that you should be able to build upon.
First, we define a Shape as having a ShapeInterface, which for now is just something that can be hit.
typedef struct HitRecord HitRecord;
typedef struct Ray Ray;
typedef struct Shape {
const struct ShapeInterface * const vtable;
} Shape;
struct ShapeInterface {
bool (*hit)(Shape *, const Ray *, double, double, HitRecord *);
void (*dump)(Shape *);
};
bool shape_hit (Shape *s, const Ray *r, double x, double y, HitRecord *hr) {
return s->vtable->hit(s, r, x, y, hr);
}
void shape_dump (Shape *s) {
s->vtable->dump(s);
}
Then, we define Sphere and Box to be kinds of Shape.
typedef struct Point3 {
double p[3];
} Point3;
typedef struct Sphere {
Shape base;
Point3 center;
double radius;
bool popped;
} Sphere;
typedef struct Box {
Shape base;
Point3 center;
double radius;
bool crushed;
} Box;
Now, define Objects to be a union of these different kinds of Shape. We note that all items in Objects have a common initial sequence, which is Shape.
typedef union Objects {
Shape shape;
Sphere sphere;
Box box;
} Objects;
When you have an array of Objects, you can loop through and call shape_hit on the shape member.
void process_hit_objects (
Objects shapes[],
int number_of_shapes,
const Ray *r, double x, double y, HitRecord *hr) {
for (int i = 0; i < number_of_shapes; ++i) {
if (shape_hit(&shapes[i].shape, r, x, y, hr)) {
/* ... do something ... */
shape_dump(&shapes[i].shape);
}
}
}
When creating a Sphere, it needs to initialize its base member with an appropriate implementations for the functions in its vtable.
static bool sphere_hit (
Shape *shape, const Ray *r, double x, double y, HitRecord *hr) {
Sphere *sphere = (void *)shape;
return sphere->popped;
}
static void sphere_dump (Shape *shape) {
Sphere *sphere = (void *)shape;
double *p = sphere->center.p;
printf("sphere: %p # <%f,%f,%f> |%f|\n",
(void *)sphere, p[0], p[1], p[2], sphere->radius);
}
void makeSphere (Sphere *s, Point3 center, double radius) {
static const struct ShapeInterface vtable = {
sphere_hit, sphere_dump
};
Shape base = { &vtable };
Sphere sphere = { base, center, radius, true };
memcpy(s, &sphere, sizeof(sphere));
}
Similarly for a Box.
static bool box_hit (
Shape *shape, const Ray *r, double x, double y, HitRecord *hr) {
Box *box = (void *)shape;
return box->crushed;
}
static void box_dump (Shape *shape) {
Box *box = (void *)shape;
double *p = box->center.p;
printf("box: %p # <%f,%f,%f> |%f|\n",
(void *)box, p[0], p[1], p[2], box->radius);
}
void makeBox (Box *b, Point3 center, double radius) {
static const struct ShapeInterface vtable = {
box_hit, box_dump
};
Shape base = { &vtable };
Box box = { base, center, radius, true };
memcpy(b, &box, sizeof(box));
}

Related

Emulating Classes in C using Structs

I am constrained to using C for a competition and I have a need to emulate classes. I am trying to construct a simple "point" class that can return and set the X and Y coordinates of a point. Yet, the below code returns errors such as "unknown type name point", "expected identifier or (" and "expected parameter declarator." What do these errors mean? How do I correct them? Is this the correct approach to writing a "pseudo-class"?
typedef struct object object, *setCoordinates;
struct object {
float x, y;
void (*setCoordinates)(object *self, float x, float y);
void (*getYCoordinate)(object *self);
void (*getXCoordinate)(object *self);
};
void object_setCoordinates(object *self, float x, float y){
self->x = x;
self->y = y;
}
float object_getXCoordinate(object *self){
return self->x;
}
float object_getYCoordinate(object *self){
return self->y;
}
object point;
point.setCoordinates = object_setCoordinates;
point.getYCoordinate = object_getYCoordinate;
point.getXCoordinate = object_getXCoordinate;
point.setCoordinates(&point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f", point.getXCoordinate, point.getYCoordinate);
Reference:
1. C - function inside struct
2. How do you implement a class in C?
You would do much better to implement it as follows:
#include <stdio.h>
struct point {
float x;
float y;
};
void point_setCoordinates(struct point *self, float x, float y){
self->x = x;
self->y = y;
}
float point_getXCoordinate(struct point *self){
return self->x;
}
float point_getYCoordinate(struct point *self){
return self->y;
}
int main(void) {
struct point my_point;
point_setCoordinates(&my_point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f\n",
point_getXCoordinate(&my_point),
point_getYCoordinate(&my_point));
return 0;
}
A few things to note:
As #Olaf has pointed out, never typedef a pointer - it hides your intent and makes things unclear. Yes, it's all over poor APIs (e.g: Windows), but it reduces readability.
You really don't need these functions to be the equivalent to virtual functions... just have a set of point_*() functions that you call on the point 'thing'.
Don't confuse things with poor names... if it's an X,Y point, then call it such - not an object (which is a very generic concept).
You need to call functions... in your call to printf() you used point.getXCoordinate - that is to say you took it's address and asked printf() to display it as though it were a float
You might start to wonder why you'd care about calling a function to get access to a variable that is inside a transparent struct... See below.
Many libraries / APIs provide opaque datatypes. This means that you can get a 'handle' to a 'thing'... but you have no idea what's being stored within the 'thing'. The library then provides you with access functions, as shown below. This is how I'd advise you approach the situation.
Don't forget to free the memory!
I've implemented an example below.
point.h
#ifndef POINT_H
#define POINT_H
struct point;
struct point *point_alloc(void);
void point_free(struct point *self);
void point_setCoordinates(struct point *self, float x, float y);
float point_getXCoordinate(struct point *self);
float point_getYCoordinate(struct point *self);
#endif /* POINT_H */
point.c
#include <stdlib.h>
#include <string.h>
#include "point.h"
struct point {
float x;
float y;
};
struct point *point_alloc(void) {
struct point *point;
point = malloc(sizeof(*point));
if (point == NULL) {
return NULL;
}
memset(point, 0, sizeof(*point));
return point;
}
void point_setCoordinates(struct point *self, float x, float y) {
self->x = x;
self->y = y;
}
float point_getXCoordinate(struct point *self) {
return self->x;
}
float point_getYCoordinate(struct point *self) {
return self->y;
}
void point_free(struct point *self) {
free(self);
}
main.c
#include <stdio.h>
#include "point.h"
int main(void) {
struct point *point;
point = point_alloc();
point_setCoordinates(point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f\n",
point_getXCoordinate(point),
point_getYCoordinate(point));
point_free(point);
return 0;
}
Your code has some minor errors. That's why it doesn't compile.
Fixed here:
typedef struct object object;
struct object {
float x, y;
void (*setCoordinates)(object *self, float x, float y);
float (*getYCoordinate)(object *self);
float (*getXCoordinate)(object *self);
};
void object_setCoordinates(object *self, float x, float y){
self->x = x;
self->y = y;
}
float object_getXCoordinate(object *self){
return self->x;
}
float object_getYCoordinate(object *self){
return self->y;
}
int main()
{
object point;
point.setCoordinates = object_setCoordinates;
point.getYCoordinate = object_getYCoordinate;
point.getXCoordinate = object_getXCoordinate;
point.setCoordinates(&point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f",
point.getXCoordinate(&point), point.getYCoordinate(&point));
}
As for the approach, there's probably no need to store the pointers to your methods inside the struct when you can simply call them directly:
object x;
object_setCoordinates(x, 1, 2);
//...
I also have an example of basic class emulation in C [the OP specified for a specific application, although, this answer is to the general question]:
A header file called "c_class.h"
#ifndef CLASS_HEADER_H
#define CLASS_HEADER_H
// Function pointer prototypes used by these classes
typedef int sub_func_t (int);
typedef float sub_funcf_t (int,int);
/* class type definition
(emulated class type definition; C doesn't really have class types) */
typedef struct {
//Data Variables
int a;
/*Function (also known as Method) pointers
(note that different functions have the same function pointer prototype)*/
sub_func_t* add;
sub_func_t* subt;
sub_func_t* mult;
sub_funcf_t* div;
} class_name;
// class init prototypes
// These inits connect the function pointers to specific functions
// and initialize the variables.
class_name* class_init_ptr (int, sub_func_t*, sub_func_t*, sub_func_t*, sub_funcf_t*);
class_name class_init (int, sub_func_t*, sub_func_t*, sub_func_t*, sub_funcf_t*);
#endif
A source code file called "c_class.c"
//gcc -o c_class c_class.c
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"c_class.h"
// The class function definitions.
/*
If we make these member functions static then they are only
accessible via code from this file.
However, we can still pass the class-like objects around a
larger program and access their member functions,
just like in any OO language.
It is possible to emulate inheritance by declaring a class object
from the class type definition (I don't touch on these more
abstract subjects though, this is only a basic class emulation).
*/
static int AddFunc(int num){
num++;
return num;
}
static int SubtFunc(int num){
num--;
return num;
}
static int MultFunc(int num){
num *= num;
return num;
}
static float DivFunc(int num, int denom){
float fnum = (float)num / (float)denom;
return fnum;
}
// The class init function definitions.
class_name* class_init_ptr (int num, sub_func_t* addition, sub_func_t* subtraction, sub_func_t* multiplication, sub_funcf_t* division)
{
class_name* new_class = malloc(sizeof(*new_class));
assert(new_class != NULL);
*new_class = (class_name){num, addition, subtraction, multiplication, division};
/*We could also just type:
new_class->a = num;
new_class->add = addition;
new_class->subt = subtraction;
new_class->mult = multiplication;
new_class->div = division;
*/
return new_class;
}
class_name class_init(int num, sub_func_t* addition, sub_func_t* subtraction, sub_func_t* multiplication, sub_funcf_t* division)
{
class_name new_class;
new_class = (class_name){num, addition, subtraction, multiplication, division};
/* We could also just type:
new_class.a = num;
new_class.add = addition;
new_class.subt = subtraction;
new_class.mult = multiplication;
new_class.div = division;
*/
return new_class;
}
//Working Function Prototypes
class_name* Working_Function(class_name*);
class_name Working_Function_Two(class_name);
int main(){
/* It's possible to connect the functions within the init also,
w/o sending them. */
class_name *MyClass = class_init_ptr(5, AddFunc, SubtFunc, MultFunc, DivFunc);
class_name MyOtherClass = class_init(0, AddFunc, SubtFunc, MultFunc, DivFunc);
printf("%i\n",MyClass->add(100));// 101
printf("%i\n",MyClass->subt(100));// 99
printf("%i\n",MyClass->mult(100));// 10000
printf("%f\n",MyClass->div(MyClass->a,2)); // 2.5
printf("%i\n",MyClass->mult(MyClass->mult(100))); //100000000
MyClass = Working_Function(MyClass);
//This would work also (because we're passing a pointer):
//Working_Function(MyClass);
printf("%i\n",MyClass->a); //a = 5000
MyOtherClass = Working_Function_Two(MyOtherClass);
printf("%i\n",MyOtherClass.a); //a = 9999
MyOtherClass.a = 25;
Working_Function_Two(MyOtherClass); //pass by value
printf("%i\n",MyOtherClass.a); //a = 25 (no value change)
Working_Function(&MyOtherClass); //pass by reference
printf("%i\n",MyOtherClass.a); //a = 5000 (value changed)
return 0;
}
//Working Functions
class_name* Working_Function(class_name* PassedClass){
printf("%i\n",PassedClass->a);// 5, then 25
printf("%i\n",PassedClass->add(PassedClass->a));// 6, then 26
PassedClass->a = 5000;
return PassedClass;
}
class_name Working_Function_Two(class_name PassedClass){
printf("%i\n",PassedClass.a);// 0, then 25
printf("%i\n",PassedClass.add(PassedClass.a));// 1, then 26
PassedClass.a = 9999;
return PassedClass;
}
/* We're passing emulated class objects and emulated class pointers
by reference and value, if everything works it should print this:
101
99
10000
2.500000
100000000
5
6
5000
0
1
9999
25
26
25
25
26
5000
*/
Another way to write a pseudo-class that needs polymorphism, with less overhead per instance, is to create a single virtual function table and have your constructor or factory function set that. Here’s a hypothetical example. (Edit: Now a MCVE, but for real code, refactor into header and separate source files.)
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct point; // Abstract base class.
struct point_vtable {
void (*setCoordinates)(struct point *self, float x, float y);
float (*getYCoordinate)(const struct point *self);
float (*getXCoordinate)(const struct point *self);
};
typedef struct point {
const struct point_vtable* vtable;
} point;
typedef struct cartesian_point {
const struct point_vtable* vtable;
float x;
float y;
} cartesian_point;
typedef struct polar_point {
const struct point_vtable* vtable;
float r;
float theta;
} polar_point;
void cartesian_setCoordinates( struct point* self, float x, float y );
float cartesian_getXCoordinate(const struct point* self);
float cartesian_getYCoordinate(const struct point* self);
void polar_setCoordinates( struct point* self, float x, float y );
float polar_getXCoordinate(const struct point* self);
float polar_getYCoordinate(const struct point* self);
const struct point_vtable cartesian_vtable = {
.setCoordinates = &cartesian_setCoordinates,
.getXCoordinate = &cartesian_getXCoordinate,
.getYCoordinate = &cartesian_getYCoordinate
};
const struct point_vtable polar_vtable = {
.setCoordinates = &polar_setCoordinates,
.getXCoordinate = &polar_getXCoordinate,
.getYCoordinate = &polar_getYCoordinate
};
void cartesian_setCoordinates( struct point* const self,
const float x,
const float y )
{
assert(self->vtable == &cartesian_vtable);
struct cartesian_point * const this = (struct cartesian_point*)self;
this->x = x;
this->y = y;
}
float cartesian_getXCoordinate(const struct point* const self)
{
assert(self->vtable == &cartesian_vtable);
const struct cartesian_point * const this = (struct cartesian_point*)self;
return this->x;
}
float cartesian_getYCoordinate(const struct point* const self)
{
assert(self->vtable == &cartesian_vtable);
const struct cartesian_point * const this = (struct cartesian_point*)self;
return this->y;
}
void polar_setCoordinates( struct point* const self,
const float x,
const float y )
{
assert(self->vtable == &polar_vtable);
struct polar_point * const this = (struct polar_point*)self;
this->theta = (float)atan2((double)y, (double)x);
this->r = (float)sqrt((double)x*x + (double)y*y);
}
float polar_getXCoordinate(const struct point* const self)
{
assert(self->vtable == &polar_vtable);
const struct polar_point * const this = (struct polar_point*)self;
return (float)((double)this->r * cos((double)this->theta));
}
float polar_getYCoordinate(const struct point* const self)
{
assert(self->vtable == &polar_vtable);
const struct polar_point * const this = (struct polar_point*)self;
return (float)((double)this->r * sin((double)this->theta));
}
// Suitable for the right-hand side of initializations, before the semicolon.
#define CARTESIAN_POINT_INITIALIZER { .vtable = &cartesian_vtable,\
.x = 0.0F, .y = 0.0F }
#define POLAR_POINT_INITIALIZER { .vtable = &polar_vtable,\
.r = 0.0F, .theta = 0.0F }
int main(void)
{
polar_point another_point = POLAR_POINT_INITIALIZER;
point* const p = (point*)&another_point; // Base class pointer.
polar_setCoordinates( p, 0.5F, 0.5F ); // Static binding.
const float x = p->vtable->getXCoordinate(p); // Dynamic binding.
const float y = p->vtable->getYCoordinate(p); // Dynamic binding.
printf( "(%f, %f)\n", x, y );
return EXIT_SUCCESS;
}
This takes advantage of the guarantee that the common initial subsequence of structs can be addressed through a pointer to any of them, and stores only one pointer of class overhead per instance, not one function pointer per virtual function. You can use the virtual table as your class identifier for your variant structure. Also, the virtual table cannot contain garbage. Virtual function calls need to dereference two pointers rather than one, but the virtual table of any class in use is highly likely to be in the cache.
I also note that this interface is very skeletal; it’s silly to have a polar class that can do nothing but convert back to Cartesian coordinates, and any implementation like this would at minimum need some way to initialize dynamic memory.
If you don’t need polymorphism, see Attie’s much simpler answer.

function pointer and function is incompatible because of arguments

I have read the book Understanding and Using C Pointers and try to compile the code below. But after compiling I got the warning: assignment from incompatible pointer type.
I have checked the code and find out the function pointer fptrSet and function ShapeSetX is incompatible because the first argument of fptrSet is void * and function ShapeSetX is Shape *.
How can I fix this?
Thanks!
typedef void (*fptrSet)(void*, int);
typedef int (*fptrGet)(void*);
typedef void (*fptrDisplay)();
typedef struct _vfunc
{
fptrSet setX;
fptrGet getX;
fptrSet setY;
fptrGet getY;
fptrDisplay display;
} vFunc;
typedef struct _shape
{
vFunc function;
int x;
int y;
} Shape;
void displayShape(){
printf("Shape\n");
}
void ShapeSetX(Shape *shape, int x){
shape->x = x;
}
void ShapeSetY(Shape *shape, int y){
shape->y = y;
}
int ShapeGetX(Shape *shape){
return shape->x;
}
int ShapeGetY(Shape *shape){
return shape->y;
}
Shape *newShape()
{
Shape *shape = (Shape *)malloc(sizeof(Shape));
shape->x = 10;
shape->y = 10;
shape->function.setX = ShapeSetX;
shape->function.getX = ShapeGetX;
shape->function.setY = ShapeSetY;
shape->function.getY = ShapeGetY;
shape->function.display = displayShape;
return shape;
}
You have to respect pointer definition: pointer need that first parameter is a pointer to void, so your function implementation should have first parameter as void:
void ShapeSetX(void *void_shape, int x){
Shape *shape = (Shape*) void_shape;
shape->x = x;
}
void ShapeSetY(void *void_shape, int y){
Shape *shape = (Shape*) void_shape;
shape->y = y;
}
int ShapeGetX(void *void_shape){
Shape *shape = (Shape*) void_shape;
return shape->x;
}
int ShapeGetY(void *void_shape){
Shape *shape = (Shape*) void_shape;
return shape->y;
}
I was going to say "Why don't you replace void with Shape then?", until I realised that Shape hadn't been defined yet - nor could you swap the two definitions, because Shape needs vFunc which needs the typedefs.
So, do this:
typedef struct _shape Shape; // Define _shape and Shape later
typedef void (*fptrSet)(Shape*, int);
typedef int (*fptrGet)(Shape*);
typedef void (*fptrDisplay)();
If your compiler doesn't like that, you may need to change it to:
typedef struct _shape; // Define _shape later
typedef void (*fptrSet)(struct _shape*, int);
typedef int (*fptrGet)(struct _shape*);
typedef void (*fptrDisplay)();

Declaring struct attribute with different type

I have a struct that contain an attribute that can take many types,
I want ask about the most appropriate way to declare this attribute.
Example:
struct
{
void* pShape; //poiter to the shape that will be casted on *tCircle or *tRectangle
int type;//type of the shape
int h;
int l;
}tImage;
struct{
int size;
int r;
HANDLE calcul;
}tCircle
struct{
int size;
int x;
int y;
HANDLE calcul;
}tRectangle;
As you see here i'am using void* to declare a pointer to the shape and use type attribute to guess the type of the shape.
this is my function for the calcuation of the size of the shape in an image
int Image_Get_ShapeSize(tImage Im)
{
switch (Im.type)
{
case CIRCLE:
((tCircle*)(Im.shape))->calcul();
break;
case RECTANGLE:
((tRectangle*)(Im.shape))->calcul();
break;
default:
break;
}
}
what do you think about this is it a good method ?
I do not understand well why you need the tCircle and tRectangle structures because they have the same fields. I suggest you use only one definition and initialize the function pointer to a different and specific method.
struct shape {
int size;
int x;
int y;
void (*calcul) (struct shape * shape);
};
And then the specific functions:
void circle_calcul(struct shape * shape)
{
...
}
void rectangle_calcul(struct shape * shape)
{
...
}
And finally:
struct shape circle;
struct shape rectangle;
circle.calcul = circle_calcul;
rectangle.calcul = rectangle_calcul;

Need help passing a Struct to a function locally in C

am building a simple program dealing with structs. The logic is simple enough but for some reason I can't quite figure out how to pass the struct to a function. I declared the struct in my main(). I got the impression from searching the site that the only way to do this is to create a header file and declare that way. Is this true?
main() {
struct Rect {
double x;
double y;
char color;
double width;
double height;
};
struct Rect a, b, *rec;
and this is where I am trying to pass it:
int chk_overlap(struct Rect *r1, struct Rect *r2) {
if(((r1->x + r1->width) >= r2->x) && ((r1->y) >= (r1->y - r2->height))){
return 1;
} else {
return 0;
}
}
This is just one iteration of my attempt, when I pass it like this, I get a dereferencing to incomplete pointer error. I have also tried declaring it as
typedef struct Rect {
double x;
double y;
char color;
double width;
double height;
} Rect;
Rect a, b, *rec;
passing it as
int chk_overlap(Rect *r1, Rect *r2) {
EDIT: This is where I am actually using the function
int check = 0;
check = check + chk_overlap(&a, &b);
You should declare the structure before the main.
struct Rect {
double x;
double y;
char color;
double width;
double height;
}
/* Place here the function definitions */
int main (int argc, char *argv[]) {
struct Rect a, b, *rec;
...
}
/* place here the function code */
Since you're declaring it inside the main() it's not seen outside, so functions don't recognise it.
Other than that, the way you're calling the function (function(&a, &b)) looks correct.

struct/union initialization confusion

I'm currently doing practice exams for a test I will have next monday and I came across something that confused me!
I have the following structs:
struct shape2d {
float x;
float y;
};
struct shape3d {
struct shape2d base;
float z;
};
struct shape {
int dimensions;
char *name;
union {
struct shape2d s1;
struct shape3d s2;
} description;
};
typedef struct shape Shape;
I have to make a function that 'creates' a shape with the following signature:
Shape *createShape3D(float x, float y, float z, char *name);
Because I'm dealing with an union of structs, I'm not quite sure how to initialize all the fields I need!
Here's what I have so far:
Shape *createShape3D(float x, float y, float z, char *name) {
Shape *s = (Shape *) malloc(sizeof(Shape));
s->dimensions = 3;
s->name = "Name...";
// How can I initialize s2?
return s;
}
Any help would be apprectiated!
First you need to strcpy name to s->name.
strcpy(s->name, "Name ...");
You can initialize s2 as
s->description.s2.z = 0;
s->description.s2.base.x = 0;
s->description.s2.base.y = 0;
You can read up more on unions in a book. You can also look here
http://c-faq.com/struct/union.html
http://c-faq.com/struct/initunion.html
http://c-faq.com/struct/taggedunion.html
You can do it like this:
s->description.s2.base.x=1;
s->description.s2.base.y=2;
s->description.s2.z=3;
As you can see, the syntax gets a little heavy at times, so it may make sense to define functions for accessing individual coordinates off a pointer to the structure:
float getX(Shape *s) {
if (dimensions == 2) {
return s->structure.s1.x;
} else {
return s->structure.s2.base.x;
}
}
void setX(Shape *s, float x) {
if (dimensions == 2) {
s->structure.s1.x = x;
} else {
s->structure.s2.base.x = x;
}
}
// Define similar functions for Y and Z
Now your initialization routine would change to more readable
setX(s, 1);
setY(s, 2);
setZ(s, 3);
Shape *createShape3D(float x, float y, float z, char *name) {
Shape *s = (Shape *) malloc(sizeof(Shape));
s->dimensions = 3;
s->name = malloc (strlen(name) + 1);
strcpy(s->name, name); // Copy the value of name
s->description.s2.base.x = x;
s->description.s2.base.y = y;
s->description.s2.z = z;
return s;
}
Also make sure to free up the memory for s->name before freeing up Shape* s

Resources