Кучи выделяют 2D массив (не массив указателей)

Я пишу код C, и я хотел бы выделить кучу 512 * 256 байт. Для собственного удобства я хотел бы иметь возможность доступа к элементам с помощью синтаксического массива [a] [b]; нет арифметики, чтобы найти правильный индекс.

Каждое учебное пособие, которое я вижу в Интернете, говорит мне о создании массива указателей, которые указывают на массивы строк, которые я хочу в моем массиве. Это означает, что каждый подмассив должен быть malloc 'd и свободным' d индивидуально. Меня интересует решение, которое требует только одного вызова malloc и одного вызова free. (Таким образом, все элементы являются смежными). Я думаю, что это возможно, потому что я не буду создавать зубчатый массив.

Буду признателен, если кто-нибудь сможет поделиться синтаксисом для объявления такого массива.

 Richard J. Ross III12 апр. 2012 г., 03:59
@EdS. в то время как вы можете предпочесть C, C ++ лучше во многих ситуациях, и это будет одна из них. Я оставил это как комментарий просто, чтобы определить, будет ли это вариант.
 R..12 апр. 2012 г., 04:40
Смотри мой ответ; в отличие от других, он на самом деле делает то, что вы просите.
 Ed S.12 апр. 2012 г., 04:07
@ RichardJ.RossIII: C ++ лучше для размещения 2d массива? да? Я так не думаю, это легко выполнимо в C, перегрузка оператора C ++ не требуется.
 Richard J. Ross III12 апр. 2012 г., 03:50
C ++ вариант? Вы можете создать простые объекты C ++, которые перегружают оператор индексации.
 Ed S.12 апр. 2012 г., 03:56
@ RichardJ.RossIII: действительно ли это правильный ответ на вопрос "как мне это сделать на языке C?" (понимая, что тыdid оставьте это как комментарий). Я возьму C над C ++ в любой день, спасибо.

Ответы на вопрос(6)

typedef это, и сделать указатель на него. Вот короткий фрагмент, демонстрирующий это использование:

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

typedef int array2d[20][20];

int main() {
    int i,j;
    array2d *a = malloc(sizeof(array2d));
    for(i=0;i!=20;i++)
        for(j=0;j!=20;j++)
            (*a)[i][j] = i + j;

    for(i=0;i!=20;i++)
        for(j=0;j!=20;j++)
            printf("%d ",(*a)[i][j]);
    free(a);
    return 0;
}
 12 апр. 2012 г., 04:05
@ RichardJ.RossIII К сожалению, это не работает с массивами динамического размера, потому что для typedef нужны константы времени компиляции для обоих измерений. Лучшее, что вы можете сделать, - это сделать одно измерение фиксированным, а другое динамическим, но это не сделает его полностью динамическим.
 12 апр. 2012 г., 04:02
Интересное решение, есть ли способ, которым вы могли бы выяснить, как сделать это с динамическим массивом?
 12 апр. 2012 г., 04:49
Typedef не нужен и фактически вредно помещать оба измерения в typedef, так как вы застряли, используя(*a) повсюду, а не простоa, Если вы просто укажите количество столбцов, это будет работать намного лучше. И, конечно же, с C99 вы можете сделать тип изменяемым; Я считаю, что это даже допустимо в typedef, если у typedef есть область блока, а не область файла.

free, но это позволяетarray[a][b] синтаксис стиля и является смежным.

char **array = malloc(512 * sizeof(char *));
array[0] = malloc(512*256);
for (int i = 1; i < 512; i++)
    array[i] = array[0] + (256 * i);

Увидетьarray2 здесь для получения дополнительной информации:http://c-faq.com/aryptr/dynmuldimary.html

 12 апр. 2012 г., 06:27
Это не двумерный массив, а массив указателей. У него есть некоторые преимущества (вы можете переставлять строки в O (1) вместо O (cols)) и другие недостатки (каждый доступ более дорогой, поскольку он проходит через дополнительный уровень косвенности; он требует больше памяти и т. Д.). В любом случае, если вы воспользуетесь этим подходом, рассмотрите предложение Зака использовать только одинmalloc, Это упрощает обработку ошибок (без частичной ошибки при очистке) и обеспечивает локальность памяти.
 12 апр. 2012 г., 03:53
