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.
Related
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));
}
I have a c struct that has a const variable.
typedef struct {
u32 status;
const u32 dir_search_idx;} FS_OBJ;
What I would like to do is init the const variable in a function once I have created the struct object. I guess I want to do something similar to what a constructor would do in c++. Is it possible to do something similar in c? Thanks
This should work perfectly fine if you are using C99 or newer and want to initialize the const variable when creating the struct:
FS_OBJ obj = { .status = /* something */, .dir_seach_idx = /* something */ };
You can't modify the const variable after creating the struct. Then you would have to remove the const keyword as mentioned by user3386109 in the comments.
I think const is not the right tool for what you are looking for. You can put data (structs) and behavior (functions) in a *.c file and provide public functions in the corresponding header file. This way you can mimic the equivalent c++ code that you want and hide the data and of course, you can define a constructor. A great book that might help is The GLib/GTK+ Development Platform. In chapter 3 you can find a good introduction to Semi-Object-Oriented Programming in C.
Here is a possible implementation, not necessarily the best one:
/src/main.c
#include <stdio.h>
#include "point.h"
int main()
{
Point *p1 = init(6, 7);
printf("%d\n", getX(p1));
printf("%d\n", getY(p1));
Point *p2 = init(12, 14);
printf("%d\n", getX(p2));
printf("%d\n", getY(p2));
setX(p2, 16);
printf("%d\n", getX(p2));
setY(p2, 16); /* error; we want y to initialize once and remain constant. Also accessing y with p2->y is an error too. */
printf("%d\n", getY(p2)); /* getY is ok */
freep(p1);
freep(p2);
}
/src/point.h
typedef struct _Point Point;
Point *init(int, int);
int getX(Point *);
void setX(Point *, int);
int getY(Point *);
void freep(Point *);
/src/point.c
#include <stdlib.h>
#include "point.h"
struct _Point{
int x;
int y;
};
Point *init(int x, int y)
{
Point *temp;
temp = malloc(sizeof(Point));
temp->x = x;
temp->y = y;
return temp;
}
int getX(Point *p)
{
return p->x;
}
void setX(Point *p, int x)
{
p->x = x;
}
int getY(Point *p)
{
return p->y;
}
void freep(Point *p)
{
free(p);
}
Furthermore, if we need a private method in our class, we do not provide a declaration of it in the header and also we use static to restrict its access within the class's file.
is there a more compact way for using function pointers inside a struct ?
Do I really need to type defining the function pointer? I tried without but received type errors. Are there any hazards, or anything that I've done that is against good code practice?
#include <stdio.h>
#include <math.h>
void lineFunc(int* a)
{
int x1 = a[0];
int y1 = a[1];
int x2 = a[2];
int y2 = a[3];
double length = sqrtf( pow( (x1-x2),2 )+ pow((y1-y2),2) );
printf("%f\n", length);
}
void areaFunc(int* a)
{
int base = a[0];
int height = a[1];
int area = base*height;
printf("%d",area);
}
typedef void (*Operation)(int* a );
typedef struct CALC_TYPE
{
Operation opt
} CALC;
int main()
{
int lineArg[4] = {1 , 2, 3, 4}; //x1, y1, x2, y2
int areaArg[2] = {5,10}; // base, height
void (*lineCalc)(int*);
void (*areaCalc)(int*);
lineCalc = lineFunc;
areaCalc = areaFunc;
CALC line;
CALC area;
CALC* cmdArray = calloc(2,sizeof(CALC));
line.opt = lineFunc;
area.opt = areaFunc;
cmdArray[0]=line;
cmdArray[1]=area;
cmdArray[0].opt(lineArg);
cmdArray[1].opt(areaArg);
return 0;
}
is there a more compact way for using function pointers inside a struct ?
No.
Do I really need to type defining the function pointer?
No, but it makes your code much more readable because the notation for function pointers is arcane. You could have instead written.
typedef struct CALC_TYPE
{
void (*opt) (int*);
} CALC;
Are there any hazards, or anything that I've done that is against good code practice?
Not really. Making a struct that only contains 1 thing is questionable, but it's obviously a learning exercise.
The typedef Operation and some variables are useless. The struct too but If I've understood you, you want to keep it. So here is a more compacte way:
#include <stdio.h>
#include <math.h>
#include <stdlib.h> // calloc
void lineFunc(int* a)
{
// ...
}
void areaFunc(int* a)
{
// ...
}
typedef struct CALC_TYPE
{
void (*opt)(int *a);
} CALC;
int main()
{
int lineArg[4] = {1 , 2, 3, 4}; //x1, y1, x2, y2
int areaArg[2] = {5,10}; // base, height
CALC *cmdArray = calloc(2, sizeof(CALC));
cmdArray[0].opt = lineFunc;
cmdArray[1].opt = areaFunc;
cmdArray[0].opt(lineArg);
cmdArray[1].opt(areaArg);
free(cmdArray); // 1 malloc/calloc => 1 free
return 0;
}
EDIT:
Are there any hazards, or anything that I've done that is against good
code practice?
Include stdlib.h to use calloc
Don't forget to free dynamically allocated memory
Why pow then sqrtf then store in double ? Use sqrt instead
You could avoid the use of a struct here
One additional point that I did not see in the other answers concerns a benefit of struct usage: function prototype stability. Even if a struct starts out with a single variable, future requirements for the struct may force more variables to be added. Because of the way struct variables are passed as arguments, prototype's of functions written to use the original single single variable struct, will not be broken when additional variables are added.
For example, your struct can be defined as:
typedef struct CALC_TYPE
{
Operation opt
} CALC;
Or:
typedef struct CALC_TYPE
{
Operation opt
int a;
float b;
} CALC;
Without forcing change to a function that calls it.:
void func(CALC *c)
{
...
}
It's a great way to allow changes to the number of items that need to be passed as data without changing the argument list.
Using a modification of your area function, consider the following struct that was initially designed to support area measurements:
typedef struct
{
int length;
int width;
}DIM;
int areaFunc(DIM *d)
{
return d->length*d->width*d
}
Later a requirement for the struct to support volume forces the addition of a variable:
typedef struct
{
int length;
int width;
int height;
}DIM;
Adding the new variable to the struct does not break the existing areaFunc(), but also supports the new function:
int volumeFunc(DIM *d)
{
return d->length*d->width*d->height;
}
I try to write a function, that finds void pointers in a data structure. The function has to cast the void* to any kind of struct.
Let's say I write a struct, which I store in my data sturcture in form of a void pointer. Then I calls the function, which prints information of all stored data elements.
To do that the function has to know to which type it should cast.
So my question is: Is it possible to give the function the informations it needs in form of a parameter somehow?
example code:
typedef struct{
int a, b
} teststruct;
void DSOut(datastructure* ds, datatypeinfo dt){
//...
//search for data in ds
//...
//if data is found cast it to the type defined in dt
//and print out the a and b fields
}
int main(){
datastructure* ds = DSCreate(4, 3); //can hold any type of data,
//but should hold just one at a time
//4 and 3 are just example parameters
teststruct ts;
ts.a = 4;
ts.b = 10;
teststruct ts2;
ts2.a = 6;
ts2.b = 12;
//Add the teststructs to the data-structure
DSAdd(2, 2, ts); //the numbers are just for example
DSAdd(4, 1, ts2);
datatypeinfo dt = teststruct; //stores the type teststruct for DSOut
DSOut(ds, dt); //function, that prints information of all added teststructs
return 0;
}
in this example DSOut(x,y) should print the following:
- on position 2, 2 is an element which holds following data: 4, 10.
- on position 4, 1 is an element which holds following data: 6, 12.
Do you think this is possible ?
Types cannot be passed as parameters in C, so the short answer to your question is "no, it cannot be done", at least not in the general case. You could pass something that would allow you to identify one of a limited set of types, and then hard-code how to handle each of those types (I'm thinking of a big switch statement). Since you don't specify what datatypeinfo looks like, it isn't clear how general you expect it to be.
I can think of adding a type identifier field to your struct and check it's value to decide how to print it, and initialize the structs with functions to take care of the type field
enum Types {
Point3D,
Point2D
};
struct Base {
enum Types type;
};
struct Point3D {
enum Types type;
int x;
int y;
int z;
};
struct Point2D {
enum Types type;
int u;
int v;
};
void print(void *data)
{
switch (((struct Base *)data)->type)
{
case Point2D:
{
struct Point2D *point;
point = (struct Point2D *)data;
printf("2D: %d, %d\n", point->u, point->v);
}
break;
case Point3D:
{
struct Point3D *point;
point = (struct Point3D *)data;
printf("3D: %d, %d, %d\n", point->x, point->y, point->z);
}
break;
}
}
void initialized2dPoint(struct Point2D *const point, int u, int v)
{
if (point == NULL)
return;
point->type = Point2D;
point->u = u;
point->v = v;
}
void initialized3dPoint(struct Point3D *const point, int x, int y, int z)
{
if (point == NULL)
return;
point->type = Point3D;
point->x = x;
point->y = y;
point->z = z;
}
int main(void)
{
struct Point2D point2d;
struct Point3D point3d;
initialized2dPoint(&point2d, 1, 2);
initialized3dPoint(&point3d, 3, 4, 5);
print(&point2d);
print(&point3d);
return 0;
}
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