繁体   English   中英

C分配二维整数数组

[英]C allocating 2-dimensional integer array

我如何使用reallocmalloc声明一个全局变量二维整数数组,比如说int array[][]然后在给定xy数字后重新分配它,所以它是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/NULL0在数字类型的情况下, 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;
}

分配功能很简单。 它接受mn作为参数( 类型 size_t索引不能为负),并返回指向n int数组的m指针的完全分配,完全初始化的集合。 让我们看看它用于将my_array分配为int4x5矩阵的用法:

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()在这种情况下)。 在进行重新分配的调用之前,我们唯一需要保留在mainm的旧值(以允许使用值填充新空间,等等。)行的重新分配可能如下所示:

/* 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM