I have a specific application written in C that needs to be memory efficient. It is collecting statistics, so I need to be able to "turn on/off" certain fields in run-time to minimize the memory consumption.
I know you can define conditional struct fields using macros but that is compile-time if I'm not mistaken, is there a possible way of doing this in C in run-time?
Example:
input :
collect (A,B)
will result in a struct like this:
struct statistics{
double A;
double B;
};
but input:
collect (A,B,C)
will result in a struct like this:
struct statistics{
double A;
double B;
double C;
};
Its not possible to turn-off certain fields inside the struct at run-time. You can however have a pointer that points to a dynamically allocated array of doubles that can represent multiple fields.
For example:
#include <stdio.h>
#include <stdlib.h>
struct stats
{
size_t number_of_doubles;
double* data;
};
void make_stats(struct stats* pStats)
{
pStats->number_of_doubles = 3;
pStats->data = (double*) malloc(pStats->number_of_doubles * sizeof(double));
}
void delete_stats(struct stats* pStats)
{
free(pStats->data);
}
int main()
{
struct stats foo;
make_stats(&foo);
foo.data[0] = 3.0;
foo.data[1] = 5.0;
foo.data[2] = 7.0;
delete_stats(&foo);
return 0;
}
Instead of the usual array of structs (AoS):
struct statistics{
double A;
double B;
double C;
};
struct statistics my_statistics = malloc(1000000 * sizeof(my_statistics[0]));
my_statistics[0].A = 1;
my_statistics[0].B = 2;
my_statistics[0].C = 3;
you could switch to a struct of arrays (SoA):
struct statistics{
double *A;
double *B;
double *C;
};
struct statistics my_statistics;
my_statistics.A = using_A ? malloc(1000000 * sizeof(my_statistics.A[0])) : NULL;
my_statistics.B = using_B ? malloc(1000000 * sizeof(my_statistics.B[0])) : NULL;
my_statistics.C = using_C ? malloc(1000000 * sizeof(my_statistics.C[0])) : NULL;
my_statistics.A[0] = 1;
my_statistics.B[0] = 2;
my_statistics.C[0] = 3;
There is no way to alter the size of a struct at runtime. The size of a struct is built into the executable's instructions whenever you allocate them on the stack or on the heap. As another example, sizeof of a struct is available at compile time, so it can not be altered at runtime.
Of course, you can have custom structs with a custom memory manager to do that, but it's not built right into the language.
Related
Using c language, If I have I declared four random integers how do I go about storing them inside the series variable and then accessing them?
int a =3;
int b=4;
int c=5;
int d=6;
typedef struct struct1
{
int *series;
int num1;
double num2;
double num3;
}
Struct1;
I declared the struct as
Struct1 mystruct;
First of all you allocate the memory you need to store them using malloc. You'll need to include <stdlib.h> to access that function. You need enough space for 4 int so:
mystruct.series = malloc(4 * sizeof(int));
Then you just store and access the data like you'd do for any other array:
mystruct.series[0] = a;
mystruct.series[1] = b;
mystruct.series[2] = c;
mystruct.series[3] = d;
Once you don't need it anymore, remember to free the memory to avoid a memory leak with free(mystruct.series).
I have created a structure called Register, with around 8 fields within it. I now want to create a structure called Instrument, which should have a variable amount of of fields, 6 which are the same for every instrument, plus a certain amount of fields depending on how many registers are attributed to it. How can I create this?
For clarity here is what I would like to create (although may not be accurate).
typedef struct {
int x;
int y;
int z;
} Register;
typedef struct {
int x;
int y;
int z;
Register Reg1;
Register Reg2;
...
} Instrument;
You can make use of flexible array members to achieve the same.
Something like
typedef struct {
int x;
int y;
int z;
Register Reg1;
Register Reg2; //upto this is fixed....
Register Reg[];
} Instrument;
and then, you can allocate memory as needed to someVar.Reg later.
For an example, quoting C11, chapter ยง6.7.2.1/20
EXAMPLE 2 After the declaration:
struct s { int n; double d[]; };
the structure struct s has a flexible array member d. A typical way to use this is:
int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if
p had been declared as:
struct { int n; double d[m]; } *p;
You can use pointers
typedef struct
{
int x;
int y;
int z;
Register *reg;
} Instrument;
use it into code
Instrument a.reg = malloc(sizeof(Register)*NUM_OF_REGISTERS);
if (a.reg != NULL)
{
// your STUFF
free(a.Reg);
}
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;
}
To explain more, I have two structures-'first' and 'second' having common variables 'jack' and 'jill'. I want to print jack via a pointer based on if-else condition.
I understand at the time of printing I have to typecast the void pointer. But whether the pointer points to struct a or b is decided on run time.
It is a basic C code. How to overcome this?
Code
#include <stdio.h>
int main(void)
{
typedef struct one
{
int jack;
float jill;
}a;
typedef struct two
{
int jack;
float jill;
char something;
int something1;
}b;
a first;
b second;
void *z;
if(1)
{
a* z;
z = &first;
printf("First one");
}
else
{
b* z;
z = &second;
printf("Second one");
}
printf("%d\n", z->jack);
return 0;
}
Error
prog.c:36:17: warning: dereferencing 'void *' pointer printf("%d\n", z->jack); prog.c:36:17: error: request for member 'jack' in something not a structure or union
You get a compiler warning since the compiler does not understand z->jack since z is a void * (note that the declarations a* z and b* z are not valid outside the scope of the if and else block).
To overcome this you can use a function printJack as shown in the following listing:
#include <stdio.h>
typedef struct one
{
int jack;
float jill;
}a;
typedef struct two
{
int jack;
float jill;
char something;
int something1;
}b;
void printJack(void *pStruct, int type)
{
switch (type)
{
case 1:
printf("jack: %d\n", ((a *)pStruct)->jack);
break;
default:
printf("jack: %d\n", ((b *)pStruct)->jack);
break;
}
}
/*
** main
*/
int main(void)
{
a first;
b second;
void *z;
first.jack = 5;
second.jack = 4892;
printJack(&first, 1);
printJack(&second, 0);
z = &first;
printJack(z, 1);
return (0);
}
I've written code like this often and experienced a lot of trouble with it. Not at the time of implementing, since you are knowing what you are typing at that moment but let's say a few years later if you need to extend your code. You will miss a few places where you cast from void * to a * or b * and you'll spend a lot of time debugging what's going on...
Now I'm writing things like this in the following way:
#include <stdio.h>
typedef struct header
{
int jack;
float jill;
} h;
typedef struct one
{
struct header header;
/* what ever you like */
}a;
typedef struct two
{
struct header header;
char something;
int something1;
/* and even more... */
}b;
void printJack(void *pStruct)
{
printf("jack: %d\n", ((struct header *)pStruct)->jack);
}
/*
** main
*/
int main(void)
{
a first;
b second;
void *z;
first.header.jack = 5;
second.header.jack = 4892;
printJack(&first);
printJack(&second);
v = &first;
printJack(v);
return (0);
}
As you've noticed I have declared a new struct header which covers the the common parts of struct one and struct two. Instead of casting the void * to either a * or b * a "common" cast to struct header * (or h *) is done.
By doing so you can easily extend the "common attribtues" of the structs or you can implement further structs using this header and function printJack still will work. Additionally there is no need for attribute type anymore making is easier to call printJack. You can even change the type of jack without needing to change it in various places within your code.
But remember that struct header needs to be the first element of the structs you use this mechanism. Otherwise you will end up with a few surprises since you are using memory which does not contain the data of the struct header...
Given two structure in c:
typedef struct _X_
{
int virtual_a;
int virtual_b;
void *virstual_c;
int a;
int b;
void *c;
/* More fields to follow */
}X;
typedef struct _Y_
{
int a;
int b;
void *c;
/* Same fields as in X structure */
}Y;
Q : Is it safe to say that ?
void foo_low( Y *y )
{
y->a = 1;
y->b = 2;
}
void foo( X *x )
{
Y *y = (Y *)(&(x->a) )
foo_low( y );
}
Is it standard C ? will it work on all compilers ? Is there any problem with padding ?
No, your function foo won't work, because a is in the wrong place.
Your example is clearly made up and tha's going to reduce the relevance of my answer to the problem you are really trying to solve, but this definition does something like I believe you are asking for:
struct header {
int a;
int b;
void *c;
};
struct shared_fields {
int a;
int b;
void *c;
/* More fields to follow */
};
typedef struct
{
struct header virtuals;
struct shared_fields shared;
} X;
typedef struct
{
struct shared_fields shared;
} Y;
void foo_low(struct shared *ys)
{
ys->a = 1;
ys->b = 2;
}
void foo(X *x)
{
foo_low(&x->shared);
}
However, this does not perform a cast, since one is not needed. If you really intended to set data via one struct and access it via another, this is not allowed in standard C (though there might be an exception for same-struct-with-different labels as described by Hubert).
I suspect that a better solution to the problem you asked about is the use of union which can often be used to do what you may have in mind. But strictly speaking, if you have an object u of union type and you set u.a, accessing the value of u.b before setting u.b has undefined behaviour. Though commonly people do not worry about that.
That should work. But since you need to access the same fields in two distinct ways (y->a and x->a are different), I would use union:
typedef struct _Y_
{
int a;
int b;
void *c;
/* Same fields as in X structure */
}Y;
typedef struct _X_
{
int virtual_a;
int virtual_b;
void *virstual_c;
Y y_fields;
}X;
typedef union {
X x;
Y y;
} Z;
Now x.virtual_a and y.a are in the same memory address.
And you can rewrite your code as follows:
void foo_low( Z *z )
{
z->y.a = 1;
z->y.b = 2;
}
void foo( Z *z )
{
Z *w = z;
w->y = z->x.y_fields;
foo_low( w );
}
The only clumsy part is adding Y inside X.
if both structs have identically structure it is ok. Names of fields inside the struts need not to be the same, but their types must be the same. Each subfield in X must match to a subfield in Y in its type and position. Names of fields can be different.