-1

Is it possible to make an array of a variable number of dimensions? That is, the number of dimensions would be specified at runtime. If yes, then how to do it?

Note that I am talking about a variable number of dimensions, not variable length of an array.

Gravemind
  • 15
  • 3
  • `malloc` what you need, and work with `void *` or `void **` till you need something else. Or, make a 1-dimensional array, and a function that translates n-dimensional coordinates into 1-dimensional index. – Amadan Sep 06 '18 at 07:45
  • https://stackoverflow.com/questions/14075194/variable-length-arrays-vla-in-c-and-c – KBlr Sep 06 '18 at 07:46
  • 2
    Most things are possible in C, but I don't really see the use for it. It rather sounds like you should use a tree or linked list etc. What is the actual problem you are trying to solve? – Lundin Sep 06 '18 at 07:49
  • Well the actual problem was that of giving change to (variable number of) passengers of a flight in the best possible way (using least number of notes), the number and value of denominations being variable. There is a way to do it without using variable dimensional arrays, but I figured out that it would be much faster and efficient to do it this way. So I wanted to know if it was possible. – Gravemind Sep 06 '18 at 07:57
  • Possible duplicate of [Variable length arrays (VLA) in C and C++](https://stackoverflow.com/questions/14075194/variable-length-arrays-vla-in-c-and-c) – Rizwan Sep 06 '18 at 08:02
  • 2
    @Rizwan: This question is not a duplicate of that question. This question asks about a variable number of dimensions. That question asks about a dimension of variable length. – Eric Postpischil Sep 06 '18 at 10:43
  • Thats right. How to revoke the flag of duplicate ? just deleting my comment will do ? – Rizwan Sep 06 '18 at 10:44
  • @Gravemind Simply use a 1D array, or if the look-up part is the problem, use a suitable container such as a hash table. – Lundin Sep 06 '18 at 11:13

1 Answers1

1

Sure. Just write your own library to handle that:

#include <stdio.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>

struct arrnd_s {
    void *memory;
    size_t membsize;
    size_t *dims;
    size_t dimcnt;
};

static inline size_t _arrnd_arraysize(struct arrnd_s *t)
{
    size_t ret = 1;
    for (size_t i = 0; i < t->dimcnt; ++i) {
        ret *= t->dims[i];
    }
    return ret;
}

struct arrnd_s *arrnd_new(size_t membsize, size_t dimcnt, ...)
{
    struct arrnd_s *t = malloc(sizeof(*t));
    if (t == NULL) {
        goto T_MALLOC_ERR;
    }
    t->dims = malloc(dimcnt * sizeof(*t->dims));
    if (t->dims == NULL) {
        goto T_DIMS_ERR;
    }

    va_list va;
    va_start(va, dimcnt);
    for (size_t i = 0; i < dimcnt; ++i) {
        t->dims[i] = va_arg(va, size_t);
    }
    va_end(va);

    t->dimcnt = dimcnt;
    t->memory = malloc(_arrnd_arraysize(t) * membsize);
    if (t->memory == NULL) {
        goto T_MEMORY_ERR;
    }
    t->membsize = membsize;

    return t;

    T_MEMORY_ERR:
    free(t->dims);
    T_DIMS_ERR:
    free(t);
    T_MALLOC_ERR:
    return NULL;
}

void arrnd_free(const struct arrnd_s *t)
{
    assert(t != NULL);
    free(t->memory);
    free(t->dims);
    free((void*)t);
}

size_t arrnd_arraysize(struct arrnd_s *t)
{
    assert(t != NULL);
    assert(t->dims != NULL);
    assert(t->dimcnt >= 1);
    return _arrnd_arraysize(t);
}

size_t arrnd_getdim(struct arrnd_s *t, size_t dimpos)
{
    assert(t != NULL);
    assert(t->dims != NULL);
    assert(t->dimcnt >= 1);
    assert(dimpos < t->dimcnt);
    return t->dims[dimpos];
}

void *arrnd_getpnt_v(struct arrnd_s *t, va_list va)
{
    assert(t != NULL);
    assert(t->dims != NULL);
    assert(t->dimcnt >= 1);
    size_t pos = 0;
    for (size_t i = 0; i < t->dimcnt; ++i) {
        const size_t dim = va_arg(va, size_t);
        pos += dim;
        if (i != t->dimcnt - 1) {
            pos *= t->dims[i];
        }
    }
    return &((char*)t->memory)[pos * t->membsize];
}

void *arrnd_getpnt(struct arrnd_s *t, ...)
{
    va_list va;
    va_start(va, t);
    void * const ret = arrnd_getpnt_v(t, va);
    va_end(va);
    return ret;
}

int main() 
{

    struct arrnd_s *arrnd = arrnd_new(sizeof(int), 4, 2, 4, 4, 8);
    assert(arrnd != NULL);
    assert(arrnd_arraysize(arrnd) == 2 * 4 * 4 * 8);


    for (size_t i = 0; i < arrnd_getdim(arrnd, 0); ++i) {
        for (size_t j = 0; j < arrnd_getdim(arrnd, 1); ++j) {
            for (size_t k = 0; k < arrnd_getdim(arrnd, 2); ++k) {
                for (size_t l = 0; l < arrnd_getdim(arrnd, 3); ++l) {
                    *(int*)arrnd_getpnt(arrnd, i, j, k, l) = i + j + k + l;
                }
            }
        }
    }

    for (size_t i = 0; i < arrnd_getdim(arrnd, 0); ++i) {
        for (size_t j = 0; j < arrnd_getdim(arrnd, 1); ++j) {
            for (size_t k = 0; k < arrnd_getdim(arrnd, 2); ++k) {
                for (size_t l = 0; l < arrnd_getdim(arrnd, 3); ++l) {
                    printf("[%zu][%zu][%zu][%zu] = %d\n", i, j, k, l, *(int*)arrnd_getpnt(arrnd, i, j, k, l));
                }
            }
        }
    }

    arrnd_free(arrnd);

    return 0;
}

As a side note, the follwing is something I always considered cool in C, but this is compile time, not runtime:

int main() {
    int memory[256];
    for (size_t i = 0; i < sizeof(memory)/sizeof(*memory); ++i) {
        memory[i] = i;
    }


    int *arr1d = (void*)memory;
    printf("1d[%d] = %d == %d\n", 1, arr1d[1], memory[1]);

    int (*arr2d)[16] = (void*)memory;
    printf("2d[%d][%d] = %d == %d\n", 2, 2, arr2d[2][2], memory[2 * 16 + 2]);

    int (*arr3d)[8][8] = (void*)memory;
    printf("3d[%d][%d][%d] = %d == %d\n", 2, 2, 2, arr3d[2][2][2], memory[(2 * 8 + 2) * 8 + 2]);

    int (*arr4d)[4][4][4] = (void*)memory;
    printf("4d[%d][%d][%d][%d] = %d == %d\n", 2, 2, 2, 2, arr4d[2][2][2][2], memory[((2 * 4 + 2) * 4 + 2) * 4 + 2]);

    int (*arr5d)[2][2][2][2] = (void*)memory;
    printf("5d[%d][%d][%d][%d][%d] = %d == %d\n", 1, 1, 1, 1, 1, arr5d[1][1][1][1][1], memory[(((1 * 2 + 1) * 2 + 1) * 2 + 1) * 2 + 1]);

    return 0;
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111