我们如何使用一个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));