这两种内存分配方法有什么区别?

4
以下是一个 p[10][10] 数组的内存分配方法。
//First
char** p;
int i;
p=(char**)malloc(10*sizeof(char*));
for(i=0;i<10;i++)
    p[i]=(char*)malloc(10*sizeof(char));

//Second
char** p;
int i;
p=(char**)malloc(10*sizeof(char*));
*p=(char*)malloc(100*sizeof(char));
for(i=1;i<10;i++)
    p[i]=p[0]+10*i;

这两者之间有什么区别?

2
这些并不是"数组" - yizzlez
1
标准警告:不要malloc 和其它函数返回的 void * 强制转换类型! C 不是 C++。 注意:sizeof(char) 的结果定义为 1 - too honest for this site
哦,这些都不是数组。更不用说二维数组了。就像你在第一句中写的那样char a[10][10] - too honest for this site
@awesomeyi;这些是动态分配的数组。 - haccks
我第一次使用这个平台,下次我会记得放上一个合适的标题,并且感谢 @awesomeyi 编辑标题。 - prasanth unnam
3个回答

9

这两个都不是C ++。第一个分配了一个由10个char *组成的数组,然后将每个指针分配给一个单独的动态分配的包含10个char的数组。每个数组都是独立的,所以您无法保证p[0][9]p[1][0]之间的差异:

  p
+------+
| p[0] |  --> [][][][][][][][][][]
+------+
| p[1] |  --> [][][][][][][][][][]
+------+
|      |  --> [][][][][][][][][][]
+------+
 ...  
+------+
| p[9] |  --> [][][][][][][][][][]
+------+

在第二种情况下,您有一个连续的包含100个char的数组,而您的10个char* 分别指向其中不同的片段。
   0  1  2      10     20
  +--+--+--+   +--+   +--+
  |  |  |  |...|  |...|  |...    <== dynamically allocated array of 100 char
  +--+--+--+   +--+   +--+
    |         /       /
    \        /       /
  +------+------+------+
p | p[0] | p[1] | p[2] |...      <== dynamically allocated array of 10 char*
  +------+------+------+

您可以确信,p [0] [9] 之后的下一个字符是 p [1] [0]

虽然这两个都不是真正的数组。要实现这个功能,您需要使用以下代码:

char p[10][10]; 

这将提供第二个代码块相同的行为 - 减去所有额外的10个 char* 和动态内存分配的开销。在C++中,我们更喜欢将其编写为:

std::array<std::array<char, 10>, 10> p;

1
它们实际上是 C++ - 只是 malloc() 的使用已被弃用。 - Peter

4
你在你的片段中动态分配了数组。两个片段的区别在于,第一个片段以锯齿状(取决于内存空间的可用性)为每个10个char指针分配内存。第二个片段为每个10个char指针分配了连续的内存。
可以看图片更加清晰明了。
int **array1 = malloc(nrows * sizeof(int *));
    for(i = 0; i < nrows; i++)
        array1[i] = malloc(ncolumns * sizeof(int));    

enter image description here

int **array2 = malloc(nrows * sizeof(int *));
    array2[0] = malloc(nrows * ncolumns * sizeof(int));
    for(i = 1; i < nrows; i++)
        array2[i] = array2[0] + i * ncolumns; 

在这里输入图片描述

更多阅读: 如何动态分配多维数组?.


@Barry;你为什么认为我的回答没有意义? - haccks
1
这10个char*是以相同的方式分配的,不同的是这些char*所指向的内存是以不同的方式分配的。 - TartanLlama
@TartanLlama; 我什么时候说过这10个char *是以不同的方式分配的? - haccks
1
区别在于第一个代码片段为10个字符指针分配内存[...]而第二个代码片段为10个char指针分配连续的内存。这让我感觉你是在说这10个指针被不同地分配了。 - TartanLlama
@ TartanLlama;哦!现在看来我是指针和数组标签的新手! - haccks
@haccks 我并不质疑你的专业知识,只是想说你的措辞似乎暗示了一些不正确的事情。修改后更清晰地表达了你的意图 :) - TartanLlama

3
在这段代码片段中
char** p;
int i;
p=(char**)malloc(10*sizeof(char*));
for(i=0;i<10;i++)
    p[i]=(char*)malloc(10*sizeof(char));

分配了一个长度为10的char *类型一维数组所需的内存空间:

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

每个指针依次通过分配给char类型的10个元素的一维数组的地址进行初始化:

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

在这个代码片段中
char** p;
int i;
p=(char**)malloc(10*sizeof(char*));
*p=(char*)malloc(100*sizeof(char));
for(i=1;i<10;i++)
    p[i]=p[0]+10*i;

一开始,为了一个由10个char *类型元素组成的一维数组分配内存,就像第一个代码片段中所示。

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

然而,这只会初始化数组的第一个元素,它指向了一个100个char元素的一维数组所分配的内存地址。

*p=(char*)malloc(100*sizeof(char));

上述语句相当于:
p[0]=(char*)malloc(100*sizeof(char));

然后其他9个指针由整数表达式10*i初始化。

for(i=1;i<10;i++)
    p[i]=p[0]+10*i;

显然这是没有意义的。这9个元素的值无效,因为它们不是指向对象的指针。这些初始化的目的不清楚。

请注意,您可以按以下方式为一个二维数组分配内存

char ( *p )[10] = malloc( 100 * sizeof( char ) );

这种分配的好处在于,您只需要调用一次free函数就可以释放所有已分配的内存。而且,这个指针可以作为参数传递给一个将二维数组作为参数的函数。
例如:
void func( char a[][10] );

您可以像这样调用此函数:
func( p );

但是如果p的类型是char **,你可能无法调用该函数,因为此类型与参数类型不兼容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接