C中的malloc,但使用多维数组语法

时间:2010-06-29 19:43:10

标签: c pointers arrays multidimensional-array malloc

有没有办法对大型数组进行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);

然后参考我的blob:

memory[INDX(a,b)];

我更喜欢:

memory[a][b];

<小时/> 更新:我理解编译器无法按原样知道。我愿意提供额外的信息,例如:

int *MAGICVAR[][200] = memory;

不存在这样的语法吗?请注意我不仅使用固定宽度数组的原因是它太大而无法放在堆栈上。

<小时/> 更新:伙计们,我可以这样做:

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,但代码有效,我已经确认访问了相同的位置。没有使用其他功能有没有办法做到这一点?

8 个答案:

答案 0 :(得分:27)

是的,你可以这样做,不,你不需要像大多数其他答案告诉你的另一个指针数组。您想要的调用只是:

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)
{
    /* ... */

答案 1 :(得分:19)

使用指向数组的指针:

#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;
}

答案 2 :(得分:4)

如果不关心额外的间接,可以使用指针数组。

修改

这是@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;

答案 3 :(得分:2)

#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 );

编辑:

数组和指针看起来非常相似,但编译器对它们的处理方式却截然不同。让我们看看需要对数组索引和取消引用带偏移量的指针做什么:

  1. 假设我们声明了一个静态数组(堆栈上的数组只是稍微复杂一点,固定偏移量来自寄存器,但基本相同):

    static int array[10];

  2. 指针:

    static int* pointer;

  3. 然后我们按照以下方式对每个进行去除:

    x = array[i];
    x = pointer[i];

  4. 需要注意的是,array的开头地址以及pointer的地址(不是其内容)在链接/加载时已修复 。编译器然后执行以下操作:

    1. array取消引用:
      • 加载i
      • 的值
      • 将其添加到array的值,即其固定地址,以形成目标内存地址,
      • 从计算地址
      • 加载值
    2. pointer取消引用:
      • 加载i
      • 的值
      • 在其地址加载pointer的值,即内容
      • 添加两个值以形成有效地址
      • 从计算地址加载值。
    3. 对于2D数组也是如此,其中包括加载第二个索引并将其乘以行大小(这是一个常量)的附加步骤。所有这些都是在编译时决定的,并且在运行时无法用一个代替另一个。

      编辑:

      @caf这里有正确的解决方案。在语言中有一种合法的方法可以将指针索引为二维数组。

答案 4 :(得分:2)

与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);

这将使用指向紧随其后的连续数组数据中每一行的指针填充缓冲区的第一部分。

答案 5 :(得分:1)

编译器和运行时无法通过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,表示内存分配失败。

答案 6 :(得分:0)

int** memory = malloc(sizeof(*memory)*400); 
for (int i=0 ; i < 400 ; i++) 
{
    memory[i] = malloc(sizeof(int)*200);
}

答案 7 :(得分:0)

根据蒂姆和咖啡馆的答案,我将这里留给后人:

#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;
}