如何为多维数组动态分配内存
How to dynamically allocate the memory for multi dimensional arrays
这里我尝试动态分配内存来创建多维。
所以我声明了一个指向指针的指针:
int ***array ;
并为变量数组
分配内存
array = (int***)malloc((sizeof(int) * 2));
这是我的代码!
void main(void)
{
int matrices, rows, columns;
int ***array;
printf("\n\n HOW MANY MATRICES YOU TO CREATE ? : ");
scanf("%d",&matrices);
array = (int***)malloc((sizeof(int) * matrices));
printf("\n HOW MANY ROWS YOU TO CREATE ? : ");
scanf("%d",&rows);
printf("\n HOW MANY COLUMNS YOU TO CREATE ? : ");
scanf("%d",&columns);
for(int i = 1; i <= matrices; i++)
{
printf("\n Enter %d - matrix! ",i);
for(int j = 1; j <= columns; j++)
{
for(int k = 1; k <= rows; k++)
{
printf("\n Enter element [%d[%d] : ",j,k);
scanf("%d",&array[i][j][k]);
}
}
}
//printing two matrices elements!!!
for(int l = 1; l <= matrices; l++)
{
printf("\n MATRIX - %d !! \n",l);
for(int m = 1; m <= columns; m++)
{
for(int n = 1; n <= rows; n++)
{
printf("%d\t",array[l][m][n]);
}
printf("\n");
}
}
}
但是当我尝试打印两个矩阵的元素时,这里只有第二个矩阵元素显示在两个矩阵的输出上,两个矩阵中的第一个元素显示为“0”。
示例:
输入:
第一个矩阵
1 2 3
4 5 6
第二矩阵
9 8 7
3 5 2
输出:
第一个矩阵
0 8 7
3 5 2
第二矩阵
0 8 7
3 5 2
我是这个网站的新手,任何错误请评论!!
因为您使用的是指向指针的指针。您需要在所有阶段动态分配内存。在您询问矩阵数量后的第一阶段。应该是,
array = (int***)malloc (sizeof(int**) * matrices);
因为您分配的矩阵是 int**
。然后在询问行数之后,对于每个矩阵你需要分配它,
for(i=1 ; i <= matrices ; i++)
array[i-1] = (int**)malloc (sizeof(int*)*ROWS);
最后你需要为每一行分配内存。所以,
for(i=1 ; i <= matrices ; i++)
for(j=1 ; j <= ROWS ; j++)
array[i-1][j-1] = (int*)malloc (sizeof(int)*COLS);
在此之后,您可以按照以前的方式随意输入。试试这个,它应该工作。如果没有,应该是其他问题。
在 C 中,避免
的模型
pointer = (some_type *) malloc(n * sizeof(some_type)); // Avoid
不是分配给类型,而是分配给引用的对象和drop the unneeded cast。先形成类型最宽的尺寸计算。 sizeof
运算符 returns 一种 size_t
.
pointer = malloc(sizeof *pointer * n); // Best
这更容易正确编码(OP 的 (sizeof(int) * matrices)
不正确且太小),审查和维护。
针对分配错误的可靠代码检查。
if (pointer == NULL) {
fprintf(stderr, "Out of memory\n"); // Sample error code, adjust to your code's need
exit(-1);
}
为矩阵数据分配内存,这是 OP 的代码没有做的事情。
array = malloc(sizeof *array * matrices);
// Error checking omitting for brevity, should be after each malloc()
// Use zero base indexing
// for(int i = 1; i <= matrices; i++) {
for (int m = 0; m < matrices; m++) {
array[m] = malloc(sizeof *array[m] * rows);
for (int r = 0; r < rows; r++) {
array[m][r] = malloc(sizeof *array[m][r] * columns);
}
}
// Now read in data
// Use data
// Free when done
for (int m = 0; m < matrices; m++) {
for (int r = 0; r < rows; r++) {
free(array[m][r]);
}
free(array[m]);
}
free(array);
比 int
更好的代码将 size_t
用于数组维度的类型,但 int
将适用于小程序。
只需使用具有动态存储的可变长度数组 (VLA)。
int (*array)[rows + 1][cols + 1] = malloc(sizeof(int[matrices + 1][rows + 1][cols + 1]));
使用 VLA 更简单且性能更高。
将每个维度加 1 可以让您从索引 1 开始寻址数组,并防止程序在访问元素 array[matrixes][rows][cols]
.
时出现未定义行为 (UB)
但是,BAD 实践是因为 C 中的数组是从 0 索引的。其他方法会使您的代码的其他用户感到困惑。
因此,我强烈建议您从 0 开始索引数组并删除所有“+ 1”。
所以正确的分配码应该是:
int (*array)[rows][cols] = malloc(sizeof(int[matrices][rows][cols]));
并更新所有循环以形成:
for(i = 0; i < matrices ; i++)
最后,当数组不再使用时释放它。
free(array)
您没有发生 SegFaulted 只是出于意外,并且由于指针的大小不会改变。因此,在您应该为 int**
分配 int*
的地方,分配的大小不受影响(幸运的意外...)
您通常希望避免成为 3 星程序员,但有时,如本例,这是必需的.在分配任何指针或指针到指针,或者在这种情况下是指针到指针到指针的分配时,请理解不涉及任何“数组”。
当您声明 int ***array;
时,您声明了一个指针。然后该指针指向(保存地址)您分配的一个指针块(类型 int**
)。您为用户输入的 int**
个指针的矩阵分配存储空间。
每个矩阵都是 int**
类型,因此您必须为每个矩阵分配一个包含 rows
个指针的内存块。
最后,您为每个矩阵中的每一行分配 cols
个 int
(类型 int*
)。
所以你的矩阵集合是一个分配的指针块,每个矩阵都有一个指针。然后每个矩阵都是一个分配的指针块,该矩阵中的每一行都有一个指针。最后,您为每个矩阵的每一行指针分配一个价值 int
的列。
从视觉上看,您的分配和分配类似于以下内容:
array (int***)
|
+ allocate matricies number of [Pointers]
|
+----------+
| array[0] | allocate rows number of [Pointers] for each matrix
+----------+ assign to each pointer in array block
| array[1] |
+----------+ array[2] (int**)
| array[2] | <======= +-------------+
+----------+ | array[2][0] |
| .... | +-------------+ allocate cols no. of [int]
| array[2][1] | for each allocated row pointer
+-------------+
| array[2][2] | <=== array[2][2] (int*)
+-------------+ +----------------+
| ... | | array[2][2][0] |
+----------------+
| array[2][2][1] |
+----------------+
| array[2][2][2] |
+----------------+
| ... |
为了始终保持每个分配的 type-size 正确,只需使用 dereferenced pointer 来设置 type-size .例如,当为 array
(int***
) 分配时,您将使用:
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
为每个 array[i]
分配时,您将使用:
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
最后,当为每行的每个 int
块分配时,每个 array[i][j]
,您将使用:
array[i][row] = malloc (cols * sizeof *array[i][row]);
如果你总是使用取消引用指针来设置类型大小,你永远不会出错。
按照上图依次进行每个分配(并验证每个分配),您可以编写类似于以下的分配和释放例程:
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
用用户输入的行数和列数分配矩阵数的完整示例是:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int ***array = NULL,
matrix,
rows,
cols;
fputs ("no. of matricies: ", stdout);
if (scanf ("%d", &matrix) != 1) /* validate EVERY input */
return 1;
fputs ("no. of rows : ", stdout);
if (scanf ("%d", &rows) != 1) /* ditto */
return 1;
fputs ("no. of cols : ", stdout);
if (scanf ("%d", &cols) != 1) /* ditto */
return 1;
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
/* fill matricies with any values */
for (int i = 0; i < matrix; i++)
for (int j = 0; j < rows; j++)
for (int k = 0; k < cols; k++)
array[i][j][k] = j * cols + k + 1;
/* display each matrix and free all memory */
for (int i = 0; i < matrix; i++) {
printf ("\nmatrix[%2d]:\n\n", i);
for (int j = 0; j < rows; j++) {
for (int k = 0; k < cols; k++)
printf (" %2d", array[i][j][k]);
putchar ('\n');
free (array[i][j]); /* free row of int (int*) */
}
free (array[i]); /* free matrix[i] pointers (int**) */
}
free (array); /* free matricies pointers (int***) */
}
(注意: 在释放每个矩阵中的行指针块的内存之前,先释放 int
的每个块的内存,然后再释放指针块每个矩阵)
示例Use/Output
$ ./bin/allocate_p2p2p
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址,因此,(2) 当不再需要时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。
对于Linux valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。
$ valgrind ./bin/allocate_p2p2p
==9367== Memcheck, a memory error detector
==9367== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9367== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9367== Command: ./bin/allocate_p2p2p
==9367==
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
==9367==
==9367== HEAP SUMMARY:
==9367== in use at exit: 0 bytes in 0 blocks
==9367== total heap usage: 23 allocs, 23 frees, 2,528 bytes allocated
==9367==
==9367== All heap blocks were freed -- no leaks are possible
==9367==
==9367== For counts of detected and suppressed errors, rerun with: -v
==9367== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放所有分配的内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。
这里我尝试动态分配内存来创建多维。 所以我声明了一个指向指针的指针:
int ***array ;
并为变量数组
分配内存array = (int***)malloc((sizeof(int) * 2));
这是我的代码!
void main(void)
{
int matrices, rows, columns;
int ***array;
printf("\n\n HOW MANY MATRICES YOU TO CREATE ? : ");
scanf("%d",&matrices);
array = (int***)malloc((sizeof(int) * matrices));
printf("\n HOW MANY ROWS YOU TO CREATE ? : ");
scanf("%d",&rows);
printf("\n HOW MANY COLUMNS YOU TO CREATE ? : ");
scanf("%d",&columns);
for(int i = 1; i <= matrices; i++)
{
printf("\n Enter %d - matrix! ",i);
for(int j = 1; j <= columns; j++)
{
for(int k = 1; k <= rows; k++)
{
printf("\n Enter element [%d[%d] : ",j,k);
scanf("%d",&array[i][j][k]);
}
}
}
//printing two matrices elements!!!
for(int l = 1; l <= matrices; l++)
{
printf("\n MATRIX - %d !! \n",l);
for(int m = 1; m <= columns; m++)
{
for(int n = 1; n <= rows; n++)
{
printf("%d\t",array[l][m][n]);
}
printf("\n");
}
}
}
但是当我尝试打印两个矩阵的元素时,这里只有第二个矩阵元素显示在两个矩阵的输出上,两个矩阵中的第一个元素显示为“0”。
示例:
输入:
第一个矩阵
1 2 3
4 5 6
第二矩阵
9 8 7
3 5 2
输出:
第一个矩阵
0 8 7
3 5 2
第二矩阵
0 8 7
3 5 2
我是这个网站的新手,任何错误请评论!!
因为您使用的是指向指针的指针。您需要在所有阶段动态分配内存。在您询问矩阵数量后的第一阶段。应该是,
array = (int***)malloc (sizeof(int**) * matrices);
因为您分配的矩阵是 int**
。然后在询问行数之后,对于每个矩阵你需要分配它,
for(i=1 ; i <= matrices ; i++)
array[i-1] = (int**)malloc (sizeof(int*)*ROWS);
最后你需要为每一行分配内存。所以,
for(i=1 ; i <= matrices ; i++)
for(j=1 ; j <= ROWS ; j++)
array[i-1][j-1] = (int*)malloc (sizeof(int)*COLS);
在此之后,您可以按照以前的方式随意输入。试试这个,它应该工作。如果没有,应该是其他问题。
在 C 中,避免
的模型pointer = (some_type *) malloc(n * sizeof(some_type)); // Avoid
不是分配给类型,而是分配给引用的对象和drop the unneeded cast。先形成类型最宽的尺寸计算。 sizeof
运算符 returns 一种 size_t
.
pointer = malloc(sizeof *pointer * n); // Best
这更容易正确编码(OP 的 (sizeof(int) * matrices)
不正确且太小),审查和维护。
针对分配错误的可靠代码检查。
if (pointer == NULL) {
fprintf(stderr, "Out of memory\n"); // Sample error code, adjust to your code's need
exit(-1);
}
为矩阵数据分配内存,这是 OP 的代码没有做的事情。
array = malloc(sizeof *array * matrices);
// Error checking omitting for brevity, should be after each malloc()
// Use zero base indexing
// for(int i = 1; i <= matrices; i++) {
for (int m = 0; m < matrices; m++) {
array[m] = malloc(sizeof *array[m] * rows);
for (int r = 0; r < rows; r++) {
array[m][r] = malloc(sizeof *array[m][r] * columns);
}
}
// Now read in data
// Use data
// Free when done
for (int m = 0; m < matrices; m++) {
for (int r = 0; r < rows; r++) {
free(array[m][r]);
}
free(array[m]);
}
free(array);
比 int
更好的代码将 size_t
用于数组维度的类型,但 int
将适用于小程序。
只需使用具有动态存储的可变长度数组 (VLA)。
int (*array)[rows + 1][cols + 1] = malloc(sizeof(int[matrices + 1][rows + 1][cols + 1]));
使用 VLA 更简单且性能更高。
将每个维度加 1 可以让您从索引 1 开始寻址数组,并防止程序在访问元素 array[matrixes][rows][cols]
.
但是,BAD 实践是因为 C 中的数组是从 0 索引的。其他方法会使您的代码的其他用户感到困惑。 因此,我强烈建议您从 0 开始索引数组并删除所有“+ 1”。
所以正确的分配码应该是:
int (*array)[rows][cols] = malloc(sizeof(int[matrices][rows][cols]));
并更新所有循环以形成:
for(i = 0; i < matrices ; i++)
最后,当数组不再使用时释放它。
free(array)
您没有发生 SegFaulted 只是出于意外,并且由于指针的大小不会改变。因此,在您应该为 int**
分配 int*
的地方,分配的大小不受影响(幸运的意外...)
您通常希望避免成为 3 星程序员,但有时,如本例,这是必需的.在分配任何指针或指针到指针,或者在这种情况下是指针到指针到指针的分配时,请理解不涉及任何“数组”。
当您声明 int ***array;
时,您声明了一个指针。然后该指针指向(保存地址)您分配的一个指针块(类型 int**
)。您为用户输入的 int**
个指针的矩阵分配存储空间。
每个矩阵都是 int**
类型,因此您必须为每个矩阵分配一个包含 rows
个指针的内存块。
最后,您为每个矩阵中的每一行分配 cols
个 int
(类型 int*
)。
所以你的矩阵集合是一个分配的指针块,每个矩阵都有一个指针。然后每个矩阵都是一个分配的指针块,该矩阵中的每一行都有一个指针。最后,您为每个矩阵的每一行指针分配一个价值 int
的列。
从视觉上看,您的分配和分配类似于以下内容:
array (int***)
|
+ allocate matricies number of [Pointers]
|
+----------+
| array[0] | allocate rows number of [Pointers] for each matrix
+----------+ assign to each pointer in array block
| array[1] |
+----------+ array[2] (int**)
| array[2] | <======= +-------------+
+----------+ | array[2][0] |
| .... | +-------------+ allocate cols no. of [int]
| array[2][1] | for each allocated row pointer
+-------------+
| array[2][2] | <=== array[2][2] (int*)
+-------------+ +----------------+
| ... | | array[2][2][0] |
+----------------+
| array[2][2][1] |
+----------------+
| array[2][2][2] |
+----------------+
| ... |
为了始终保持每个分配的 type-size 正确,只需使用 dereferenced pointer 来设置 type-size .例如,当为 array
(int***
) 分配时,您将使用:
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
为每个 array[i]
分配时,您将使用:
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
最后,当为每行的每个 int
块分配时,每个 array[i][j]
,您将使用:
array[i][row] = malloc (cols * sizeof *array[i][row]);
如果你总是使用取消引用指针来设置类型大小,你永远不会出错。
按照上图依次进行每个分配(并验证每个分配),您可以编写类似于以下的分配和释放例程:
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
用用户输入的行数和列数分配矩阵数的完整示例是:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int ***array = NULL,
matrix,
rows,
cols;
fputs ("no. of matricies: ", stdout);
if (scanf ("%d", &matrix) != 1) /* validate EVERY input */
return 1;
fputs ("no. of rows : ", stdout);
if (scanf ("%d", &rows) != 1) /* ditto */
return 1;
fputs ("no. of cols : ", stdout);
if (scanf ("%d", &cols) != 1) /* ditto */
return 1;
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
/* fill matricies with any values */
for (int i = 0; i < matrix; i++)
for (int j = 0; j < rows; j++)
for (int k = 0; k < cols; k++)
array[i][j][k] = j * cols + k + 1;
/* display each matrix and free all memory */
for (int i = 0; i < matrix; i++) {
printf ("\nmatrix[%2d]:\n\n", i);
for (int j = 0; j < rows; j++) {
for (int k = 0; k < cols; k++)
printf (" %2d", array[i][j][k]);
putchar ('\n');
free (array[i][j]); /* free row of int (int*) */
}
free (array[i]); /* free matrix[i] pointers (int**) */
}
free (array); /* free matricies pointers (int***) */
}
(注意: 在释放每个矩阵中的行指针块的内存之前,先释放 int
的每个块的内存,然后再释放指针块每个矩阵)
示例Use/Output
$ ./bin/allocate_p2p2p
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址,因此,(2) 当不再需要时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入 beyond/outside 您分配的块的边界,尝试读取或基于未初始化的条件跳转值,最后,确认您释放了所有已分配的内存。
对于Linux valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。
$ valgrind ./bin/allocate_p2p2p
==9367== Memcheck, a memory error detector
==9367== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9367== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9367== Command: ./bin/allocate_p2p2p
==9367==
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
==9367==
==9367== HEAP SUMMARY:
==9367== in use at exit: 0 bytes in 0 blocks
==9367== total heap usage: 23 allocs, 23 frees, 2,528 bytes allocated
==9367==
==9367== All heap blocks were freed -- no leaks are possible
==9367==
==9367== For counts of detected and suppressed errors, rerun with: -v
==9367== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放所有分配的内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。