可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is there any way to malloc a large array, but refer to it with 2D syntax? I want something like:
int *memory = (int *)malloc(sizeof(int)*400*200);
int MAGICVAR = ...;
MAGICVAR[20][10] = 3; //sets the (200*20 + 10)th element
UPDATE: This was important to mention: I just want to have one contiguous block of memory. I just don't want to write a macro like:
#define INDX(a,b) (a*200+b);
and then refer to my blob like:
memory[INDX(a,b)];
I'd much prefer:
memory[a][b];
UPDATE: I understand the compiler has no way of knowing as-is. I'd be willing to supply extra information, something like:
int *MAGICVAR[][200] = memory;
Does no syntax like this exist? Note the reason I don't just use a fixed width array is that it is too big to place on the stack.
UPDATE: OK guys, I can do this:
void toldyou(char MAGICVAR[][286][5]) {
//use MAGICVAR
}
//from another function:
char *memory = (char *)malloc(sizeof(char)*1820*286*5);
fool(memory);
I get a warning, passing arg 1 of toldyou from incompatible pointer type
, but the code works, and I've verified that the same locations are accessed. Is there any way to do this without using another function?
回答1:
Yes, you can do this, and no, you don't need another array of pointers like most of the other answers are telling you. The invocation you want is just:
int (*MAGICVAR)[200] = malloc(400 * sizeof *MAGICVAR);
MAGICVAR[20][10] = 3; // sets the (200*20 + 10)th element
If you wish to declare a function returning such a pointer, you can either do it like this:
int (*func(void))[200]
{
int (*MAGICVAR)[200] = malloc(400 * sizeof *MAGICVAR);
MAGICVAR[20][10] = 3;
return MAGICVAR;
}
Or use a typedef, which makes it a bit clearer:
typedef int (*arrayptr)[200];
arrayptr function(void)
{
/* ... */
回答2:
Use a pointer to arrays:
#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:
If extra indirection isn't a concern, you can use an array of pointers.
Edit
Here's a variation on @Platinum Azure's answer that doesn't make so many calls to malloc. Besides faster allocation, all the elements are guaranteed to be contiguous:
#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:
In the same vein as Cogwheel's answer, here's a (somewhat dirty) trick that makes only one call to 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);
This fills the first part of the buffer with pointers to each row in the immediately following, contiguous array data.
回答5:
#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:
Arrays and pointers look very much the same, but the compiler treats them very differently. Let's see what needs to be done for an array indexing and de-referencing a pointer with offset:
Say we declared a static array (array on the stack is just a bit more complicated, fixed offset from a register, but essentially the same):
static int array[10];
And a pointer:
static int* pointer;
We then de-deference each as follows:
x = array[i];
x = pointer[i];
The thing to note is that address of the beginning of array
, as well as, address of pointer
(not its contents) are fixed at link/load time. Compiler then does the following:
- For
array
de-reference:
- loads value of
i
,
- adds it to the value of
array
, i.e. its fixed address, to form target memory address,
- loads the value from calculated address
- For
pointer
de-reference:
- loads the value of
i
,
- loads the value of
pointer
, i.e. the contents at its address,
- adds two values to form the effective address
- loads the value from calculated address.
Same happens for 2D array with additional steps of loading the second index and multiplying it by the row size (which is a constant). All this is decided at compile time, and there's no way of substituting one for the other at run-time.
Edit:
@caf here has the right solution. There's a legal way within the language to index a pointer as two-dimentional array after all.
回答6:
The compiler and runtime have no way of knowing your intended dimension capacities with only a multiplication in the malloc call.
You need to use a double pointer in order to achieve the capability of two indices. Something like this should do it:
#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;
Make sure you check all your malloc return values for NULL returns, indicating memory allocation failure.
回答7:
Working from Tim's and caf's answers, I'll leave this here for posterity:
#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;
}
回答8:
int** memory = malloc(sizeof(*memory)*400);
for (int i=0 ; i < 400 ; i++)
{
memory[i] = malloc(sizeof(int)*200);
}