Переменные размерные массивы в C - PullRequest
0 голосов
/ 06 сентября 2018

Можно ли сделать массив с переменным числом измерений? То есть количество измерений будет указано во время выполнения. Если да, то как это сделать?

Обратите внимание, что я имею в виду переменное количество измерений, а не переменную длину массива.

1 Ответ

0 голосов
/ 06 сентября 2018

Конечно. Просто напишите свою собственную библиотеку, чтобы справиться с этим:

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

Как примечание: в C я всегда считал это классным, но это время компиляции, а не времени выполнения:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...