这个
int **arr = (int **)malloc(r * sizeof(int *));
是int * [r] 类型数组的动态分配,该数组是r 元素的数组,其类型为int *。
为了使声明更清晰,请考虑以下简单程序
#include <stdio.h>
int main(void)
{
char * s[] = { "Hello", " ", "user292174" };
const size_t N = sizeof( s ) / sizeof( *s );
char **p = s;
for ( size_t i = 0; i < N; i++ ) printf( "%s", p[i] );
putchar( '\n' );
return 0;
}
它的输出是
Hello user292174
为简单起见,在程序中使用char 类型而不是int。
表达式中的数组指示符(极少数例外)被转换为指向其第一个元素的指针。
因此,由于数组s 的类型是char *,那么指向数组s 的第一个元素的指针将具有char ** 类型。
在问题的原始声明的情况下,动态分配的内存范围被解释为int * 类型的元素数组。并且将存在隐含数组的第一个元素的范围的起始地址分配给指针。所以指针的类型应该是 int **。
int **arr = (int **)malloc(r * sizeof(int *));
当数组的行数和列数在运行时计算时,通常使用这种分配来模拟二维数组。
例如
#include <stdio.h>
#include<stdlib.h>
int main(void)
{
size_t r = 2;
size_t c = 3;
int **arr = (int **)malloc( r * sizeof( int * ) );
for ( size_t i = 0; i < r; i++ )
{
arr[i] = malloc( c * sizeof( int ) );
}
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
arr[i][j] = c * i + j;
}
}
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
printf( "%d ", arr[i][j] );
}
putchar( '\n' );
}
for ( size_t i = 0; i < r; i++ )
{
free( arr[i] );
}
free( arr );
return 0;
}
程序输出是
0 1 2
3 4 5
如果编译器支持可变长度数组,则可以一次分配一个二维数组。例如
#include <stdio.h>
#include<stdlib.h>
int main(void)
{
size_t r = 2;
size_t c = 3;
int ( *arr )[c] = (int **)malloc( sizeof( int[r][c] ) );
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
arr[i][j] = c * i + j;
}
}
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
printf( "%d ", arr[i][j] );
}
putchar( '\n' );
}
free( arr );
return 0;
}
porgram 输出如上图所示。