How can I initialize similar structs with the same function? - c

I have some structs that start with a void *buffer and the next members can be of different types:
struct A {
void *buffer;
type_x *x;
type_y *y;
};
struct B {
void *buffer;
type_w *w;
type_y *y;
type_z *z;
};
The buffer from struct A will store n elements of type type_x, followed by n elements of type_y. The other members, type_x *x and type_y *y, will point to those arrays, respectively. Analogous for struct B.
What I'm currently doing is something like this:
void allocate(struct B **b, unsigned int n) {
(*b)->buffer = calloc(n * (sizeof(type_w) + sizeof(type_y) + sizeof(type_z));
(*b)->w = (type_w *) (*b)->buffer;
(*b)->y = (type_y *) ((*b)->w + n);
(*b)->z = (type_z *) ((*b)->y + n);
}
Is there any way to create a function to achieve this? The function should receive as arguments a pointer to one of these structs (void *s) and an int, like this:
void allocate(void *s, unsigned int n) {
// MAGIC
}
Some other options I've considered:
Create void allocate(void *buffer, int n, ...) and give it pointers to the pointers of the struct. The problem with this is that I have to give it void * pointers, so I would have to give it the size of every type as well.
Create void *create_struct(StructType type) (where StructType is an enum) but I would have to code the case for every struct anyway and I want to be able to define new structs and not have to write aditional code.
I'm trying to do this as I will have many structs, and because the allocate function does basically the same thing for every struct I thought there may be a "cleaner" way to do it.
Also, I know that I can just remove the buffer and allocate memory directly to all the members, but I want to do it this way so data is stored contiguously.

There is no generic way to do this that doesn't play fast and loose with type safety. This means, technically, a truly generic solution will result in undefined behavior. If I was forced to implement something like this, I would have to assume I could treat the incoming structure pointer as an array of pointers. And the size of each type would need to be passed in. Ignoring alignment issues, some untested code:
void allocate(void *sp, size_t n, ... /* terminate with 0 */) {
void **sv = sp;
size_t arg, total = 0;
size_t args = 0;
va_list ap;
va_start(ap, n);
while ((arg = va_arg(ap, size_t)) != 0) {
total += arg;
++args;
}
va_end(ap);
*sv = calloc(...);
sv[1] = sv[0];
va_start(ap, n);
while (--args > 0) {
++sv;
sv[1] = (char *)sv[0] + va_arg(ap, size_t);
}
va_end(ap);
}
allocate(a, n, sizeof(type_x), sizeof(type_y), (size_t)0);
allocate(b, n, sizeof(type_w), sizeof(type_y), sizeof(type_z), (size_t)0);
Clearly hacky and ugly.
The better solution should really be to create a separate allocator function for each type. However, you can create a macro to aid in the automatic generation of the allocator. More untested code follows:
#define CREATE_ALLOCATOR(Type, X_Fields) \
void allocate_##Type (struct Type *sp, size_t n) { \
_Pragma("pop_macro(\"X\")") \
size_t total = 0 \
X_Fields \
; \
void *p; \
sp->buffer = calloc(sizeof(*sp) + total); \
p = sp->buffer; \
_Pragma("pop_macro(\"X\")") \
X_Fields \
; \
}
#include "create_allocator_helper.h"
CREATE_ALLOCATOR(A, X(x) X(y))
#include "create_allocator_helper.h"
CREATE_ALLOCATOR(B, X(w) X(y) X(z))
Where the helper header file defines and pushes some X macro definitions used by the CREATE_ALLOCATOR macro:
#ifdef X
#undef X
#endif
#define X(A) ; sp->A = p; p = sp->A + n
#pragma push_macro("X")
#undef X
#define X(A) + sizeof(sp->A)
#pragma push_macro("X")
#undef X

If you know the set of possible ns at compile time, you can let each (member set)/(array size) combination be its own type, and use convenience macros to refer to the correct ones.
#include <stddef.h>
/*
We put a type marker at the beginning of each struct. There won't be padding before the first member, and all the types
start with a struct Type, so we can do `(struct Type*)&unknown_structure` and be guaranteed to have a valid object that
tells us what type the rest of it is.
In practice, I'd probably use X-Macros to generate an enum containing all the types instead of using strings, to
make comparison faster
*/
struct Type { char *type; size_t n; };
/* We define what types of arrays each structure contains. Since the struct contains the arrays themselves
instead of pointers to them, the memory will be contiguous, +/- a bit of padding. */
#define DECL_A(N) struct A_##N { struct Type type; char x[N]; double y[N]; }
#define DECL_B(N) struct B_##N { struct Type type; size_t n; int x[N]; float y[N]; char z[N]; }
/*
Declare a struct and initialize the type and n members. This one just
declares a local variable, but we could make a malloc version easily enough.
*/
#define CREATE_STRUCT(NAME, TYPE, N) struct TYPE##_##N NAME = { .type = { #TYPE, N} }
/* We declare all struct type/size combinations we'll use */
DECL_A(42);
DECL_A(100);
DECL_B(30);
int main(void) {
int i;
CREATE_STRUCT(foo, A, 42);
CREATE_STRUCT(bar, A, 100);
CREATE_STRUCT(baz, B, 30);
return 0;
}

