你没有 SegFaulted 只是偶然的,因为指针的大小没有改变。因此,在您为 int* 分配的地方,您应该为 int** 分配的地方,您的分配大小不会受到影响(偶然发生...)
您通常希望避免成为三星级程序员,但有时,就像在这种情况下,这是必需的。在分配任何指针,或指针到指针,或者在这种情况下为指针到指针到指针的情况下,请理解不涉及任何“数组”。
当您声明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 指针 来设置 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 的每个块的内存,然后再释放每个矩阵中的行指针块的内存)
使用/输出示例
$ ./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
内存使用/错误检查
在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此 (2) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后, 以确认您已释放所有已分配的内存。
对于 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)
始终确认您已释放已分配的所有内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。