struct/union initialization confusion - c

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

Related

Best way to store different structs in same array in c

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

Why does my function not modify the value of variable in a struct in C?

This is my input. I must write a function, which give me minus Zesp.Im
struct Zesp { double Re;
double Im;
};
struct Zesp z1 = { .Re = 5.323 ,.Im= 3.321};
typedef struct Zesp zesp;
zesp spZ(zesp z)
{
z.Im = -(z.Im);
return z;
}
int main ()
{
spZ(z1);
printf("%.2f, %.2f\n", z1.Re, z1.Im);
return 0;
}
I don't know why I get 3.321 instead of -3.321?
I edit my program, my teacher said that I can't modify argument of a function spZ.
I get a segmentation fault
#include <stdio.h>
struct Zesp { double Re;
double Im;
};
struct Zesp z1 = { .Re = 5.323 ,.Im= 3.321};
typedef struct Zesp zesp;
zesp spZ(zesp z)
{
z.Im = -(z.Im);
z = spZ(z);
return z;
}
int main ()
{
spZ(z1);
printf("%.2f, %.2f\n", z1.Re, z1.Im);
return 0;
}
You're passing a copy of the structure to the function. It returns a copy, but you're not using the result.
You need to assign the result of the function to the variable.
z1 = spZ(z1);
The problem is that the copy of this struct is being modified.
In your code, this function returns the new instance of zest that should have this number inverted. So, you should save the result of this function call:
z1 = spZ(z1);
Or you can modify the argument itself, then you should pass it by pointer:
void spZ(zesp* z)
{
z->Im = -(z->Im);
}

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.

Casting void* to a variable data type in C

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

returning multiple values from a function [duplicate]

This question already has answers here:
How do I return multiple values from a function in C?
(8 answers)
Closed 3 years ago.
Can anyone tell me how to return multiple values from a function?
Please elaborate with some example?
Your choices here are to either return a struct with elements of your liking, or make the function to handle the arguments with pointers.
/* method 1 */
struct Bar{
int x;
int y;
};
struct Bar funct();
struct Bar funct(){
struct Bar result;
result.x = 1;
result.y = 2;
return result;
}
/* method 2 */
void funct2(int *x, int *y);
void funct2(int *x, int *y){
/* dereferencing and setting */
*x = 1;
*y = 2;
}
int main(int argc, char* argv[]) {
struct Bar dunno = funct();
int x,y;
funct2(&x, &y);
// dunno.x == x
// dunno.y == y
return 0;
}
You can't do that directly. Your options are to wrap multiple values into a struct, or to pass them in as pointer arguments to the function.
e.g.
typedef struct blah
{
int a;
float b;
} blah_t;
blah_t my_func()
{
blah_t blah;
blah.a = 1;
blah.b = 2.0f;
return blah;
}
or:
void my_func(int *p_a, float *p_b)
{
*p_a = 1;
*p_b = 2.0f;
}
First of all, take a step back and ask why you need to return multiple values. If those values aren't somehow related to each other (either functionally or operationally), then you need to stop and rethink what you're doing.
If the various data items are part of a larger, composite data type (such as a mailing address, or a line item in a sales order, or some other type described by multiple attributes), then define a struct type to represent a single value of that composite type:
struct addr { // struct type to represent mailing address
char *name;
int streetNumber;
char *streetName;
char *unitNumber;
char *city;
char state[3];
int ZIP;
};
struct addr getAddressFor(char *name) {...}
struct point2D {
int x;
int y;
};
struct polygon2D {
size_t numPoints;
struct point2D *points;
};
struct point2D getOrigin(struct polygon2D poly) {...}
Do not define a struct to collect random items that aren't somehow related to each other; that's just going to cause confusion for you and anyone who has to maintain your code down the road.
If the data items are not functionally related, but are somehow operationally related (e.g. data plus a status flag plus metadata about the operation or items as part of a single input operation), then use multiple writable parameters. The most obvious examples are the *scanf() functions in the standard library. There are also the strtod() and strtol() functions, which convert a string representation of a number; they return the converted value, but they also write the first character that was not converted to a separate parameter:
char *str = "3.14159";
double value;
char *chk;
value = strtod(str, &chk);
if (!isspace(*chk) && *chk != 0)
printf("Non-numeric character found in %s\n", str);
You can combine these approaches; here's an example inspired by some work I'm currently doing:
typedef enum {SUCCESS, REQ_GARBLED, NO_DATA_OF_TYPE, EMPTY, ERROR} Status;
typedef struct bounds {...} Bounds;
tyepdef struct metadata {
size_t bytesRead;
size_t elementsRead;
size_t rows;
size_t cols;
} Metadata;
typedef struct elevations {
size_t numValues;
short *elevations;
} Elevations;
Elevations elevs;
Metadata meta;
Bounds b = ...; // set up search boundary
Status stat = getElevationsFor(b, &elevs, &meta);
The service that I request elevation data from returns a 1-d sequence of values; the dimensions of the array are returned as part of the metadata.
You can do it using structures:
#include <stdio.h>
struct dont { int x; double y; };
struct dont fred(void)
{
struct dont b;
b.x = 1;
b.y = 91.99919;
return b;
}
int main(int argc, char **argv)
{
struct dont look = fred();
printf("look.x = %d, look.y = %lf\n", look.x, look.y);
return 0;
}
You cannot return multiple values from a C function.
You can either
Return a data structure with multiple values, like a struct or an array.
Pass pointers to the function and modify the values of the pointers inside the function. You need to pass x number of pointers where x is the number of return values you need
To return multiple values from a function we should use a pointer. Here is an example through which you can understand it better
int* twoSum(int* nums, int numsSize, int target) {
int i,j,*a;
a=(int*)malloc(2*sizeof(int));
for(i=0;i<numsSize;i++)
for(j=i+1;j<numsSize;j++)
if(nums[i]+nums[j]==target)
{
a[0]=i;
a[1]=j;
return a;
}
}
I´m a beginner in C, so I don´t have experience with array, pointer, structure. To get more than one value from my function I just used a global variable.
Here is my code:
#include <stdio.h>
double calculateCharges( double hourCharges );
// Global variable for totalCharges-function and main-function interaction
double totalCharges = 0;
int main ( void ) {
double car1 = 0;
double car2 = 0;
double car3 = 0;
double totalHours = 0;
printf( "%s", "Hours parked for Car #1: ");
scanf( "%lf", &car1 );
printf( "%s", "Hours parked for Car #2: ");
scanf( "%lf", &car2 );
printf( "%s", "Hours parked for Car #3: ");
scanf( "%lf", &car3 );
totalHours = car1 + car2 + car3;
printf( "%s", "Car\tHours\tCharge\n");
printf( "#1\t%.1f\t%.2f\n", car1, calculateCharges( car1 ));
printf( "#2\t%.1f\t%.2f\n", car2, calculateCharges( car2 ));
printf( "#3\t%.1f\t%.2f\n", car3, calculateCharges( car3 ));
printf( "TOTAL\t%.1f\t%.2f\n", totalHours, totalCharges);
}
double calculateCharges( double hourCharges ) {
double charges = 0;
if( hourCharges <= 3.0 ) {
charges = 2;
} else if ( hourCharges >= 24.0) {
charges = 10.00;
} else {
charges = ((hourCharges - 3.0)*0.5) + 2.0;
}
totalCharges += charges;
return charges;
}
Method 1 is using array
Method 2 is using pointer
Method 3 is using structure

Resources