在C语言中为三维数组分配空间
这个问题已经得到了回答,但对我来说,有些事情仍然悬而未决,讨论时间太长,任何人都无法回复评论,此外,我想问一下我的实现中出现了什么问题 不管怎样,问题的解决。我想为三维数组在C语言中为三维数组分配空间,c,arrays,pointers,dynamic-memory-allocation,C,Arrays,Pointers,Dynamic Memory Allocation,这个问题已经得到了回答,但对我来说,有些事情仍然悬而未决,讨论时间太长,任何人都无法回复评论,此外,我想问一下我的实现中出现了什么问题 不管怎样,问题的解决。我想为三维数组3,h,w分配空间。我在做什么: int ***a = (int***)malloc(3 * sizeof(int*)); for (int i = 0; i < 3; i++) { a[i] = (int **) malloc(height * sizeof(int*)); } 所以现在我认为每个a[I][0
3,h,w
分配空间。我在做什么:
int ***a = (int***)malloc(3 * sizeof(int*));
for (int i = 0; i < 3; i++)
{
a[i] = (int **) malloc(height * sizeof(int*));
}
所以现在我认为每个a[I][0]
基本上是一个二维数组的空间,数组的大小、高度和宽度;此外,对于j!=0
初始化为a[i][0]
的j行
然后,我通过以下方式初始化值:
for (int c = 0; c < 3; c++){
for (int i = 0; i < height; i++){
for (int j = 0; j < width; j++){
a[c][i][j] = i+j+c;
for(int c=0;c<3;c++){
对于(int i=0;i
但是,这是不正确的。我想通过以下方式将此作为分配2D数组的扩展练习:
int *a[height];
a[0] = (int*)malloc(height * width * sizeof(int));
for (int i = 1; i < height; i++){
a[i] = a[i-1] + widht;
}
int*a[高度];
a[0]=(int*)malloc(高度*宽度*尺寸(int));
对于(int i=1;i
这样,a是一个长度高度的指针数组,a[0]
被分配给整个2D数组,随后的指针指向它们各自的行,我只需调用a[I][j]=some number;
我想做的是将这个2D想法扩展到3D案例,但遗憾的是我失败了
int ***a = (int***)malloc(3 * sizeof(int*));
这没有分配任何有意义的内容。特别是,它没有分配3D数组,甚至没有分配3D数组的一部分。它为3个整数指针分配空间,这没有任何意义。int***
也没有任何意义
而是分配一个三维阵列:
int (*a)[y][z] = malloc( sizeof(int[x][y][z]) );
for(int i=0; i<x; i++)
for(int j=0; j<y; j++)
for(int k=0; k<z; k++)
a[i][j][k] = something;
free(a);
为了解决OP的更高目标,我怀疑指向2D数组的指针就足够了
但根据OP的要求
…要为三维阵列分配空间
代码通常如何创建3D阵列?
下面的代码使用C99中提供的可变长度数组执行此操作。
(VLA可选地支持C11)
示例代码
void VT_3_dimensional_array(int height, int width) {
assert(height > 0 && width > 0);
int (*a2)[3][height][width] = malloc(sizeof *a2);
printf("%p %zu\n", (void*) a2, sizeof *a2);
if (a2 == NULL) {
perror("Out of memory");
exit(EXIT_FAILURE);
}
for (int c = 0; c < 3; c++) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
(*a2)[c][i][j] = i + j + c;
}
}
}
// use a;
for (int c = 0; c < 3; c++) {
for (int i = 0; i < height; i++) {
putchar('(');
for (int j = 0; j < width; j++) {
printf(" %X", (*a2)[c][i][j]);
}
putchar(')');
}
puts("");
}
free(a2);
}
int main() {
VT_3_dimensional_array(5, 7);
return 0;
}
请注意,从技术上讲,OP的代码使用了错误的大小。通常sizeof(int*)
与sizeof(int**)
的大小相同,因此没有太大的危害。但这确实表明对分配的混淆
// wrong type -----------------------v should be int**
int ***a = (int***)malloc(3 * sizeof(int*));
让我们先想象一下您正在尝试做什么,然后我将显示代码以达到目的:
int *** int ** int * int
+---+ +---+ +---+ +---+
a | | ---> a[0] | | ------> a[0][0] | | ----> a[0][0][0] | |
+---+ +---+ +---+ +---+
a[1] | | ----+ a[0][1] | | -+ a[0][0][1] | |
+---+ | +---+ | +---+
a[2] | | | ... | ...
+---+ | +---+ | +---+
| a[0][h-1] | | | a[0][0][w-1] | |
| +---+ | +---+
| |
| +---+ | +---+
+-> a[1][0] | | +--> a[0][1][0] | |
+---+ +---+
a[1][1] | | a[0][1][1] | |
+---+ +---+
... ...
+---+ +---+
a[1][h-1] | | a[0][1][w-1] | |
+---+ +---+
类型:
- 每个
a[i][j][k]
都有类型int
- 每个
a[i][j]
都指向int
对象序列的第一个元素,因此它必须具有类型int*
- 每个
a[i]
都指向int*
对象序列的第一个元素,因此它必须具有类型int**
a
指向int**
对象序列的第一个元素,因此它必须具有类型int***
由于您正在执行逐段嵌套分配,因此需要检查每个malloc
调用的结果,如果出现错误,您将希望在退出之前清理所有以前分配的内存,否则您将面临内存泄漏的风险。不幸的是,没有真正干净或优雅的方法来执行此操作-您要么在周围带一个标志然后做一系列额外的测试,或者加入几个goto
s。我将展示两种不同的方法,这两种方法都不是很好
第一种方法-当我们分配每个a[i]
时,我们也分配每个a[i][j]
(一种“深度优先”方法)并初始化每个a[i][j][k]
。如果分配a[i][j]
失败,我们必须通过a[i][j-1]
取消分配所有a[i]
,然后对a[0]
到a[i-1]
中的每一个重复该过程:
/**
* Depth-first approach: allocate each a[i][j] with each a[i]
*/
int ***alloc1( size_t pages, size_t height, size_t width )
{
size_t i, j, k;
int ***a = malloc( sizeof *a * pages ); // allocate space for N int **
// objects, where N == pages
if ( !a )
return NULL;
for ( i = 0; i < pages; i++ )
{
a[i] = malloc( sizeof *a[i] * height ); // for each a[i], allocate space for
if ( !a[i] ) // N int * objects, where N == height
goto cleanup_1;
for ( j = 0; j < height; j++ )
{
a[i][j] = malloc( sizeof *a[i][j] * width ); // for each a[i][j], allocate
if ( !a[i][j] ) // space for N int objects,
goto cleanup_2; // where N == w
for ( k = 0; k < width; k++ )
a[i][j][k] = initial_value( i, j, k );
}
}
goto done;
/**
* Free all of a[i][0] through a[i][j-1], then free a[i]
*/
cleanup_2:
while ( j-- )
free( a[i][j] );
free( a[i] );
/**
* Free all of a[0] through a[i-1], then free a
*/
cleanup_1:
while ( i-- )
{
j = height;
goto cleanup_2;
}
free( a );
a = NULL;
done:
return a; // at this point, a is either a valid pointer or NULL.
}
没有goto
s!但是在我看来,代码并不“流动”。分配代码和清理代码之间没有那么清晰的分离,清理部分之间也有一些重复性
请注意,对于这两种方法,内存都不是连续的-紧跟在a[0][0][h-1]
之后的元素不会是a[0][1][0]
。如果需要所有数组元素在内存中相邻,则需要使用其他元素显示的方法:
int (*a)[h][w] = malloc( sizeof *a * 3 );
需要注意的是,如果h
和w
较大,您可能没有足够的连续分配内存来满足请求。int(*a)[height][width]=malloc(3*sizeof*a);
应该为您提供一个3d数组。这不会创建一个指向高度、宽度大小的2D数组的指针吗?是的,a
是指向2D数组的指针,可以与a[i][j][k]一起使用
。为什么你不能只进行1D分配,然后自己编制索引?更紧凑,而且我不相信这两个乘法比所有内存遍历都要昂贵。更不用说更有效的堆使用率了。@unwind这将是更好的处理方法,然而,我只想练习一下这个技巧内存管理的y部分,数组到指针的衰减等等。我知道它不会分配整个数组,我想做的是分配3个int**
@VahagnTumanyan类型的指针。为什么?你说你想要一个3D数组。指针到指针在这种情况下没有意义。只是作为处理几个点的练习任何维度的指针类型。此外,对malloc
使用更正确的语法(语义?),如将返回的void*
转换为正确的指针类型,并具有(元素数*大小(类型))<代码> >而不是简单地分配数组。@ VAHAGNTUMYANYAN确保您不实际使用C++编译器,在这种情况下,您将得到奇怪的错误,而2)您无意中使用了一个27年历史的GCC版本,通过添加编译器选项<代码> -STD= C99 < /代码>或<代码> -STD= C。
int (*a2)[3][height][width] = malloc(sizeof *a2);
// 3 nested for loop as above
(*a2)[c][i][j] = i + j + c;
void VT_3_dimensional_array(int height, int width) {
assert(height > 0 && width > 0);
int (*a2)[3][height][width] = malloc(sizeof *a2);
printf("%p %zu\n", (void*) a2, sizeof *a2);
if (a2 == NULL) {
perror("Out of memory");
exit(EXIT_FAILURE);
}
for (int c = 0; c < 3; c++) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
(*a2)[c][i][j] = i + j + c;
}
}
}
// use a;
for (int c = 0; c < 3; c++) {
for (int i = 0; i < height; i++) {
putchar('(');
for (int j = 0; j < width; j++) {
printf(" %X", (*a2)[c][i][j]);
}
putchar(')');
}
puts("");
}
free(a2);
}
int main() {
VT_3_dimensional_array(5, 7);
return 0;
}
0x80071980 420
( 0 1 2 3 4 5 6)( 1 2 3 4 5 6 7)( 2 3 4 5 6 7 8)( 3 4 5 6 7 8 9)( 4 5 6 7 8 9 A)
( 1 2 3 4 5 6 7)( 2 3 4 5 6 7 8)( 3 4 5 6 7 8 9)( 4 5 6 7 8 9 A)( 5 6 7 8 9 A B)
( 2 3 4 5 6 7 8)( 3 4 5 6 7 8 9)( 4 5 6 7 8 9 A)( 5 6 7 8 9 A B)( 6 7 8 9 A B C)
// wrong type -----------------------v should be int**
int ***a = (int***)malloc(3 * sizeof(int*));
int *** int ** int * int
+---+ +---+ +---+ +---+
a | | ---> a[0] | | ------> a[0][0] | | ----> a[0][0][0] | |
+---+ +---+ +---+ +---+
a[1] | | ----+ a[0][1] | | -+ a[0][0][1] | |
+---+ | +---+ | +---+
a[2] | | | ... | ...
+---+ | +---+ | +---+
| a[0][h-1] | | | a[0][0][w-1] | |
| +---+ | +---+
| |
| +---+ | +---+
+-> a[1][0] | | +--> a[0][1][0] | |
+---+ +---+
a[1][1] | | a[0][1][1] | |
+---+ +---+
... ...
+---+ +---+
a[1][h-1] | | a[0][1][w-1] | |
+---+ +---+
/**
* Depth-first approach: allocate each a[i][j] with each a[i]
*/
int ***alloc1( size_t pages, size_t height, size_t width )
{
size_t i, j, k;
int ***a = malloc( sizeof *a * pages ); // allocate space for N int **
// objects, where N == pages
if ( !a )
return NULL;
for ( i = 0; i < pages; i++ )
{
a[i] = malloc( sizeof *a[i] * height ); // for each a[i], allocate space for
if ( !a[i] ) // N int * objects, where N == height
goto cleanup_1;
for ( j = 0; j < height; j++ )
{
a[i][j] = malloc( sizeof *a[i][j] * width ); // for each a[i][j], allocate
if ( !a[i][j] ) // space for N int objects,
goto cleanup_2; // where N == w
for ( k = 0; k < width; k++ )
a[i][j][k] = initial_value( i, j, k );
}
}
goto done;
/**
* Free all of a[i][0] through a[i][j-1], then free a[i]
*/
cleanup_2:
while ( j-- )
free( a[i][j] );
free( a[i] );
/**
* Free all of a[0] through a[i-1], then free a
*/
cleanup_1:
while ( i-- )
{
j = height;
goto cleanup_2;
}
free( a );
a = NULL;
done:
return a; // at this point, a is either a valid pointer or NULL.
}
/**
* Breadth-first approach; allocate all a[i], then all a[i][j], then initialize
*/
int ***alloc2( size_t pages, size_t height, size_t width )
{
size_t i, j, k;
/**
* Allocate space for N int ** objects, where N == pages
*/
int ***a = malloc( sizeof *a * pages );
if ( !a )
return NULL; // allocation failed for initial sequence, return NULL
for ( i = 0; i < pages; i++ ) // For each a[i], allocate N objects of type
{ // int *, where N == height
a[i] = malloc( sizeof *a[i] * height );
if ( !a[i] )
break;
}
if ( i < pages )
{
while ( i-- ) // allocation of a[i] failed, free up a[0] through a[i-1]
free( a[i] );
free( a ); // free a
return NULL;
}
for ( i = 0; i < pages; i++ )
{
for ( j = 0; j < height; j++ )
{
a[i][j] = malloc( sizeof *a[i][j] * width ); // for each a[i][j], allocate
if ( !a[i][j] ) // space for N int objects,
break; // where N == width
}
}
if ( j < h )
{
do
{
while ( j-- ) // allocation of a[i][j] failed, free up a[i][0] through a[i][j-1]
free( a[i][j] ); // repeat for all of a[0] through a[i-1].
free( a[i] );
j = h;
} while ( i-- );
free( a ); // free a
return NULL;
}
/**
* All allocations were successful, initialize array contents
*/
for ( i = 0; i < pages; i++ )
for ( j = 0; j < height; j++ )
for ( k = 0; k < width; k++ )
a[i][j][k] = initial_value( i, j, k );
return a;
}
int (*a)[h][w] = malloc( sizeof *a * 3 );