Here's an alternative that doesn't require n to be known at compile time.
Note that I am not completely sure about the legality of this, but I'm
reasonably sure it's valid. The key idea here is that if p points to a
properly aligned memory block for type T, then ((char*)p) + sizeof(T) * N must also point
to properly aligned memory as long as it falls within an allocated block.
As long as that's true, I'm pretty sure this must necessarily be legal, since the union
of buffer and Alignment_Hack guarantees that buffer[0] is aligned properly for all types.
Even if it's legal, it's still a bit of a hack, so I'm not entirely sure I'd recommend it, but it's a potential option.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
/* This MUST contain all types that might be stored in the arrays */
union Alignment_Hack {
short hd;
int d;
char c;
float hf;
double f;
};
/* This struct is used for *all* structures. The structure-specific details get specified later */
struct Variable_Structure {
size_t num_arrays;
void **arrays;
union {
union Alignment_Hack *hack;
char *buffer;
} u; //u.buffer[0] is guaranteed to be properly aligned for anything in the union
};
//Here's where the details for a specific struct (struct A {short x; double y; int z; }) are specified.
size_t sizes_A[] = { sizeof(short), sizeof(double), sizeof(int) };
void create_structure(struct Variable_Structure *p, const size_t array_count, size_t *sizes, unsigned nvars) {
size_t offsets[nvars];//in bytes (NOTE: requires C99)
unsigned i;
offsets[0] = 0;
for (i = 1; i < nvars; i++) {
//offsets[i] must be an even multiple of sizes[i] and must also be past the end of the last array
size_t min = offsets[i - 1] + sizes[i - 1] * array_count;
size_t mod = min % sizes[i];
//offsets[i] = min_p such that p >= min and p % sizes[i] == 0
offsets[i] = (min - mod) + (mod ? sizes[i] : 0);// (min - mod) and (min - mod + sizes[i]) are the two possible starting points
/* Visualization of the transition from TYPE_A[] to TYPE_B[], showing where everything's pointing:
min (end of TYPE_A array)
V
... | TYPE_A | TYPE_A | TYPE_A |
... | TYPE_B | TYPE_B | TYPE_B | TYPE_B |
^ ^
min - mod (min - mod) + sizes[i] */
assert(offsets[i] >= min);//doesn't overlap previous array
assert(offsets[i] <= min + sizes[i]);//doesn't include more padding than necessary
assert(0 == offsets[i] % sizes[i]);//alignment correct
}
size_t bufsiz = offsets[nvars - 1] + sizes[nvars - 1] * array_count;
//Skipping error checking for brevity
p->num_arrays = nvars;
p->u.buffer = malloc(bufsiz);
p->arrays = malloc(sizeof(void*) * nvars);
for (i = 0; i < nvars; i++) {
p->arrays[i] = p->u.buffer + offsets[i];
}
}
void free_structure(struct Variable_Structure *p) {
free(p->arrays);
free(p->u.buffer);
}
int main(void) {
struct Variable_Structure a;
size_t n = 42;
create_structure(&a, n, sizes_A, sizeof(sizes_A)/sizeof(*sizes_A));
unsigned i;
for (i = 0; i < n; i++) {
//We could always set up some macros or something so we could say, e.g., A(x, i) instead of ((short*)a.arrays[0])[i]
((short*)a.arrays[0])[i] = i;
((double*)a.arrays[1])[i] = i;
((int*)a.arrays[2])[i] = i;
printf("%hd %f %d\n",
((short*)a.arrays[0])[i],
((double*)a.arrays[1])[i],
((int*)a.arrays[2])[i]);
}
printf("SIZES: %zu %zu %zu\n", sizeof(short), sizeof(double), sizeof(int));
printf("OFFSETS: %p %p %p\n", a.arrays[0], a.arrays[1], a.arrays[2]);
free_structure(&a);
return 0;
}

Related

Multiple Flexible Array Member or VLA with Shared Memory and Semaphores

