Матрица переменного размера в C - PullRequest
0 голосов
/ 30 октября 2009

Есть ли способ создать массив с двойным скриптом переменного размера (не C ++, а только C)? Я знаю, что для создания массива с одиночным сценарием переменного размера вы просто используете указатель, например

float *array;
array = (float *) calloc(sizeof(float), n);

создает массив с плавающей запятой размером n. Есть ли что-то подобное, что я могу сделать для массивов с двойным сценарием?

Ответы [ 7 ]

10 голосов
/ 30 октября 2009

В C нет двойных скриптов; Есть только массивы массивов. Например. это:

int a[3][3];

Должен читаться как «массив из 3 массивов по 3 дюйма», а не как «массив из 3х3 дюйма». Это сразу видно по типам выражений - например, a[0] является допустимым выражением, и его тип int[3].

Для типов массивов размер массива является частью типа и поэтому должен быть известен во время компиляции. Поэтому, хотя вы можете иметь тип «указатель на массивы», чтобы сделать одно измерение динамическим, оставшиеся все равно должны быть исправлены:

int (*p)[3] // pointer to arrays of 3 ints each

Существует два традиционных обходных пути:

  1. Просто используйте одномерный динамический массив из элементов width x height и рассчитайте 1D-индексы из 2D-координат как (y * width + x) самостоятельно.

  2. Использовать указатель на указатели:

    int** a = malloc(sizeof(int*) * height);
    for (i = 0; i < height; ++i) a[i] = malloc(sizeof(int) * width);
    a[0][0] = 123;
    ...
    

    Проблема в том, что ваш массив больше не должен быть прямоугольным, и вы не можете его принудительно применить. С точки зрения производительности это также хуже, чем один непрерывный блок памяти.

В C99 вы также можете использовать массивы переменной длины:

void foo(int width, int height) {
    int a[width][height];
    ...
}
6 голосов
/ 30 октября 2009

FAQ по comp.lang.c имеет хороший раздел на эту тему.

5 голосов
/ 30 октября 2009

Вы можете сделать почти то же самое для многомерных массивов.

float **array;
array = calloc(sizeof(float*), n);
for(int i = 0; i < n; i++)
{
    array[i] = calloc(sizeof(float), n);
}
4 голосов
/ 30 октября 2009

Если вам нужна матрица с n строками и m столбцами, вы можете использовать линейный массив длины m*n, чтобы представить это, где каждый индекс i представляет

row = i  / n
col = i  % n

и обратное отображение

i  = row * n  + col

Большинство пакетов алгебры, которые используют такие матрицы, как matlab, на самом деле используют это представление, потому что оно хорошо обобщается на любое измерение (вы также можете обобщить это на 3-мерную матрицу).

2 голосов
/ 30 октября 2009

Нет, это невозможно. В качестве альтернативы выделите один массив и определите функцию индексации, которая берет вашу координату и возвращает индекс в массив.

int Index(int i, int j, int numCols)
{ 
    return i * numCols + j;
}

int numRows = 100;
int numCols = 200;

float *data = malloc(sizeof(float) * numRows * numCols);

data[Index(34, 56, numCols)] = 42.0f;
1 голос
/ 31 октября 2009

Я удивлен, что никто не указал на «очевидную» альтернативу, которая сохраняет единственное смежное распределение для основной матрицы, но имеет вектор указателей для двойной подписки. (Я полагаю, это означает, что это не очевидно, в конце концов.)

float **array2d = malloc(sizeof(*array2d) * height);
float  *array1d = malloc(sizeof(*array1d) * height * width);

for (i = 0; i < height; ++i)
    array2d[i] = &array1d[i * width];

Теперь вы можете написать 2-D доступ к массиву как обычно:

array2d[0][0] = 123.0;

Очевидно, нам также нужно проверить распределение памяти.

1 голос
/ 30 октября 2009

Вы можете использовать массивы переменной длины C99 (работает с gcc):

#include <stdio.h>
#include <stdlib.h>

void foo(size_t rows, size_t cols, float array[rows][cols])
{
    printf("%f\n", array[2][3]);
}

int main(void)
{
    size_t rows = 4;
    size_t cols = 5;
    float (*array)[cols] = calloc(sizeof (float), rows * cols);
    array[2][3] = 42;
    foo(rows, cols, array);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...