2009-12-28 77 views
59

我有以下C代码:多维阵列,不同的行的分配用malloc长度

int *a; 
size_t size = 2000*sizeof(int); 
a = (int *) malloc(size); 

工作正常。但是,如果我有以下几点:

char **b = malloc(2000*sizeof *b); 

其中b每一个元素都有不同的长度。

怎么可能为b做同样的事情,就像我为a做的那样;即以下代码将保持正确?

char *c; 
size_t size = 2000*sizeof(char *); 
c = (char *) malloc(size); 

回答

67

首先,你需要分配的指针数组一样char **c = malloc(N * sizeof(char*)),然后用一个单独的分配每一行来电malloc,大概在循环:


/* N is the number of rows */ 
/* note: c is char** */ 
if ((c = malloc(N*sizeof(char*))) == NULL) 
{ /* error */ } 

for (i = 0; i < N; i++) 
{ 
    /* x_i here is the size of given row, no need to 
    * multiply by sizeof(char), it's always 1 
    */ 
    if ((c[i] = malloc(x_i)) == NULL) 
    { /* error */ } 

    /* probably init the row here */ 
} 

/* access matrix elements: c[i] give you a pointer 
* to the row array, c[i][j] indexes an element 
*/ 
c[i][j] = 'a'; 

如果你知道总数的元素(如N*M)你可以做到这一点一次分配。

+2

如果你在一次操作中分配N * M个字节,那么你手动填充所有的c [i]:c [i] = p + M * i; – 2009-12-28 18:28:43

+2

这取决于c的类型 - 如果它是char **,那么是的,如果它是char *,那么索引改变:element [i] [j]〜c [i * M + j]。 – 2009-12-28 18:30:38

+1

@Nikolai N Fetissov,代码中有很多malloc,这怎么可以全部释放?通过也使用for循环? – e19293001 2011-10-24 08:02:11

3

如果b中的每一个元素都有不同的长度,那么你需要做的是这样的:

int totalLength = 0; 
for_every_element_in_b { 
    totalLength += length_of_this_b_in_bytes; 
} 
return (char **)malloc(totalLength); 
+1

它不对于char *指针的1维阵列分配内存。 – 2009-12-28 18:29:30

2

我认为2步法是最好的,因为c 2-d数组只是数组。第一步是分配一个单一的数组,然后循环遍历它为每一列分配数组。 This article给出了很好的细节。

46

对于动态分配类型T的N×M个阵列的典型形式是

T **a = malloc(sizeof *a * N); 
if (a) 
{ 
    for (i = 0; i < N; i++) 
    { 
    a[i] = malloc(sizeof *a[i] * M); 
    } 
} 

如果阵列中的每个元件具有不同的长度,然后用该元素的适当的长度更换米;例如

T **a = malloc(sizeof *a * N); 
if (a) 
{ 
    for (i = 0; i < N; i++) 
    { 
    a[i] = malloc(sizeof *a[i] * length_for_this_element); 
    } 
} 
+0

如果我有我会得到的int的总数,但是没有多少人进入每个数组,我该如何继续? – dietbacon 2014-09-15 23:01:23

+0

非常明确的答案,谢谢!你还可以添加一个关于以正确的'释放'分配内存的顺序的描述吗? – Kagaratsch 2018-02-18 17:03:47

+2

@Kagaratsch:一般情况下,你可以按照相反的顺序自由分配 - 也就是说,先释放每个“a [i]”,然后释放“a”。 – 2018-02-18 17:59:27

10

另一种方法将是要分配的存储器,其包括用于指针的行头块的一个连续的块,以及主体块存储在行实际数据。然后,通过将正文中的内存地址分配给基于每行的标题中的指针来标记内存。它看起来像如下:

int** 2dAlloc(int rows, int* columns) {  
    int header = rows * sizeof(int*); 

    int body = 0; 
    for(int i=0; i<rows; body+=columnSizes[i++]) { 
    } 
    body*=sizeof(int); 

    int** rowptr = (int**)malloc(header + body); 

    int* buf = (int*)(rowptr + rows); 
    rowptr[0] = buf; 
    int k; 
    for(k = 1; k < rows; ++k) { 
     rowptr[k] = rowptr[k-1] + columns[k-1]; 
    } 
    return rowptr; 
} 

int main() { 
    // specifying column amount on per-row basis 
    int columns[] = {1,2,3}; 
    int rows = sizeof(columns)/sizeof(int); 
    int** matrix = 2dAlloc(rows, &columns); 

    // using allocated array 
    for(int i = 0; i<rows; ++i) { 
     for(int j = 0; j<columns[i]; ++j) { 
      cout<<matrix[i][j]<<", "; 
     } 
      cout<<endl; 
    } 

    // now it is time to get rid of allocated 
    // memory in only one call to "free" 
    free matrix; 
} 

这种方法的优点是存储器和使用阵列状符号来访问所得到的2D阵列的元素能力优雅释放。

+2

需要注意的是:这种解决方案通常在缓存一致性方面表现更好,因为与保证一次分配一行的其他方法不同,单独的行保证是连续的,并且可能导致其组件部分为散布在高度分散的堆中。 – 2014-05-06 04:20:09

+2

这不幸的是也有不保证非指针大小类型对齐的副作用。例如:一个32位指针和一个奇数行的64位双精度的系统将在double对齐的非对齐边界上开始第一行双精度。它被认为是非常重要的,因为它可能由于不正确的数据对齐而容易导致总线错误。一般的解决方案应该确保数据行在8字节的边界上开始,从而产生额外的分配空间,并在将指针指向主指针段时进行相应的调整。 – WhozCraig 2014-10-24 21:16:37

+0

@DmitryAleks:你在哪里声明'columnSizes []'? – user2284570 2015-03-26 01:55:41

27

char a[10][20]的等效存储器分配如下。

char **a; 

a=(char **) malloc(10*sizeof(char *)); 

for(i=0;i<10;i++) 
    a[i]=(char *) malloc(20*sizeof(char)); 

我希望这看起来很容易理解。

0

malloc不会在特定的边界上分配,所以必须假定它分配在一个字节边界上。

返回如果转换为任何其它类型的,因为访问该指针将可能是由CPU产生的存储器访问冲突然后不能使用指针,应用程序将被立即关闭。

0

2- d阵列动态内存分配

int **a,i; 

// for any number of rows & columns this will work 
a = (int **)malloc(rows*sizeof(int *)); 
for(i=0;i<rows;i++) 
    *(a+i) = (int *)malloc(cols*sizeof(int));