Это хороший трюк! +1
 12 апр. 2012 г., 03:55
Вы можете объединить два распределения, поместив блок данных сразу после вектора допинга. Требуется определенное количество типографских вставок, но это не так сложно. Тем не менее, ваш код, как показано, имеет серьезную ошибку: вы выделяете место для 512charс, а затем вы рассматриваете это как достаточно места для 512char *s. Это почти гарантированно уйдет с конца распределения и сбоя.
 12 апр. 2012 г., 04:01
Ой опечатка, это должно сделать это ...
Решение Вопроса

если вы хотите выделить массив типа, вы назначаете его в указатель этого типа.

Поскольку двумерные массивы являются массивами массивов (в вашем случае это массив из 512 массивов по 256 символов), вы должны назначить его в указатель на массив из 256 символов:

char (*arr)[256]=malloc(512*256);
//Now, you can, for example:
arr[500][200]=75;

(Скобки вокруг*arr сделать его указателем на массив, а не на массив указателей)

 12 апр. 2012 г., 04:50
+1, почему-то мне не хватало того, что вы опубликовали это, пока я писал свой ответ. :-)
 12 апр. 2012 г., 10:59
Обратите внимание, что начиная с C99 размеры больше не должны быть известны во время компиляции. Вы можете иметьn,m читать со стандартного ввода и объявитьchar arr[n][m] или, в этом случае,char (*arr)[n].
 Paul12 апр. 2012 г., 10:21
Это именно то, что я искал. Спасибо.

если предположить, что вам не нужна совместимость с древним стандартом C89 (среди современных компиляторов C только обратная версия - только MSVC и несколько компиляторов со встроенными целевыми объектами). Вот как вы это делаете:

int (*array)[cols] = malloc(rows * sizeof *array);

затемarray[a][b] действует для любогоa в[0,rows) а такжеb в[0,cols).

На языке стандарта С,array имеетvariably-modified type, Если вы хотите передать указатель на другие функции, вам нужно будет повторить этот тип в списке аргументов функции и убедиться, что по крайней мере количество столбцов передано функции (поскольку это необходимо как часть переменной). модифицированный тип).

Edit: Я упустил тот факт, что OP заботится только о фиксированном размере, 512x256. В этом случае C89 будет достаточно, и все, что вам нужно, это:

int (*array)[256] = malloc(512 * sizeof *array);

Точно такой же тип может быть использован в списках аргументов функции, если вам нужно передать указатель между функциями (а также как тип, возвращаемый функцией, но для этого использования вы можете захотеть определить его ... :-)

 Paul16 апр. 2012 г., 18:43
На самом деле, этот ответ отличный. Хотя сейчас мне нужно только 512 * 256, я мог легко увидеть, как это требование изменится в будущем.
 05 янв. 2016 г., 02:15
@sacheie: звонить можно толькоfree ровно один раз для каждогоmalloc; это всегда правдаarray это не массив указателей, а массив массивов. каждыйarray[i] decays указатель на его первый элемент, ноarray[i] is массив.
 12 апр. 2012 г., 04:44
Действительно, тогда я обновлю ответ.
 04 янв. 2016 г., 21:25
Мне нравится общий подход к делу, но я не смог понять одну вещь. Требуется ли по-прежнему циклически проходить через внешний массив, чтобы освободить все внутренние указатели? Или требуется только один вызов free ()?
 12 апр. 2012 г., 04:43
Вы правы в общем случае, но ОП хочет только 512 * 256 массивов.

Этоis можно динамически выделять один и тот же вид многомерного массива, который

static char x[512][256];

дает, но это довольно сложно из-за распада типа. Я только знаю, как это сделать сtypedef:

typedef char row[512];
row *x = malloc(sizeof(row) * 256);

Это позволяет только определить размер второго измерения во время выполнения. Если оба измерения могут изменяться во время выполнения, вам нужен допинг-вектор.

 12 апр. 2012 г., 04:51
Скучал по этому тоже. Обратите внимание, что если вы не ограничены C89, оба размера могут изменяться; вам просто нужно использовать переменно-модифицированный тип указателя.

struct тип, который содержит массив 521x256, а затем динамически выделитьstruct.

Ваш ответ на вопрос