如何使用realloc
和malloc
声明全局变量二维整数数组,比如int array[][]
,然后在给定x
和y
的数字后重新分配它,使其成为int array[x][y]
?
在C中模拟2D数组或矩阵时需要考虑几点。首先了解实际分配的内容。要模拟只通过array[m][n]
访问的2D数组,首先要将一个m
指针数组分配给指向int的指针。这提供了可用于分配n
int(列)的m
int*
(或行)。
简单地说,您可以分配m pointers to int*
行和n int
列。
现在,在我们查看代码之前,有一个实用的选择,您可以选择是使用malloc
来分配内存(特别是列),还是使用calloc
。为什么?在尝试访问数组的某个元素之前,必须初始化该元素以保持某些值。否则,任何从该元素读取的尝试都是从未初始化的值读取的尝试,该值是尚未定义的行为,并可能使您的程序陷入无路可走的境地。。
为什么calloc
而不是malloc
。calloc
不仅为您分配空间,还将该位置的内存初始化/设置为0/NULL
(如果是数字类型,则为0
,如果是指针,则为NULL
——两者都是有效的0
)。这可以防止未初始化元素的意外读取,因为所有元素一开始都初始化为0
。现在,您可以自由地设置一个循环,并以这种方式将每个值设置为0
(或其他任何值),但新的C程序员通常会忽略这一点。所以calloc
可以帮助保护你免受伤害。让我们来看一个分配函数:
/* allocate/initialize mxn matrix */
int **mtrx_calloc (size_t m, size_t n)
{
register size_t i;
int **array = calloc (m, sizeof *array);
if (!array) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.n", __func__);
exit (EXIT_FAILURE);
}
for (i = 0; i < m; i++)
{
array[i] = calloc (n, sizeof **array);
if (!array[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.n", __func__);
exit (EXIT_FAILURE);
}
}
return array;
}
分配函数是直接的。它接受m
和n
作为参数(类型size_t
--索引不能为负),并返回一组完全分配、完全初始化的指向n
int
数组的m
指针。让我们看看它用于将my_array
分配为int
:的4x5
矩阵
int **my_array = mtrx_calloc (4, 5);
在代码的其余部分,您可以通过my_array[0-3][0-4]
访问任何元素(索引是零基的,就像C中的其余索引一样)
realloc
呢?当您谈论固定大小的数组时,您需要重新分配内存的唯一时间是是否需要调整数组的大小。(现在你可以创建一个新数组并复制旧的/新的)然而,由于重新分配内存在C中是一个重要的概念,让我们写一个函数来重新分配矩阵的行数。
假设您现在发现需要my_array
作为8x5
矩阵,而不是4x5
矩阵。在这种情况下,您需要realloc
的数量pointers to int*
,以允许添加更多的4
行。您还需要分配空间来保存行5-8
(索引4-7
)的新值。
您还需要跟踪已分配的行数,因此,如果我们发送一个指向当前行数的指针,我们可以更新该地址的值,并在调用函数中返回该值(在本例中为main()
)。在调用重新分配之前,我们唯一需要在main
中保留的是m
的旧值(以允许用值等填充新空间)。我们对行的重新分配可能如下所示:
/* realloc an array of pointers to int* setting memory to 0. */
int **realloc_rows (int **ap, size_t *m, size_t n, size_t newm)
{
if (newm <= *m) return ap;
size_t i = 0;
int **tmp = realloc (ap, newm * sizeof *ap);
if (!tmp) {
fprintf (stderr, "%s() error: memory reallocation failure.n", __func__);
// return NULL;
exit (EXIT_FAILURE);
}
ap = tmp;
for (i = *m; i < newm; i++)
{
ap[i] = calloc (n, sizeof **ap);
if (!ap[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.n", __func__);
exit (EXIT_FAILURE);
}
}
*m = newm;
return ap;
}
现在需要注意的是,我们不会直接将新重新分配的值分配给数组变量,而是分配给tmp
变量。为什么?如果重新分配失败,realloc
将释放新分配的空间并返回NULL
,如果我们将realloc
的返回分配给数组,这将导致我们的数据完全丢失。通过使用tmp
阵列,您可以根据需要灵活地处理故障。重新分配4个额外行的示例调用如下所示:
my_array = realloc_rows (my_array, &m, n, m + 4);
这是对2D矩阵/阵列的概述,比我最初想要的要长得多,但即使是一组简单的函数,也需要考虑很多因素来动态分配和重新分配模拟的2D阵列。接下来,我们将给您留下一个示例。默认情况下,该示例将创建一个3x4 2D数组,但您也可以将大小指定为程序的参数。例如:
./programname 4 5
将创建一个初始的4x5 2D阵列,而不是默认阵列。为了显示realloc的使用,无论最初分配的大小如何,都将调整大小以添加4行,并用其他值填充新行。原始尺寸和重新分配的尺寸阵列都被打印到stdout
。如果您有问题,请告诉我:
/*
gcc -Wall -Wextra -o progname progname.c
*/
#include <stdio.h>
#include <stdlib.h>
int **mtrx_calloc (size_t m, size_t n); /* initialize elements to 0 */
int **realloc_rows (int **ap, size_t *m, size_t n, size_t newm); /* resize newm x n */
void mtrx_prn (size_t m, size_t n, int **matrix); /* print matrix with/pad */
void mtrx_free (size_t m, int **matrix); /* free memory allocated */
int main (int argc, char **argv)
{
/* set initial size from arguments given (default: 3 x 4) */
size_t m = argc > 2 ? (size_t)atoi (argv[1]) : 3;
size_t n = argc > 2 ? (size_t)atoi (argv[2]) : 4;
/* allocate the m x n matrix */
int **matrix = mtrx_calloc (m, n);
/* fill with misc values */
register size_t i = 0, j = 0;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
matrix [i][j] = (int)(i + j);
}
/* print matrix */
printf ("nThe dynamically allocated %zux%zu matrix is:nn", m, n);
mtrx_prn (m, n, matrix);
/* reallocate matrix - add 4 rows */
printf ("nReallocate matrix to %zux%zu:nn", m + 4, n);
size_t oldm = m;
matrix = realloc_rows (matrix, &m, n, m + 4);
/* fill new rows with misc values */
for (i = oldm; i < m; i++)
{
for (j = 0; j < n; j++)
matrix [i][j] = (int)(i + j);
}
mtrx_prn (m, n, matrix);
/* free memory alocated */
mtrx_free (m, matrix);
/* just to make it look pretty */
printf ("n");
return 0;
}
/* allocate/initialize mxn matrix */
int **mtrx_calloc (size_t m, size_t n)
{
register size_t i;
int **array = calloc (m, sizeof *array);
if (!array) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.n", __func__);
exit (EXIT_FAILURE);
}
for (i = 0; i < m; i++)
{
array[i] = calloc (n, sizeof **array);
if (!array[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.n", __func__);
exit (EXIT_FAILURE);
}
}
return array;
}
/* realloc an array of pointers to int* setting memory to 0. */
int **realloc_rows (int **ap, size_t *m, size_t n, size_t newm)
{
if (newm <= *m) return ap;
size_t i = 0;
int **tmp = realloc (ap, newm * sizeof *ap);
if (!tmp) {
fprintf (stderr, "%s() error: memory reallocation failure.n", __func__);
// return NULL;
exit (EXIT_FAILURE);
}
ap = tmp;
for (i = *m; i < newm; i++)
{
ap[i] = calloc (n, sizeof **ap);
if (!ap[i]) { /* validate allocation */
fprintf (stderr, "%s() error: memory allocation failed.n", __func__);
exit (EXIT_FAILURE);
}
}
*m = newm;
return ap;
}
/* print a (m x n) matrix (check pad alloc) */
void mtrx_prn (size_t m, size_t n, int **matrix)
{
register size_t i, j;
for (i = 0; i < m; i++)
{
char *format = "[ %2d";
for (j = 0; j < n; j++)
{
printf (format, matrix [i][j]);
format = ", %2d";
}
puts(" ]");
}
}
void mtrx_free (size_t m, int **matrix)
{
register size_t i;
for (i = 0; i < m; i++)
{
free (matrix [i]);
}
free (matrix);
}
创建4x5矩阵并重新分配到8x5
$ ./bin/mtrx_dyn_int 4 5
The dynamically allocated 4x5 matrix is:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
Reallocate matrix to 8x5:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
[ 4, 5, 6, 7, 8 ]
[ 5, 6, 7, 8, 9 ]
[ 6, 7, 8, 9, 10 ]
[ 7, 8, 9, 10, 11 ]
检查内存错误/泄漏
$ valgrind ./bin/mtrx_dyn_int 4 5
==31604== Memcheck, a memory error detector
==31604== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==31604== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==31604== Command: ./bin/mtrx_dyn_int 4 5
==31604==
The dynamically allocated 4x5 matrix is:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
Reallocate matrix to 8x5:
[ 0, 1, 2, 3, 4 ]
[ 1, 2, 3, 4, 5 ]
[ 2, 3, 4, 5, 6 ]
[ 3, 4, 5, 6, 7 ]
[ 4, 5, 6, 7, 8 ]
[ 5, 6, 7, 8, 9 ]
[ 6, 7, 8, 9, 10 ]
[ 7, 8, 9, 10, 11 ]
==31604==
==31604== HEAP SUMMARY:
==31604== in use at exit: 0 bytes in 0 blocks
==31604== total heap usage: 10 allocs, 10 frees, 256 bytes allocated
==31604==
==31604== All heap blocks were freed -- no leaks are possible
==31604==
==31604== For counts of detected and suppressed errors, rerun with: -v
==31604== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
C没有2D数组。它有数组和指针数组,每一个都可以类似于2D数组使用。不幸的是,realloc()
对这两种情况都不了解。您可以realloc()一个指针数组,然后新的指针将为null,必须自己分配,并且所有现有的行仍然是旧的大小,必须重新定位。您也可以重新分配一个数组数组,但仅当次要维度相同时,也就是说,如果您最初分配了一个10x10数组,您可以将其重新分配到20x10,但不能重新分配到10x20(否则现有值将被移到奇怪的地方)。
由于您不是试图调整矩阵的大小,而是使用动态维度进行初始化,因此当您知道您的x和y时,可以通过调用malloc()来完成:
int **global_array;
void main() {
// ...
if (allocateMatrixDynamically(3, 5) == 0) {
// We can now set a value
global_array[0][0] = 11;
}
//...
}
// This functions returns zero if allocation was succesful, and !=0 otherwise
int allocateMatrixDynamically(int rows, int cols) {
int idxRow, idxCol;
int RCod = -1;
// Allocate the memory as requested
if (rows > 0 && cols > 0) {
global_array = (int**) malloc(rows * sizeof(int*));
if (!global_array) {
return -1;
}
for (idxRow=0; idxRow< rows; ++idxRow) {
global_array[idxRow] =(int*) malloc(cols * sizeof(int));
if (!global_array[idxRow]) {
return -1;
}
}
}
return 0;
}