如何为多维数组动态分配内存

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 个指针的内存块。

最后,您为每个矩阵中的每一行分配 colsint(类型 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)

始终确认您已释放所有分配的内存并且没有内存错误。

检查一下,如果您还有其他问题,请告诉我。