我们如何使用一个malloc语句来分配一个二维数组

我在采访中被问及如何分配一个二维arrays,下面是我的解决scheme。

#include <stdlib.h> int **array; array = malloc(nrows * sizeof(int *)); for(i = 0; i < nrows; i++) { array[i] = malloc(ncolumns * sizeof(int)); if(array[i] == NULL) { fprintf(stderr, "out of memory\n"); exit or return } } 

我以为我做了一个好工作,但后来他让我用一个malloc()语句不是两个。 我不知道如何实现它。

任何人都可以build议我一个想法做单malloc()吗?

只需计算两个行指针所需的内存总量,并将实际数据加起来,然后执行一次调用:

 int **array = malloc(nrows * sizeof *array + (nrows * (ncolumns * sizeof **array)); 

如果你认为这看起来太复杂了,你可以分解它,并通过命名大小expression式的不同项来使它有点自我logging:

 int **array; /* Declare this first so we can use it with sizeof. */ const size_t row_pointers_bytes = nrows * sizeof *array; const size_t row_elements_bytes = ncolumns * sizeof **array; array = malloc(row_pointers_bytes + nrows * row_elements_bytes); 

然后您需要通过并初始化行指针,以便每行的指针指向该特定行的第一个元素:

 size_t i; int * const data = array + nrows; for(i = 0; i < nrows; i++) array[i] = data + i * ncolumns; 

请注意,所得到的结构与你得到的结果是完全不同的,例如int array[nrows][ncolumns] ,因为我们有显式的行指针,这意味着对于像这样分配的数组,没有真正的要求,所有的行都有相同的列数。

这也意味着像array[2][3]这样的访问完全不同于类似于访问实际二维数组的访问。 在这种情况下,最内层的访问首先发生, array[2]array的第三个元素读出一个指针。 然后该指针作为(列)数组的基础处理,我们通过索引来获取第四个元素。

相反,对于类似的东西

 int array2[4][3]; 

这是一个“压缩”的适当二维数组,只占用12个整数的空间,像array[3][2]这样的访问只是简单地将基本地址偏移量加到元素上。

 int **array = malloc (nrows * sizeof(int *) + (nrows * (ncolumns * sizeof(int))); 

这是可行的,因为在C中,数组是一个接一个的所有元素作为一堆字节。 没有元数据或任何东西。 malloc()不知道它是否分配用作字符,整数或数组中的行。

然后,你必须初始化:

 int *offs = &array[nrows]; /* same as int *offs = array + nrows; */ for (i = 0; i < nrows; i++, offs += ncolumns) { array[i] = offs; } 

这是另一种方法。

如果你知道编译时的列数,你可以这样做:

 #define COLS ... // integer value > 0 ... size_t rows; int (*arr)[COLS]; ... // get number of rows arr = malloc(sizeof *arr * rows); if (arr) { size_t i, j; for (i = 0; i < rows; i++) for (j = 0; j < COLS; j++) arr[i][j] = ...; } 

如果您使用C99,则可以使用指向VLA的指针:

 size_t rows, cols; ... // get rows and cols int (*arr)[cols] = malloc(sizeof *arr * rows); if (arr) { size_t i, j; for (i = 0; i < rows; i++) for (j = 0; j < cols; j++) arr[i][j] = ...; } 

你应该可以做到这一点(虽然所有的铸造丑陋):

 int** array; size_t pitch, ptrs, i; char* base; pitch = rows * sizeof(int); ptrs = sizeof(int*) * rows; array = (int**)malloc((columns * pitch) + ptrs); base = (char*)array + ptrs; for(i = 0; i < rows; i++) { array[i] = (int*)(base + (pitch * i)); } 

我不是这个“arrays指针数组”的粉丝来解决multidimensional array范例。 在数组[row * cols + col]访问元素时,总是偏爱单维数组? 没有任何问题封装在一个类,并实施“at”方法。

如果你坚持用这个表示法访问数组的成员:Matrix [i] [j],你可以做一点C ++的魔法。 @John解决scheme试图这样做,但他需要在编译时知道列的数量。 用一些C ++和覆盖运算符[],你可以完全得到这个:

 class Row { private: int* _p; public: Row( int* p ) { _p = p; } int& operator[](int col) { return _p[col]; } }; class Matrix { private: int* _p; int _cols; public: Matrix( int rows, int cols ) { _cols=cols; _p = (int*)malloc(rows*cols ); } Row operator[](int row) { return _p + row*_cols; } }; 

所以现在可以使用Matrix对象来创build一个乘法表:

 Matrix mtrx(rows, cols); for( i=0; i<rows; ++i ) { for( j=0; j<rows; ++j ) { mtrx[i][j] = i*j; } } 

您现在应该知道优化器是正确的,没有调用函数或任何其他types的开销。 没有构造函数被调用。 只要不在函数之间移动matrix,即使_colsvariables也不会被创build。 语句mtrx [i] [j]基本上是mtrx [i * cols + j]。

您可以使用malloc分配(row*column) * sizeof(int)字节的内存。 这里是一个代码片段来演示。

 int row = 3, col = 4; int *arr = (int *)malloc(row * col * sizeof(int)); int i, j, count = 0; for (i = 0; i < r; i++) for (j = 0; j < c; j++) *(arr + i*col + j) = ++count; //row major memory layout for (i = 0; i < r; i++) for (j = 0; j < c; j++) printf("%d ", *(arr + i*col + j));