Как создать многомерный массив? - C (СИ)
Формулировка задачи:
Подскажите, пожалуйста, возможно ли задать многомерный массив в С, если заранее (на момент написания кода) не известно точное число количества мер? Может, как-то возможно реализовать через указатели или там массивы указателей?
Решение задачи: «Как создать многомерный массив?»
textual
Листинг программы
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct md_array
{
unsigned rank;
unsigned *dimensions;
int *data;
};
unsigned num_elements(unsigned rank, unsigned *dimensions)
{
unsigned num = 1, i;
for(i = 0; i < rank; ++i)
num *= dimensions[i];
return num;
}
struct md_array *make_md_array(unsigned rank, unsigned *dimensions)
{
struct md_array *array = malloc(sizeof *array);
if(array == NULL)
goto err_ret;
array->dimensions = malloc(rank * sizeof *dimensions);
if(array->dimensions == NULL)
goto free_array;
array->data = malloc(num_elements(rank, dimensions) * sizeof *(array->data));
if(array->data == NULL)
goto free_dimensions;
array->rank = rank;
memcpy(array->dimensions, dimensions, rank * sizeof *dimensions);
return array;
free_dimensions:
free(array->dimensions);
free_array:
free(array);
err_ret:
return NULL;
}
unsigned calculate_offset(unsigned rank, unsigned *dimensions, unsigned *indices)
{
unsigned offset = 0, i, last_dim = 1;
for(i = 0; i < rank; ++i)
{
offset = offset * last_dim + indices[i];
last_dim = dimensions[i];
}
return offset;
}
int *get_item(struct md_array *array, unsigned *indices)
{
return &(array->data[calculate_offset(array->rank, array->dimensions, indices)]);
}
void destroy_md_array(struct md_array *array)
{
free(array->data);
free(array->dimensions);
free(array);
}
typedef int (*MD_ARRAY_FUN)(struct md_array *, unsigned *);
int gen_walk(struct md_array *array, MD_ARRAY_FUN fun, unsigned *indices, unsigned curr_dim)
{
if(curr_dim >= array->rank)
return fun(array, indices);
for(indices[curr_dim] = 0; indices[curr_dim] < array->dimensions[curr_dim]; ++indices[curr_dim])
if(gen_walk(array, fun, indices, curr_dim + 1) == 0)
return 0;
return 1;
}
int walk_md_array(struct md_array *array, MD_ARRAY_FUN fun)
{
int ret;
unsigned *indices = calloc(array->rank, sizeof *indices);
if(indices == NULL)
return 0;
ret = gen_walk(array, fun, indices, 0);
free(indices);
return ret;
}
void print_indices(unsigned count, unsigned *indices)
{
unsigned i;
for(i = 0; i < count; ++i)
printf("[%u]", indices[i]);
}
int read_array(struct md_array *array, unsigned *indices)
{
printf("ARRAY");
print_indices(array->rank, indices);
printf(": ");
fflush(stdout);
if(scanf("%d", get_item(array, indices)) != 1)
{
perror("scanf");
return 0;
}
return 1;
}
int print_array(struct md_array *array, unsigned *indices)
{
printf("ARRAY");
print_indices(array->rank, indices);
printf(" = %d\n", *get_item(array, indices));
return 1;
}
int main(void)
{
unsigned rank, i;
unsigned *dimensions;
struct md_array *array;
int ret = EXIT_FAILURE;
printf("Rank: ");
fflush(stdout);
scanf("%u", &rank);
dimensions = malloc(rank * sizeof *dimensions);
if(dimensions == NULL)
{
perror("malloc");
goto err_ret;
}
for(i = 0; i < rank; ++i)
{
printf("Dim #%u: ", i);
fflush(stdout);
scanf("%u", &dimensions[i]);
}
array = make_md_array(rank, dimensions);
if(array == NULL)
{
perror("make_md_array");
goto free_dimensions;
}
puts("Enter array:");
if(walk_md_array(array, read_array) == 0)
goto free_array;
puts("Got array:");
if(walk_md_array(array, print_array) == 0)
goto free_array;
ret = EXIT_SUCCESS;
free_array:
destroy_md_array(array);
free_dimensions:
free(dimensions);
err_ret:
exit(ret);
}
Объяснение кода листинга программы
В этом коде создается многомерный массив, используя динамическое выделение памяти. Сначала определяются структура и функции для работы с многомерным массивом:
struct md_array- структура, представляющая многомерный массив. Она содержит поляrank(количество измерений),dimensions(массив размеров каждого измерения) иdata(массив данных).num_elements(unsigned rank, unsigned *dimensions)- функция для вычисления общего количества элементов в многомерном массиве.make_md_array(unsigned rank, unsigned *dimensions)- функция для создания нового экземпляра многомерного массива. Она выделяет память для структуры и ее компонентов, а затем заполняет поля структуры.calculate_offset(unsigned rank, unsigned *dimensions, unsigned *indices)- функция для вычисления смещения элемента в многомерном массиве относительно начала массива.get_item(struct md_array *array, unsigned *indices)- функция для получения указателя на элемент многомерного массива по индексам.destroy_md_array(struct md_array *array)- функция для освобождения памяти, выделенной под многомерный массив.gen_walk(struct md_array *array, MD_ARRAY_FUN fun, unsigned *indices, unsigned curr_dim)- рекурсивная функция для обхода всех элементов многомерного массива в заданном порядке.walk_md_array(struct md_array *array, MD_ARRAY_FUN fun)- функция для обхода всех элементов многомерного массива с использованием функцииfunдля каждого элемента.print_indices(unsigned count, unsigned *indices)- функция для печати индексов многомерного массива.read_array(struct md_array *array, unsigned *indices)- функция для чтения значения элемента многомерного массива по индексам.print_array(struct md_array *array, unsigned *indices)- функция для печати значения элемента многомерного массива по индексам. Затем в функцииmain()создается многомерный массив с помощью функцийmake_md_array()иwalk_md_array(). Пользователю предлагается ввести значения массива, и после ввода всех значений они выводятся на экран.