I need to define a struct with two semaphores and three(at the least) or maybe more arrays as members of the struct whose size are variables. Indicative example ( not the right syntax but to give a contextual meaning ; lr is typedef for double) :
int nx = 400,ny = 400,nz = 400;
struct ShMem {
sem_t prod;
sem_t cons;
lr u_x[nx+1][ny+2][nz+2];
lr u_y[nx+2][ny+1][nz+2];
lr u_z[nx+2][ny+2][nz+2];
};
What I need to do is to make the struct ShMem as a shared memory block between two codes aka producer and consumer which compute and read this memory block with the help of the semaphores present in the struct.
Since the array size are variables and will be defined in runtime how do i get a 3 Dimensional variable length array ?
Comment :
If lets say I have nx, ny and nz #defined to 400 I follow the following step ( already tested )
#define nx (400)
#define ny (400)
#define nz (400)
struct ShMem {
sem_t prod;
sem_t cons;
lr u_x[nx+1][ny+2][nz+2];
lr u_y[nx+2][ny+1][nz+2];
lr u_z[nx+2][ny+2][nz+2];
};
...
// shared memory allocation
ShmID = shmget(ShmKEY, sizeof(struct Shmem), IPC_CREAT|0666);
...
Additional requirement is that for the application I do need those arrays as 3D arrays such that I can index them as u_x[i][j][k], whre i, j, k are indices in the x, y, and z-direction respectively.
Edit after Lundin and Felix solution.
CONSTRAINT - u_x, u_y and u_z needs to be a 3D array/*** pointer which is accessed by u_x[i][j][k] - This can't be changed since this is a legacy code. The arrays need to be set such that the sanctity of the access is maintained. Everywhere in the code it is accessed like that.
As already discussed in the comments, C doesn't support something like that. So, you will have to build it yourself. A simple example using a macro to make the "3D access" inside the structure readable could look like this:
#include <stdlib.h>
typedef int lr;
struct foo {
size_t ny;
size_t nz;
lr *u_y;
lr *u_z;
lr u_x[];
};
#define val(o, a, x, y, z) ((o).a[(o).ny * (o).nz * x + (o).nz * y + z])
struct foo *foo_create(size_t nx, size_t ny, size_t nz)
{
size_t arrsize = nx * ny * nz;
struct foo *obj = malloc(sizeof *obj + 3 * arrsize * sizeof *(obj->u_x));
if (!obj) return 0;
obj->ny = ny;
obj->nz = nz;
obj->u_y = obj->u_x + arrsize;
obj->u_z = obj->u_y + arrsize;
return obj;
}
int main(void)
{
struct foo *myFoo = foo_create(10, 10, 10);
// set u_y[9][5][2] in *myFoo to 42:
val(*myFoo, u_y, 9, 5, 2) = 42;
free(myFoo);
}
This uses the single FAM at the end of the struct supported by C, so you can allocate such a struct in a single block. To place it in shared memory, just replace the malloc() and use the same calculations for the size.
You have to build something like this
struct ShMem {
int some_stuff_here;
size_t x[3];
size_t y[3];
size_t z[3];
int array[];
};
And then ignore that the flexible array member type is a plain int array. Instead do something like
size_t size = sizeof( int[x1][y1][z1] ) +
sizeof( int[x2][y2][z2] ) +
sizeof( int[x3][y3][z3] );
ShMem* shmem = malloc(sizeof *shmem + size);
And then when accessing, you use an array pointer type instead of the int[]. The code turns a bit nasty to read:
for(size_t i=0; i<3; i++)
{
typedef int(*arr_t)[shmem->y[i]][shmem->z[i]]; // desired array pointer type
int some_offset = ... // calculate based on previously used x y z
arr_t arr = (arr_t)shmem->(array + some_offset); // cast to the array pointer type
for(size_t x=0; x<shmem->x[i]; x++)
{
for(size_t y=0; y<shmem->y[i]; y++)
{
for(size_t z=0; z<shmem->z[i]; z++)
{
arr[x][y][z] = something;
}
}
}
}
This is actually well-defined behavior since the data allocated with malloc doesn't have an effective type until you access it.
"some_offset" in the above example could be a counter variable or something stored inside the struct itself.

Implement a struct type on top of void *

Simple sanity check question here. The underlying requirement is to put two flexible array members in a struct to reduce the number of calls to malloc for performance reasons.
Given that a struct instance is a block of aligned memory containing a number of fields at constant offsets, can one implement functionality semantically equivalent to a struct by writing the offset calculations and casting?
void f()
{
typedef struct
{
double x;
char y;
int32_t foo;
double z;
} equivalent;
equivalent * e = malloc(sizeof(equivalent));
free(e);
static_assert(sizeof(equivalent) == 24,"");
char* memory = malloc(24);
double* x = (double*) ( 0 + memory);
char* y = (char *) ( 8 + memory);
int32_t* foo = (int32_t*) (12 + memory);
double* z = (double*) (16 + memory);
free(memory);
}
Keeping the alignment / offset calculations consistent is tedious, but assuming the type is opaque anyway the client code doesn't have to see any of that. Similarly the syntactic overhead is hidden.
I've read through the aliasing rules as clarified by C11 (the "effective type" part) and think I'm in the clear there.
Is this fair game? I thought I'd seek a second opinion prior to writing a lot of very dull code.
Cheers
edit: As a response to Jonathan Leffler, this is a quick & dirty sketch of how I intend to put a couple of arrays of runtime determined length into the single block of memory.
I prefer storing an integer which is used to calculate the location of the array, as opposed to storing a pointer which is already aimed at the array, because it makes copying the structure simpler. Storing appropriately initialised pointers and relocating them on copy is probably faster though.
void* g(uint64_t N_first, uint64_t N_second)
{
// desired representation:
// uint64_t N_first;
// int32_t first[N_first];
// uint64_t N_second;
// double second[N_second];
// this function doesn't populate the arrays, only
// allocates storage and sets up the length fields
uint64_t bytes_for_lengths = 16;
char* bytes = malloc(bytes_for_lengths + bytes_for_first(N_first) +
bytes_for_second(N_second));
uint64_t* ptr_N_first = get_N_first(bytes);
*ptr_N_first = N_first;
uint64_t* ptr_N_second = get_N_second(bytes);
*ptr_N_second = N_second;
return (void*)bytes;
}
// I haven't decided how best to factor out the field access
// and associated functions yet, so this is not optimal
uint64_t* get_N_first(void* vdata)
{
char* data = (char*)vdata;
return (uint64_t*)(data + 0);
}
int32_t* get_first(void* vdata)
{
char * data = (char*)vdata;
return (int32_t*)(data + 8);
}
uint64_t bytes_for_first(uint64_t N_first)
{
// first is an int32_t
// the next field needs to be 8 byte aligned
uint64_t bytes = 4 * N_first;
if (bytes % 8 != 0)
{
bytes += 4;
}
return bytes;
}
uint64_t* get_N_second(void* vdata)
{
uint64_t n_first = *get_N_first(vdata);
uint64_t first_bytes = bytes_for_first(n_first);
char* data = (char*)vdata;
return (uint64_t*)(data + 8 + first_bytes);
}
double* get_second(void* vdata)
{
char * data = (char*)vdata;
uint64_t n_first = *get_N_first(vdata);
uint64_t first_bytes = bytes_for_first(n_first);
return (double*)(data + 8 + first_bytes + 8);
}
uint64_t bytes_for_second(uint64_t N_second)
{
// second is a double
return 8 * N_second;
}
There is nothing tedious ...
size_t offset_of_x = offsetof(equivalent, x);
size_t offset_of_y = offsetof(equivalent, y);
size_t offset_of_foo = offsetof(equivalent, foo);
size_t offset_of_z = offsetof(equivalent, z);
char* memory = malloc(sizeof(equivalent));
double* x = offset_of_x + memory;
char* y = offset_of_y + memory;
int32_t* foo = offset_of_foo + memory;
double* z = offset_of_z + memory;
free(memory);
And yes, this is perfectly legal.
/edit (after your edit):
Instead of using this representation:
struct fake_your_version {
uint64_t N_first;
int32_t first[N_first];
uint64_t N_second;
double second[N_second];
};
You should consider using either this representation:
struct fake_alternative_1 {
uint64_t size; // max over all num[i]
uint64_t num[2]; // num[0] being for first, num[1] being for second
struct {
int32_t first;
double second;
} entry[num];
};
or this representation:
struct fake_alternative_2 {
uint64_t num[2];
void * data[2]; // separate malloc(num[i] * sizeof(whatever));
};
Because your approach will enforce moving of data on a size change of anything but the last array.
fake_alternative_1 will also save one malloc (at the expense of padding bytes and lost memory if the array need to be different sizes).
Before you even consider doing this, you should really ask youself, wheather malloc is really that slow, that you must avoid it. Probably, whatever you're doing, something else than malloc is slowing you down (possibly, your attempts to save mallocs make you code even slower instead of faster).
(fake_alternative_2 will just accept, that each array get's it's own malloc, but I guess, I'm not telling you anything new by giving you this alternative).
I can't help but feel that it would be cleaner to use a straight-forward structure to achieve your 'double VLA' structure type. More or less like this:
// desired representation:
// uint64_t N_first;
// int32_t first[N_first];
// uint64_t N_second;
// double second[N_second];
#include <assert.h>
#include <inttypes.h>
#include <stdalign.h>
#include <stdio.h>
#include <stdlib.h>
struct DoubleVLA
{
uint64_t N_first;
int32_t *first;
uint64_t N_second;
double *second;
//double align_32[]; // Ensures alignment on 32-bit
};
extern struct DoubleVLA *alloc_DoubleVLA(uint64_t n1, uint64_t n2);
struct DoubleVLA *alloc_DoubleVLA(uint64_t n1, uint64_t n2)
{
struct DoubleVLA *dv = malloc(sizeof(*dv) + n1 * sizeof(dv->first) + n2 * sizeof(dv->second));
if (dv != 0)
{
dv->N_first = n1;
dv->N_second = n2;
if (alignof(dv->second) >= alignof(dv->first))
{
dv->second = (double *)((char *)dv + sizeof(*dv));
dv->first = (int32_t *)((char *)dv + sizeof(*dv) + n2 * sizeof(dv->second));
}
else
{
dv->first = (int32_t *)((char *)dv + sizeof(*dv));
dv->second = (double *)((char *)dv + sizeof(*dv) + n1 * sizeof(dv->first));
}
}
return dv;
}
int main(void)
{
struct DoubleVLA *dv = alloc_DoubleVLA(UINT64_C(11), UINT64_C(32));
for (uint64_t i = 0; i < dv->N_first; i++)
dv->first[i] = i * 100 + rand() % 100;
for (uint64_t j = 0; j < dv->N_second; j++)
dv->second[j] = j * 1000.0 + (rand() % 100000) / 100.0;
for (uint64_t i = 0; i < dv->N_first; i++)
printf("%.2" PRIu64 " = %12" PRId32 "\n", i, dv->first[i]);
for (uint64_t j = 0; j < dv->N_second; j++)
printf("%.2" PRIu64 " = %12.2f\n", j, dv->second[j]);
free(dv);
return 0;
}
Even on a 32-bit platform, there should be enough padding at the end of the structure to make its size such that it will be appropriately aligned for an array of double immediately after the structure and an array of int32_t after that. However, there would be unnecessary padding that could be avoided by putting the two sizes first and the two pointers last in the structure. That isn't a problem on a 64-bit platform. The optional align_32 VLA assumes that the alignment requirement of int32_t is not greater than the alignment requirement of double; it would ensure that the structure is padded correctly, even if there was some weird alignment restrictions or requirements. It would be possible to provide a static assertion that the constraints are met.
The alignof material is from C11; it allows you to work with two types with different alignment requirements and automatically selects the better layout (more stringently aligned array before less stringent one).
With this organization, there's no need for a functional interface to the sections of the structure. Direct access is simple and readily comprehended.

Create a d-dimensional pointer [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
We use to indicate a pointer with the symbol *. Iterating the procedure, we obtain a "double" pointer **, a "triple" pointer *** and, more generally, a "d-dimensional" pointer (for each d positive natural number).
Problem: given such a d as an input, define S to be a d-dimensional pointer.
Because I started studying dynamic structures only some days ago, I am unfortunately a bit in trouble with this problem.
Does anyone have a suggestion/hint?
Thank you in advance, and my apologies for my probably too basic question.
Ps: I used the word "pointer" without specify its type only for sake of brevity.
This problem has a solution in C as long as two conditions are met:
The value of d is known at compile time, and
d has a pre-defined limit, e.g. 10
You can solve this problem by defining a series of macros and "pasting" the value of d as a token:
#define D_PTR(d,T) D_PTR##d(T)
#define D_PTR0(T) T
#define D_PTR1(T) T*
#define D_PTR2(T) T**
#define D_PTR3(T) T***
...
#define D_PTR10(T) T**********
Now you can declare d-dimension pointers like this:
D_PTR(5,int) ptr5 = NULL;
Demo.
There are three distinct ways to solve this:
Your d is a compile-time constant. For this case, dasblinkenlight has already given the solution.
The hacky-C solution: Just use a cast to get back to the pointer type:
double* dereferenceDLevels(double* pointer, int d) {
for(; d--; ) pointer = *(double**)pointer;
return pointer;
}
I do not recommend this approach, though. It's just too dirty.
You implement your d-level pointers as user defined types:
typedef struct nLevelPointer {
int n;
union {
nLevelPointer* pointer;
double value;
};
} nLevelPointer;
double nLevelPointer_dereference(nLevelPointer* me) {
for(int i = me->n; i--; ) me = me->pointer;
return me->value;
}
I consider this approach the cleanest and most flexible one. However, it has the trade-off of requiring a significant amount of boilerplate code to make it fly.
Basically the number of * represents the number of indirections to reach the variable. So you have to create d indirections. I assume this has no practical application - that's an answer to a recreative problem.
An indirection in C is an address, a pointer. Creating d indirections means the creation of d addresses to reach a variable data (the space allocated to the variable of type T).
p(d) -> p(d-1) -> ... -> p(1) -> variable
To create dynamically such a structure, you could do it via malloc (replace T with any known type), and - since you may not specify the number of * dynamically to a pointer - requires some C hacking.
So, again, this is not something recommended and is a particularly bad design, especially for inexperienced C developers. Purpose is to show it could be done dynamically, whatever the value of d.
Say T is a double
int d = ...; // from input (d >= 1)
double variable;
double **S = malloc(sizeof(double *) * d); // array of pointers to pointer
S[d-1] = &variable; // last address points to target
int i;
for(i=d-2 ; i>=0 ; i--) S[i] = (double *)&S[i+1]; // previous address
// points to next location
There is no way to represent an arbitrary number of indirections in C, so S is only a ** to satisfy the compiler requirements, and is cast when necessary.
Let's try with d set to 4 and applying the algorithm above (say T is a double), having
double variable is at address 0100 (decimal), value 3.14
S address given by malloc at 1000
a pointer size being 4
a double size being 8
variable
v
[8 bytes double value 3.14]
^
0100
S
v
[1004][1008][1012][0100]
^ ^
1000 1012
Now the structure is in place, how to use/test it? You could create a function that returns the type T (double here), take the S value and d, operate the d indirections and return the variable
double getvariable(double **S, int d) {
while (--d > 0) S = (double **)*S; // d-1 iterations
return *(double *)*S;
}
trying it
printf("%lf\n", getvariable(S, d)); // 3.14
to test the above structure without a function, for d == 4, you could create
double ****p = (double ****)*S;
printf("%lf\n", ****p); // 3.14
Problem: given such a d as an input, define S to be a d-dimensional
pointer.
It's possible in C to functionally represent an N dimensional array at run time, if not a pointer with an arbitrary number of levels of indirection. This could be a start (uncompiled, and this utterly ignores any possible alignment issues):
void *allocateArray( unsigned int N, size_t elemSize, unsigned int *dimensions )
{
if ( N == 1U )
{
return( malloc( elemSize * dimensions[ 0 ] ) )
}
void *array = malloc( sizeof( void * ) * dimensions[ 0 ] );
for ( unsigned ii = 0; ii < dimensions[ 0 ]; ii++ )
{
array[ ii ] = allocateArray( N - 1, elemSize, &( dimensions[ 1 ] ) );
}
return( array );
}
Note, that is not a very efficient way of allocating an N-dimensional array.
You could call it like this:
unsigned dims[] = { 5,7,8,9 };
unsigned d = sizeof( dims ) / sizeof( dims[ 0 ] );
size_t elemSize = sizeof( double );
void *array = allocateArray( d, elemSize, dims );
A varargs solution is probably possible, too.
Dereferencing the array would require something similar. This returns the address of the element dereferenced:
void *dereferenceArray( void *array, unsigned int N,
size_t elemSize, unsigned int *element )
{
if ( N == 1U )
{
char *tmp = array;
return( tmp + ( elemSize * element[ 0 ] ) );
}
else
{
void **tmp = array;
return( dereferenceArray( tmp[ element[ 0 ] ],
N - 1, elemSize, &( element[ 1 ] ) ) );
}
}
It'd be much easier in C++ as you could provide a [] operator to your array object and nest them to build N-dimensional arrays.
You could create the runtime equivalent of a d-indirection pointer by chaining as many void ** pointers as you need. A sparse array could then be built this way:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc < 4)
{
printf("Call this passing d (dimensions), n (elements for each dim), u (used elements) as parameters\n");
return 0;
}
int d = atoi(argv[1]);
assert(d > 0);
int n = atoi(argv[2]);
assert(n > 0);
int u = atoi(argv[3]);
assert(u < n * d);
// Creating
void *root = malloc(sizeof(void *) * n);
memset(root, 0, sizeof(void *) * n);
srand(time(NULL));
int i, p, c;
void **cursor;
for (int c = 0; c < u; ++c)
{
cursor = root;
for (i = 0; i < d; ++i)
{
p = rand() % n;
if (cursor[p] == NULL)
{
cursor[p] = malloc(sizeof(void *) * n);
memset(cursor[p], 0, sizeof(void *) * n);
}
cursor = cursor[p];
}
p = rand() % n;
if (cursor[p] == NULL)
cursor[p] = "Hello";
else
--c;
}
// Traversing
struct SE
{
void * *s;
int p;
};
struct SE *stack = malloc(sizeof(struct SE) * (d + 1));
for (cursor = root, p = 0, i = 0; ; ++p)
{
if (p == n)
{
if (i == 0)
break;
cursor = stack[--i].s;
p = stack[i].p;
}
else if (cursor[p] != NULL)
{
if (i < d)
{
stack[i].s = cursor;
stack[i++].p = p;
cursor = cursor[p];
p = -1;
}
else
{
printf("root");
for (c = 0; c < i; ++c)
printf("[%d]->", stack[c].p);
printf("[%d]=\"%s\"\n", p, cursor[p]);
}
}
}
// Tearing down
for (cursor = root, p = 0, i = 0; ; ++p)
{
if (p == n)
{
if (i == 0)
break;
cursor = stack[--i].s;
p = stack[i].p;
free(cursor[p]);
}
else if (cursor[p] != NULL && i < d)
{
stack[i].s = cursor;
stack[i++].p = p;
cursor = cursor[p];
p = -1;
}
}
free(root);
free(stack);
return 0;
}

How to allocate and declare a 3D of array of structs in C?

How do you allocate and declare a 3D array of structs in C?
Do you first allocate the array or declare it?
I feel like you have to allocate it first so you can declare it so it is on the heap, but then how do you allocate something that hasn't been made yet?
Also, should you allocate it all at once or element by element?
Also am i putting the structs into the array correctly?
My guess on how to do it would be:
header.h
struct myStruct{
int a;
int b;
};
typedef struct myStruct myStruct_t;
main.c
#include "header.h"
#include <stdio.h>
#include <stdlib.h>
int main(void){
int length=2;
int height=3;
int width =4;
myStruct_t *elements;
struct myStruct arr = (*myStruct_t) calloc(length*height*width, sizeof(myStruct);
//zero based array
arr[length-1][height-1][width-1];
int x=0;
while(x<length){
int y=0;
while(y<height){
int z=0;
while(z<depth){
arr[x][y][z].a=rand();
arr[x][y][z].b=rand();
z++;
}
y++;
}
x++;
}
return 0;
}
The easy way is:
myStruct_t (*arr2)[height][width] = calloc( length * sizeof *arr );
Then your loop can access arr2[x][y][z].a = rand(); and so on. If you're not familiar with this way of calling calloc, see here. As usual with malloc, check arr2 against NULL before proceeding.
The triple-pointer approach is not really a practical solution. If your compiler does not support variably-modified types then the array should be flattened to 1-D.
There are a couple of different ways to do this, depending on what you want. First, you can allocate your array on the stack (in C99 and some compilers) like this:
myStruct_t arr[length][height][depth];
If you want it allocated on the heap, then you can do a single allocation of the appropriate size. You can then either do the index calculation yourself or make a pointer do the work for you (in C99 and some compilers):
void *buf = malloc(length * height * width * sizeof(myStruct_t));
myStruct_t *arr = buf;
myStruct_t (*arr2)[height][width] = buf;
/* TODO: check return of malloc */
...
arr[x * height * width + y * width + z].a = rand(); /* indexing the C89 way */
arr2[x][y][z].b = rand(); /* indexing the C99 way */
Or you can manually allocate the multiple dimensions.
#include <stddef.h>
#include <stdlib.h>
typedef struct myStruct
{
int a, b;
} myStruct_t;
int main()
{
myStruct_t ***arr;
int length = 5000, height = 1000, depth = 20;
int x, y, z;
int ret = 1;
if (NULL == (arr = malloc(length * sizeof(myStruct_t**))))
goto FAIL;
for (x = 0; x < length; ++x)
{
if (NULL == (arr[x] = malloc(height * sizeof(myStruct_t*))))
goto FAIL_X;
for (y = 0; y < height; ++y)
{
if (NULL == (arr[x][y] = malloc(depth * sizeof(myStruct_t))))
goto FAIL_Y;
for (z = 0; z < depth; ++z)
{
arr[x][y][z].a = rand();
arr[x][y][z].b = rand();
}
}
}
/* TODO: rest of program logic */
/* program successfully completed */
ret = 0;
/* reclaim arr */
FAIL_CLEANUP: /* label used by TODO code that fails */
for (x = length - 1; x >= 0; --x)
{
for (y = height - 1; y >= 0; --y)
{
free(arr[x][y]);
FAIL_Y:
;
}
free(arr[x]);
FAIL_X:
;
}
free(arr);
FAIL:
return ret;
}
This last version uses a lot more memory for all the explicit pointers it contains, its memory locality is worse and it's significantly more complex to properly allocate and reclaim. However, it does allow different sizes along your dimensions. For example, the array arr[0][4] can have a different size than arr[0][7] if you ever need that.
If you want to allocate it on the heap, then you probably want the second version with a single allocation and multi-dimension pointer (if available) or do the indexing yourself manually using appropriate math.

