[英]C allocating 2-dimensional integer array
我如何使用realloc
和malloc
声明一个全局变量二维整数数组,比如说int array[][]
然后在给定x
和y
数字后重新分配它,所以它是int array[x][y]
?
在C中模拟2D数组或矩阵时,有几点要考虑。首先要了解您实际分配的内容。 为了模拟您可以简单地通过array[m][n]
访问的2D数组,您要做的是首先将m
指针数组分配给int指针 。 这提供了m
int*
(或行),您可以用来分配n
int (列)。
简而言之,您将m pointers to 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:\n\n", m, n);
mtrx_prn (m, n, matrix);
/* reallocate matrix - add 4 rows */
printf ("\nReallocate matrix to %zux%zu:\n\n", 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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.