I. Ahhoz, hogy a tömb egyben ábrázolható legyen egyáltalán, a méretének kifejezhetőnek kell lennie size_t-ben. Ezért size_t-ben összeszoroznám a dimenziók szerinti méreteket, egyben allokálnám, és az indexeléshez kézzel szoroznék.
Itt további kérdés, hogy a dimenziók darabszáma fix-e, vagy az is dinamikus. Ebben a Usenet post-omban (*) leírok egy módszert, amivel egy K dimenziós tömböt N db közel egyenlő részre lehet szétosztani (N db thread általi párhuzamos bejárásra) -- a most éppen érdekes szorzás a
get_maxflat()
függvényben van.
(*)
Message-ID: <Pine.LNX.4.64.1009062343000.32316@login03.caesar.elte.hu>
II. C99-ben lehet VLA-kat is használni (típusdefinícióra is), csak annak az a baja, hogy a függvény hatásköréből (scope) maga a típus nem tud kijönni. Ilyenkor a (void *)-ot oda-vissza kell cast-olni ugyanerre a (pointer-to-VLA) típusra, ahol csak használni akarjuk, ami elég nyűg, és könnyen el lehet rontani.
/* gcc -o vla -std=c99 -pedantic -Wall -Wextra vla.c */
#include <stdlib.h>
#include <stdio.h>
struct ia3d
{
size_t dim0,
dim1,
dim2;
void *arrptr;
};
static int
ia3d_init(struct ia3d *ia3d, size_t dim0, size_t dim1, size_t dim2)
{
/* Check for expressibility of full size in bytes. */
if (0u < dim0 && 0u < dim1 && 0u < dim2
&& dim0 <= (size_t)-1 / dim1
&& dim0 * dim1 <= (size_t)-1 / dim2
&& dim0 * dim1 * dim2 <= (size_t)-1 / sizeof(int)) {
int (*tmp)[dim0][dim1][dim2];
tmp = malloc(sizeof *tmp);
if (0 != tmp) {
ia3d->dim0 = dim0;
ia3d->dim1 = dim1;
ia3d->dim2 = dim2;
ia3d->arrptr = tmp;
return 0;
}
}
return -1;
}
static void
ia3d_uninit(struct ia3d *ia3d)
{
free(ia3d->arrptr);
}
static inline int *
ia3d_ref(struct ia3d *ia3d, size_t ofs0, size_t ofs1, size_t ofs2)
{
return &(
*(int (*)[ia3d->dim0][ia3d->dim1][ia3d->dim2])ia3d->arrptr
)[ofs0][ofs1][ofs2];
}
int
main(void)
{
int ret;
struct ia3d my;
ret = EXIT_FAILURE;
if (0 == ia3d_init(&my, 3u, 4u, 5u)) {
size_t ofs0,
ofs1,
ofs2;
/* populate */
{
int i;
i = 0;
for (ofs0 = 0u; ofs0 < my.dim0; ++ofs0) {
for (ofs1 = 0u; ofs1 < my.dim1; ++ofs1) {
for (ofs2 = 0u; ofs2 < my.dim2; ++ofs2) {
*ia3d_ref(&my, ofs0, ofs1, ofs2) = i++;
}
}
}
}
/* use */
for (ofs0 = 0u; ofs0 < my.dim0; ++ofs0) {
(void)fprintf(stdout, 0u == ofs0 ? "" : "\n");
for (ofs1 = 0u; ofs1 < my.dim1; ++ofs1) {
for (ofs2 = 0u; ofs2 < my.dim2; ++ofs2) {
(void)fprintf(stdout, "%s%2d", 0u == ofs2 ? "" : " ",
*ia3d_ref(&my, ofs0, ofs1, ofs2));
}
(void)fprintf(stdout, "\n");
}
}
/* done */
ret = EXIT_SUCCESS;
/* cleanup */
ia3d_uninit(&my);
}
return ret;
}
Ennyi erővel szerintem jobb szorozni (size_t túlcsordulást szintén ellenőrizve a kezdeti allokációnál, amikor meghatározzuk a teljes elemszámot ill. a teljes méretet byte-ban -- ezt a Usenet post-omban elhanyagoltam). Ráadásul az megy C89-ben is.
III. A kérdésed egyébként egy gyakori C kérdés (C-FAQ 6.16).