Random matrix struct creation

I'm trying to make a struct that generates a random matrix and am getting "error: expected â=â, â,â, â;â, âasmâ or â_attribute_â before âmatrixâ" when compiling. How can I get this to work effectively and efficiently?
I guess expected errors usually are caused by typos but I don't see any.
I'm very new to C so pointers and malloc are quite foreign to me. I really appreciate your help.
/* It's called RandomMatrixMaker.c */
#include <stdio.h>
#include <stdlib.h>
typdef struct {
char* name;
int MID;
int MRows;
int MCols;
long[][]* MSpace;
} matrix;
matrix makeRIDMatrix(char* name, int MID, int MRows, int MCols) {
matrix m;
static int i, j, r;
m.name = name;
m.MID = MID;
m.MRows = MRows;
m.MCols = MCols;
for (i=0; i<m.MRows; i++) {
for (j=0; i<m.MCols; j++) {
r = random(101);
*(m.MSpace[i][j]) = r;
}
}
return m;
}
int main(void) {
makeRIDMatrix("test", 1, 10, 10);
return 0;
}
There is indeed a typo. You misspelled typedef:
typdef struct {
should be:
typedef struct {
EDIT:
Also, there's no reason to use static here:
static int i, j, r;
You can just get rid of the static modifier.
int i, j, r;
As another poster mentioned, there's a typo, but even with that corrected, it wouldn't compile, due to the definition of matrix.MSpace.
Let's begin in makeRIDMatrix(). You've declared an automatic (stack) variable of type "matrix". At the end of the function, you return that object. Whilst this is permissible, it's not advisable. If the struct is large, you will be copying a lot of data unnecessarily. Better to pass a pointer to a matrix into makeRIDMatrix(), and have makeRIDMatrix() fill in the contents.
The test in the inner loop is against i, but should be against j.
Next, let's look at the definition of "matrix". The definition of "MSpace" is a mess, and wouldn't even compile. Even if it did, because you haven't defined the length of a row, the compiler would not be able to calcuate the offset to any given item in the array. You want a two-dimensional array without giving the row length, but you can't do that in C. You can in other languages, but not C.
There's a lot more I could point out, but I'd be missing the real point. The real point is this:
C Is Not Java.
(It's also not one of the interpreted languages such as JavaScript, PHP, Python, Ruby and so on.)
You don't get dynamically-expanding arrays; you don't get automatic allocation of memory; you don't get garbage collection of unreferenced memory.
What you need is something more like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
char* name;
int MID;
unsigned int MRows;
unsigned int MCols;
long *MSpace;
} matrix;
void makeRIDMatrix(matrix *pmx, char* name, int MID,
unsigned int MRows, unsigned int MCols) {
int i, j;
long *MSpace = malloc(sizeof(*MSpace)*MRows*MCols);
if (MSpace == NULL) {
return;
}
pmx->name = name;
pmx->MID = MID;
pmx->MRows = MRows;
pmx->MCols = MCols;
pmx->MSpace = MSpace;
srandom((unsigned int)time(NULL));
for (i=0; i<MRows; i++) {
for (j=0; i<MCols; j++) {
long int r = random() % 101L;
*(MSpace++) = r;
}
}
}
inline long * item_addr(const matrix *pmx,
unsigned int row, unsigned int col) {
if (pmx == NULL || pmx->MSpace == NULL
|| row >= pmx->MRows || col >= pmx->MCols) {
return NULL;
}
return &(pmx->MSpace[row * pmx->MCols + col]);
}
long get_item(const matrix *pmx, unsigned int row, unsigned int col) {
long *addr = item_addr(pmx, row, col);
return addr == NULL ? 0L : *addr;
}
void set_item(matrix *pmx,
unsigned int row, unsigned int col,
long val) {
long *addr = item_addr(pmx, row, col);
if (addr != NULL) {
*addr = val;
}
}
int main(void) {
matrix m;
makeRIDMatrix(&m, "test", 1, 10, 10);
return 0;
}
Note a few things here. Firstly, for efficiency, I fill the array as if it were one-dimensional. All subsequent get/set of array items should be done through the getter/setter functions, for safety.
Secondly, a hidden nasty: makeRIDMatrix() has used malloc() to allocate the memory - but it's going to be job of the calling function (or its successors) explciitly to free() the allocated pointer when it's finished with.
Thirdly, I've changed the rows/cols variables to unsigned int - there's little sense in definining an array with negative indices!
Fourthly: little error checking. For example, makeRIDMatrix() neither knows nor cares whether the parameter values are sensible (e.g. the matrix pointer isn't checked for NULLness). That's an exercise for the student.
Fifthly, I've fixed your random number usage - after a fashion. Another exercise for the student: why is the way I did it not good practice?
However - all of this is moot. You need to get yourself a good C textbook, or a good online course, and work through the examples. The code you've given here shows that you're punching above your weight at the moment, and you need to develop some more C muscles before going into that ring!
In relation to your question about "variable sized arrays", you could have something like:
/* can stick this into your struct, this is just an example */
size_t rows, cols;
long **matrix;
/* set the values of rows, cols */
/* create the "array" of rows (array of pointers to longs) */
matrix = (long**)malloc(rows * sizeof(long*));
/* create the array of columns (array of longs at each row) */
for (i = 0; i < rows; i++)
matrix[i] = (long*)malloc(cols * sizeof(long));
/* ... */
/* free the memory at the end */
for (i = 0; i < rows; i++)
free(matrix[i]);
free(matrix);
Then you can just access the dynamically allocated matrix similar to any other array of arrays.
ie. to set element at the first row (row 0) and fourth column (column 3) to 5:
matrix[0][3] = 5;

Resources