Malloc в C, но используйте синтаксис многомерного массива
Есть ли способ malloc большого массива, но ссылайтесь на него с помощью синтаксиса 2D? Мне нужно что-то вроде:
int *memory = (int *)malloc(sizeof(int)*400*200);
int MAGICVAR = ...;
MAGICVAR[20][10] = 3; //sets the (200*20 + 10)th element
ОБНОВЛЕНИЕ: Это было важно отметить: я просто хочу иметь один непрерывный блок памяти. Я просто не хочу писать макрос вроде:
#define INDX(a,b) (a*200+b);
а затем обратитесь к моему блобу:
memory[INDX(a,b)];
Я бы предпочел:
memory[a][b];
UPDATE: Я понимаю, что компилятор не знает, как есть. Я бы хотел предоставить дополнительную информацию, например:
int *MAGICVAR[][200] = memory;
Не существует ли такого синтаксиса? Обратите внимание, что я не просто использую массив фиксированной ширины, так это то, что он слишком велик для размещения в стеке.
UPDATE: Хорошо, ребята, я могу это сделать:
void toldyou(char MAGICVAR[][286][5]) {
//use MAGICVAR
}
//from another function:
char *memory = (char *)malloc(sizeof(char)*1820*286*5);
fool(memory);
Я получаю предупреждение, passing arg 1 of toldyou from incompatible pointer type
, но код работает, и я проверял, что доступны те же адреса. Есть ли способ сделать это без использования другой функции?
Ответы
Ответ 1
Да, вы можете это сделать, и нет, вам не нужен другой массив указателей, как большинство других ответов говорят вам. Вы можете просто вызвать вызов:
int (*MAGICVAR)[200] = malloc(400 * sizeof *MAGICVAR);
MAGICVAR[20][10] = 3; // sets the (200*20 + 10)th element
Если вы хотите объявить функцию, возвращающую такой указатель, вы можете сделать это следующим образом:
int (*func(void))[200]
{
int (*MAGICVAR)[200] = malloc(400 * sizeof *MAGICVAR);
MAGICVAR[20][10] = 3;
return MAGICVAR;
}
Или используйте typedef, что делает его более понятным:
typedef int (*arrayptr)[200];
arrayptr function(void)
{
/* ... */
Ответ 2
Используйте указатель на массивы:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int (*arr)[10];
arr = malloc(10*10*sizeof(int));
for (int i = 0; i < 10; i++)
for(int j = 0; j < 10; j++)
arr[i][j] = i*j;
for (int i = 0; i < 10; i++)
for(int j = 0; j < 10; j++)
printf("%d\n", arr[i][j]);
free(arr);
return 0;
}
Ответ 3
Если дополнительная косвенность не вызывает беспокойства, вы можете использовать массив указателей.
Edit
Здесь вариант ответа @Platinum Azure, который не вызывает столько звонков в malloc. Помимо более быстрого распределения, все элементы гарантированно смежны:
#define ROWS 400
#define COLS 200
int **memory = malloc(ROWS * sizeof(*memory));
int *arr = malloc(ROWS * COLS * sizeof(int));
int i;
for (i = 0; i < ROWS; ++i)
{
memory[i] = &arr[i * COLS];
}
memory[20][10] = 3;
Ответ 4
#define ROWS 400
#define index_array_2d(a,i,j) (a)[(i)*ROWS + (j)]
...
index_array_2d( memory, 20, 10 ) = -1;
int x = index_array_2d( memory, 20, 10 );
Edit:
Массивы и указатели выглядят одинаково, но компилятор трактует их очень по-разному. Посмотрим, что нужно сделать для индексации массива и удаления ссылки со указателем со смещением:
-
Скажем, мы объявили статический массив (массив в стеке немного сложнее, фиксированное смещение от регистра, но по существу то же самое):
static int array[10];
-
И указатель:
static int* pointer;
-
Затем мы отклоняем каждый из них следующим образом:
x = array[i];
x = pointer[i];
Следует отметить, что адрес начала array
, а также адрес pointer
(а не его содержимое) фиксируются по времени ссылки/загрузки. Затем компилятор выполняет следующие действия:
- Для
array
de-reference:
- загружает значение
i
,
- добавляет его к значению
array
, то есть его фиксированному адресу, чтобы сформировать адрес целевой памяти,
- загружает значение из вычисленного адреса
- Для
pointer
de-reference:
- загружает значение
i
,
- загружает значение
pointer
, то есть содержимое по его адресу,
- добавляет два значения для формирования эффективного адреса
- загружает значение из вычисленного адреса.
То же самое происходит для 2D-массива с дополнительными шагами по загрузке второго индекса и умножением его на размер строки (который является константой). Все это решается во время компиляции, и нет способа заменить его для другого во время выполнения.
Edit:
@caf здесь имеет правильное решение. Там законный способ внутри языка индексировать указатель как двухмерный массив в конце концов.
Ответ 5
В том же духе, что и Cogwheel, здесь (несколько грязный) трюк, который делает только один вызов malloc()
:
#define ROWS 400
#define COLS 200
int** array = malloc(ROWS * sizeof(int*) + ROWS * COLS * sizeof(int));
int i;
for (i = 0; i < ROWS; ++i)
array[i] = (int*)(array + ROWS) + (i * COLS);
Это заполняет первую часть буфера указателями на каждую строку в следующих данных непрерывного массива.
Ответ 6
Компилятор и среда выполнения не имеют возможности знать ваши предполагаемые емкости измерений только с умножением в вызове malloc.
Для достижения двух индексов вам нужно использовать двойной указатель. Что-то вроде этого должно это сделать:
#define ROWS 400
#define COLS 200
int **memory = malloc(ROWS * sizeof(*memory));
int i;
for (i = 0; i < ROWS; ++i)
{
memory[i] = malloc(COLS * sizeof(*memory[i]);
}
memory[20][10] = 3;
Убедитесь, что вы указали все возвращаемые значения malloc для возврата NULL, что указывает на отказ в распределении памяти.
Ответ 7
int** memory = malloc(sizeof(*memory)*400);
for (int i=0 ; i < 400 ; i++)
{
memory[i] = malloc(sizeof(int)*200);
}
Ответ 8
Работая с ответами Тима и кафе, я оставлю это здесь для потомков:
#include <stdio.h>
#include <stdlib.h>
void Test0() {
int c, i, j, n, r;
int (*m)[ 3 ];
r = 2;
c = 3;
m = malloc( r * c * sizeof(int) );
for ( i = n = 0; i < r; ++i ) {
for ( j = 0; j < c; ++j ) {
m[ i ][ j ] = n++;
printf( "m[ %d ][ %d ] == %d\n", i, j, m[ i ][ j ] );
}
}
free( m );
}
void Test1( int r, int c ) {
int i, j, n;
int (*m)[ c ];
m = malloc( r * c * sizeof(int) );
for ( i = n = 0; i < r; ++i ) {
for ( j = 0; j < c; ++j ) {
m[ i ][ j ] = n++;
printf( "m[ %d ][ %d ] == %d\n", i, j, m[ i ][ j ] );
}
}
free( m );
}
void Test2( int r, int c ) {
int i, j, n;
typedef struct _M {
int rows;
int cols;
int (*matrix)[ 0 ];
} M;
M * m;
m = malloc( sizeof(M) + r * c * sizeof(int) );
m->rows = r;
m->cols = c;
int (*mp)[ m->cols ] = (int (*)[ m->cols ]) &m->matrix;
for ( i = n = 0; i < r; ++i ) {
for ( j = 0; j < c; ++j ) {
mp[ i ][ j ] = n++;
printf( "m->matrix[ %d ][ %d ] == %d\n", i, j, mp[ i ][ j ] );
}
}
free( m );
}
int main( int argc, const char * argv[] ) {
int cols, rows;
rows = 2;
cols = 3;
Test0();
Test1( rows, cols );
Test2( rows, cols );
return 0;
}