如何使用malloc在C中创建矩阵并避免内存问题?我如何使用C99语法将矩阵传递给函数?

时间:2015-05-01 04:16:59

标签: c pointers matrix malloc

您是否有充分说明使用malloc函数为矩阵分配内存空间?

在这些日子里,当我需要使用malloc来管理它们时,我看到许多编码器以“坏”的方式对矩阵进行编码。我觉得我错了吗?

我所说的“坏”代码示例如下:

int main()
{
    char **row;
    int width=80, height=24, i, j;

    row = malloc(height * sizeof(char *));
    for(i = 0; i < width; i++)
        row[i] = malloc(width * sizeof(char));

    for(i = 0; i < height; i++)
    {
        for(j = 0; j < width; j++)
        {
            row[i][j] = i*j;
        }
    }

    return 0;
}

在上面的代码中,我发现至少有三个问题:

  • 强烈破坏记忆。

  • 它使用的内存超过了必要的

  • 它使用于矩阵的内存不连续。

有人建议我使用这种C99语法的有趣方法:

int (*matrix)[columns] = malloc(sizeof(int[rows][columns]));

现在我需要将此变量矩阵传递给以下函数:

void print_matrix2(int **m,int r,int c)
{
    int y,x;

    for(y=0;y<r;y++) {
        for(x=0;x<c;x++) {
            printf("(%2d,%2d) = %04d; ",y+1,x+1,m[y][x]);
        }
    }
}

我发现的唯一方法是改变原型:

void print_matrix2(int (*m)[5],int r,int c);

但是我想避免[5]声明,我希望能够向我的函数发送我想要的任何数量的列!

如果是这样,我觉得C99的改进不是解决问题的最终解决方案,我认为解决矩阵管理的最好和最简单的方法是使用经典的C语言管理它们!

5 个答案:

答案 0 :(得分:3)

使用malloc()分配连续的内存块:

some_datatype_t* matrix = NULL;
matrix = malloc(nrows * ncols * sizeof(some_datatype_t));
if (!matrix) { 
    perror("malloc failed");
    exit(ENOMEM); 
}

编写一个取消引用单元格的函数:

some_datatype_t 
get_value_from_matrix_at_index_ij(some_datatype_t* mtx, 
                                  uint32_t ncols, 
                                  uint32_t i, 
                                  uint32_t j) 
{
    return mtx[i + i * (ncols - 1) + j];
}

或者是二传手:

void
set_value_for_matrix_at_index_ij(some_datatype_t** mtx_ptr,
                                 uint32_t ncols, 
                                 uint32_t i, 
                                 uint32_t j,
                                 some_datatype_t val) 
{
    *mtx_ptr[i + i * (ncols - 1) + j] = val;
}

当你完成它时,不要忘记free()你的矩阵:

free(matrix), matrix = NULL;

以下是3x4矩阵的示例:

    0  1  2  3
  ------------
0 | 0  1  2  3
1 | 4  5  6  7
2 | 8  9 10 11

它有3行4列(ncols = 4)。

以线性化形式,其单元格如下所示:

0 1 2 3 4 5 6 7 8 9 10 11

要在某个零索引行i和列j中查找单元格内容,您可以计算在固定时间内取消引用的索引或地址:

{1, 2} = matrix[1 + 1*3 + 2] = matrix[6]
{2, 3} = matrix[2 + 2*3 + 3] = matrix[11]
etc.

如果你想将一些有用的属性隐藏到一个干净的包中,你甚至可以把它包含在struct中:

typedef struct matrix {
    some_datatype_t* data;
    uint32_t nrows;
    uint32_t ncols;
} matrix_t;

然后,您只需初始化并传递指向matrix_t变量的指针:

matrix_t*
init_matrix(uint32_t nrows, uint32_t ncols) 
{
    matrix_t *m = NULL;
    m = malloc(sizeof(matrix_t));
    if (!m) { /* error */ }
    m->data = NULL;
    m->data = malloc(nrows * ncols * sizeof(some_datatype_t));
    if (!m->data) { /* error */ }
    m->nrows = nrows;
    m->ncols = ncols;
    return m;
}

some_datatype_t 
get_value_from_matrix_at_index_ij(matrix_t* mtx,
                                  uint32_t i, 
                                  uint32_t j) 
{
    return mtx->data[i + i * (mtx->ncols - 1) + j];
}

void
set_value_for_matrix_at_index_ij(matrix_t** mtx_ptr,
                                 uint32_t i, 
                                 uint32_t j,
                                 some_datatype_t val) 
{
    (*mtx_ptr)->data[i + i * ((*mtx_ptr)->ncols - 1) + j] = val;
}

void
delete_matrix(matrix_t** m) 
{
    free((*m)->data), (*m)->data = NULL;
    free(*m), *m = NULL;
}

如果您正在使用对称方阵,则可以利用对称性并使用一半的内存。有时,如果对角线的存储可以被移除(例如,相关或其他对称统计分数),则存储器的一半以下。

主要是,这里的想法是考虑如何编写一个在矩阵索引对(i, j)和一些连续数组索引k之间映射的等式。

答案 1 :(得分:2)

这里有一些结构可以让连续的矩阵更容易使用。

struct Matrix
{
    int width;
    int height;
    int* ptr;
};

static struct Matrix matrix_create(int width, int height)
{
    struct Matrix new_matrix;
    new_matrix.width = width;
    new_matrix.height = height;
    new_matrix.ptr = malloc(width * height * sizeof(int));
    return new_matrix;
}

static void matrix_destroy(struct Matrix* m)
{
    free(m->ptr);
}

static int* matrix_row(struct Matrix* m, int row)
{
    return m->ptr + row * m->width;
}

int main()
{
    int r = 0;
    int c = 0;
    struct Matrix m = matrix_create(80, 24);

    for (r=0; r < m.height; ++r)
    {
        int* row = matrix_row(&m, r);
        for (c=0; c < m.width; ++c)
            row[c] = r * m.width + c;
    }
    matrix_destroy(&m);
}

我们还可以通过一次性分配矩阵成员及其缓冲区,使用可变长度的结构只使用struct Matrix*进行一些小的调整。

答案 2 :(得分:1)

有一些微妙的要点可以使动态创建2D基质更加健壮,并且不太可能提供无意识读取未初始化值的机会(未定义的行为)。您可以做出的第一项改进是使用calloc分配列数组,以便在分配时每个单元的内存已初始化为zero - 0。这允许在整个矩阵上立即迭代,而无法读取未初始化的值。看看以下内容:

#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);
}

**创建5x4矩阵并重新分配到**

$ ./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)

在单个块中分配的矩阵 - Stride确定尺寸

这是另一个创建单个维度数组的示例,通过设置stride来定义每行/列中要考虑的元素数量,将其解释为2D数组。这种方法提供了一种更简单的方法来处理一维数组中的底层数组数据,但模拟二维数组的逻辑变得更加复杂,以适应底层的一维数组。您可以从包含label信息的结构中删除size & stride数据,我发现使用多个stride设置时很方便。这是一个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef _STDINT_H
    typedef unsigned char uchar;
    typedef unsigned int  uint;
    typedef unsigned long ulong;
#endif

/** struct mdata defines matrix metadata for size, stride, label and lblsz.
*
*  struct mdata defines metadata for handling array of numbers as 2d array.
*/
typedef struct mdata
{
    int size;
    int stride;
    char *label;
    size_t lblsz;

} mdata;

/* function prototypes */
void mtrx_prnmatrix (int *m, mdata *md);
void mtrx_prnrow (int *m, mdata *md, int v);
void mtrx_prncol (int *m, mdata *md, int v);
void mtrx_showmdata (mdata *md);
long mtrx_getval (int *m, mdata *md, int x, int y);
long mtrx_setval (int *m, mdata *md, int x, int y, int val);
int mtrx_setlable (mdata *md, char *s);
int mtrx_setstride (mdata *md, int stride);
void free_mtrxmd (mdata *md);

int main (int argc, char **argv) {

    /* static for testing, you can allocate this single block */
    int mtrx[] = { 1, 2, 3, 4, 5, 6,
                7, 8, 9, 10, 11, 12,
                13, 14, 15, 16, 17, 18,
                19, 20, 21, 22, 23, 24,
                25, 26, 27, 28, 29, 30,
                31, 32, 33, 34, 35, 36 };

    int sz = 36;
    int stride = 6;
    int vreq = 0;
    mdata *m1d;

    m1d = malloc (sizeof *m1d);
    m1d-> size = sz;
    m1d-> stride = stride;
    m1d-> label = strdup ("m1d (6x6)");
    m1d-> lblsz = strlen (m1d-> label);

    if (argc < 2 ) {
        fprintf (stderr, "Error: insufficient input, usage: %s int (vector [0-5])\n", argv[0]);
        return 1;
    }

    /* show the metadata */
    mtrx_showmdata (m1d);

    /* set the vector request - use strtol for error check */
    vreq = atoi (argv[1]);

    /* print the full matrix */
    mtrx_prnmatrix (mtrx, m1d);

    printf ("\n");

    /* print the requested column vector */
    mtrx_prncol (mtrx, m1d, vreq);

    /* print the requested row vector */
    mtrx_prnrow (mtrx, m1d, vreq);

    /* set a new stride for matrix (set new temp label) */
    mtrx_setstride (m1d, 4);
    mtrx_showmdata (m1d);

    /* set a new label for matrix */
    mtrx_setlable (m1d, "m1d (9x4)");
    mtrx_showmdata (m1d);

    /* print the full updated matrix */
    mtrx_prnmatrix (mtrx, m1d);
    printf ("\n");

    /* set a new stride and label for matrix */
    mtrx_setstride (m1d, 3);
    mtrx_setlable (m1d, "m1d (12x3)");
    mtrx_prnmatrix (mtrx, m1d);
    printf ("\n");

    /* set a new stride and label for matrix */
    mtrx_setstride (m1d, 2);
    mtrx_setlable (m1d, "m1d (18x2)");
    mtrx_prnmatrix (mtrx, m1d);
    printf ("\n");

    /* mtrx_getval test */
    mtrx_showmdata (m1d);
    mtrx_setval (mtrx, m1d, 9, 1, 99);
    int i = 0;
    for (i = 0; i < (m1d-> size / m1d-> stride); i++) {
        printf (" mtrx [%2d,%2d] : %2ld\n", i, 0, mtrx_getval (mtrx, m1d, i, 0));
        printf (" mtrx [%2d,%2d] : %2ld\n", i, 1, mtrx_getval (mtrx, m1d, i, 1));
    }
    printf ("\n");

    /* free data allocated to metadata */
    free_mtrxmd (m1d);

    return 0;
}

/** mtrx_prnmatrix (int *, int, mdata *) print matrix in row x column format.
*
*  mtrx_prnmatrix print matrix in row x column format with metadata label.
*/
void mtrx_prnmatrix (int *m, mdata *md)
{
    int i = 0;

    if (!md) {
        fprintf (stderr, "error: metadata structure not initialized\n");
    }

    printf ("Matrix: %s\n", md->label);
    for (i = 0; i < md-> size; i++)
        if (((i + 1) % md-> stride) == 0)
            if (i == (md->size - 1))
                printf (" %2d ]\n", m[i]);
            else
                printf (" %2d\n", m[i]);
        else
            if (i == 0)
                printf ("[%2d", m[i]);
            else
                printf (" %2d", m[i]);
}

/** mtrx_prnrow (int *, mdata *, int) prints row vector.
*
*  mtrx_prnrow prints matrix row vector based on metadata.
*/
void mtrx_prnrow (int *m, mdata *md, int v)
{
    register int it = v;

    if (!md) {
        fprintf (stderr, "error: metadata structure not initialized\n");
    }
    if (v > md-> size/md-> stride - 1 || v < 0) {
        fprintf (stderr, "error: invalid rvector (%d), valid: 0 < rvector < max (%d)\n",
                v, md-> size/md-> stride);
        return;
    }

    if (md-> label) printf ("Matrix: %s -- row vector: %d\n", md-> label, v);

    for (it = v * md-> stride; it < (v * md-> stride) + md-> stride; it++)
        printf (" %d", m[it]);

    printf ("\n");
}

/** mtrx_prncol (int *, mdata *, int) prints column vector.
*
*  mtrx_prncol prints matrix column vector based on metadata.
*/
void mtrx_prncol (int *m, mdata *md, int v)
{
    register int it = v;

    if (!md) {
        fprintf (stderr, "error: metadata structure not initialized\n");
    }
    if (v > md-> size/md-> stride - 1 || v < 0) {
        fprintf (stderr, "error: invalid vector (%d), valid: 0 < vector < max (%d)\n",
                v, md-> size/md-> stride);
        return;
    }

    if (md-> label) printf ("Matrix: %s -- column vector: %d\n", md-> label, v);

    for (it = v; it < md-> size; it += md-> stride)
        printf (" %d\n", m[it]);
}

/** mtrx_showmdata (mdata *) prints metadata struct.
*
*  mtrx_showmdata prints label, size, stride and lblsz metadata.
*/
void mtrx_showmdata (mdata *md)
{
    printf ("\n label : %s\n size  : %d\n stride: %d\n lblsz : %zd\n\n",
            md-> label, md-> size, md-> stride, md-> lblsz);
}

/** mtrx_getval (int *, mdata *, int, int, int) retrieves value at position x,y).
*
*  mtrx_getval gets the value at the give position within the matrix based on x, y indexes.
*/
long mtrx_getval (int *m, mdata *md, int x, int y)
{
    if (x * y > md-> size) {
        fprintf (stderr, "%s()  error: invalid index, (x * y) > size.\n", __func__);
        return -1;
    }
    if (x > (md-> size / md-> stride - 1)) {
        fprintf (stderr, "%s()  warning: invalid metadata index, (x > %d).\n",
                __func__, md-> size/md-> stride - 1);
    }
    if (y > (md-> stride - 1)) {
        fprintf (stderr, "%s()  warning: invalid metadata index, (y > %d).\n", __func__, md-> stride - 1);
    }
    return m[(x * md-> stride) + y];
}

/** mtrx_setval (int *, mdata *, int, int, int) sets value at position x,y).
*
*  mtrx_setval set the value at the give position within the matrix based on x, y indexes.
*/
long mtrx_setval (int *m, mdata *md, int x, int y, int val)
{
    if (x * y > md-> size) {
        fprintf (stderr, "%s()  error: invalid index, (x * y) > size.\n", __func__);
        return -1;
    }
    if (x > (md-> size / md-> stride - 1)) {
        fprintf (stderr, "%s()  warning: invalid metadata index, (x > %d).\n",
                __func__, md-> size/md-> stride - 1);
    }
    if (y > (md-> stride - 1)) {
        fprintf (stderr, "%s()  warning: invalid metadata index, (y > %d).\n", __func__, md-> stride - 1);
    }
    return m[(x * md-> stride) + y] = val;
}

/** mtrx_setlable (mdata *, char *) sets new label in metadata struct.
*
*  mtrx_setlable sets new label metadata and updates lblsz.
*/
int mtrx_setlable (mdata *md, char *s)
{
    if (!md) {
        fprintf (stderr, "%s()  error: metadata structure not initialized\n", __func__);
        if (!(md = malloc (sizeof (md)))) {
            fprintf (stderr, "%s()  metadata structure allocation failed \n", __func__);
            return 0;
        }
    }

    if (!s) {
        fprintf (stderr, "%s()  error: string not initialized\n", __func__);
        return 0;
    }

    md-> lblsz = strlen (s);

    char *tmp = realloc (md-> label, md-> lblsz + 1);
    if (!tmp) {
        fprintf (stderr, "%s()  error: metadata - label realloc failed.\n", __func__);
        return 0;
    }
    strncpy (tmp, s, md-> lblsz + 1);
    md-> label = tmp;

    return 1;
}

/** mtrx_setstride (mdata *, int) sets new stride in metadata struct.
*
*  mtrx_setstride validates and sets new stride metadata with temp label.
*/
int mtrx_setstride (mdata *md, int stride)
{
    char newlabel[256];
    int newrows = 0;

    if (!md) {
        fprintf (stderr, "%s()  error: metadata structure not initialized\n", __func__);
        md = malloc (sizeof (md));
        if (!md)
            fprintf (stderr, "%s()  metadata structure allocated\n", __func__);
        else {
            fprintf (stderr, "%s()  metadata structure allocation failed \n", __func__);
            return 0;
        }
    }

    if (stride < 1) {
        fprintf (stderr, "%s()  error: invalid (stride < 1) supplied.\n", __func__);
        return 0;
    }

    if (md-> size % stride) {
        fprintf (stderr, "%s()  error: invalid stride (size %% stride != 0)\n", __func__);
        return 0;
    }

    md-> stride = stride;

    newrows = md-> size / stride;
    sprintf (newlabel, "%s -> now (%dx%d)", md->label, newrows, stride);
    mtrx_setlable (md, newlabel);

    return 1;
}

void free_mtrxmd (mdata *md)
{
    if (md-> label) free (md-> label);
    if (md) free (md);
}

<强>输出

$ /bin/mtrx_metadata_new 4

 label : m1d (6x6)
 size  : 36
 stride: 6
 lblsz : 9

Matrix: m1d (6x6)
[ 1  2  3  4  5  6
  7  8  9 10 11 12
 13 14 15 16 17 18
 19 20 21 22 23 24
 25 26 27 28 29 30
 31 32 33 34 35 36 ]

Matrix: m1d (6x6) -- column vector: 4
 5
 11
 17
 23
 29
 35
Matrix: m1d (6x6) -- row vector: 4
 25 26 27 28 29 30

 label : m1d (6x6) -> now (9x4)
 size  : 36
 stride: 4
 lblsz : 22


 label : m1d (9x4)
 size  : 36
 stride: 4
 lblsz : 9

Matrix: m1d (9x4)
[ 1  2  3  4
  5  6  7  8
  9 10 11 12
 13 14 15 16
 17 18 19 20
 21 22 23 24
 25 26 27 28
 29 30 31 32
 33 34 35 36 ]

Matrix: m1d (12x3)
[ 1  2  3
  4  5  6
  7  8  9
 10 11 12
 13 14 15
 16 17 18
 19 20 21
 22 23 24
 25 26 27
 28 29 30
 31 32 33
 34 35 36 ]

Matrix: m1d (18x2)
[ 1  2
  3  4
  5  6
  7  8
  9 10
 11 12
 13 14
 15 16
 17 18
 19 20
 21 22
 23 24
 25 26
 27 28
 29 30
 31 32
 33 34
 35 36 ]


 label : m1d (18x2)
 size  : 36
 stride: 2
 lblsz : 10

 mtrx [ 0, 0] :  1
 mtrx [ 0, 1] :  2
 mtrx [ 1, 0] :  3
 mtrx [ 1, 1] :  4
 mtrx [ 2, 0] :  5
 mtrx [ 2, 1] :  6
 mtrx [ 3, 0] :  7
 mtrx [ 3, 1] :  8
 mtrx [ 4, 0] :  9
 mtrx [ 4, 1] : 10
 mtrx [ 5, 0] : 11
 mtrx [ 5, 1] : 12
 mtrx [ 6, 0] : 13
 mtrx [ 6, 1] : 14
 mtrx [ 7, 0] : 15
 mtrx [ 7, 1] : 16
 mtrx [ 8, 0] : 17
 mtrx [ 8, 1] : 18
 mtrx [ 9, 0] : 19
 mtrx [ 9, 1] : 99
 mtrx [10, 0] : 21
 mtrx [10, 1] : 22
 mtrx [11, 0] : 23
 mtrx [11, 1] : 24
 mtrx [12, 0] : 25
 mtrx [12, 1] : 26
 mtrx [13, 0] : 27
 mtrx [13, 1] : 28
 mtrx [14, 0] : 29
 mtrx [14, 1] : 30
 mtrx [15, 0] : 31
 mtrx [15, 1] : 32
 mtrx [16, 0] : 33
 mtrx [16, 1] : 34
 mtrx [17, 0] : 35
 mtrx [17, 1] : 36

答案 3 :(得分:1)

为矩阵分配空间的另一种非常原始的方法可能是在下面,正如朋友在这个问题的评论中所建议的那样。

这是一种冒险的方法,可能会使调试代码变得非常困难。

它使用单个malloc来分配所有空间来管理样式m [y] [x]中的矩阵。

我更喜欢我在第一个回复中指出的最简单的方法:使用分配了malloc的单个数组,并使用m [y * ncols + x]指向其中。这种简单的方法使用较少的内存,我认为其他方法更快! (但我从来没有验证它的速度!)

这里有其他(危险的)代码:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void print_matrix2(int **m,int r,int c)
{
    int y,x;

    for(y=0;y<r;y++) {
        for(x=0;x<c;x++) {
            printf("(%2d,%2d) = %04d; ",y+1,x+1,m[y][x]);
        }
    }
}

int main(void)
{
    int **matrix; /* for example 2 */

    int rows=11,columns=5,x,y;

    matrix = malloc(sizeof(*matrix)*rows + sizeof(**matrix) * rows * columns);
    if (matrix==NULL)
        return errno;

    printf("Size of an int %lu\n",sizeof(int));
    puts("Memory allocation");
    printf("matrix:%p\n&matrix[0]:%p &matrix[%d]:%p\n",matrix,&matrix[0],rows-1,&matrix[rows-1]);

    puts("--------------------------------------");

    for(y=0;y<rows;y++) {
        matrix[y]=(int *)((void *)matrix+sizeof(*matrix)*rows)+y*columns;
        printf("matrix[%d]:%p matrix[%d+1]:%p\n",y,matrix[y],y+1,matrix[y]+columns);
    }
    puts("--------------------------------------");

    /* Fill the matrix */
    for(y=0;y<rows;y++)
        for(x=0;x<columns;x++)
            matrix[y][x]=(y+1)*100+(x+1);

    print_matrix2(matrix,rows,columns);


    /* end and free memory */
    free(matrix);
    return 0;
}

此代码打印出内存分配,以便我们验证内存分配。

答案 4 :(得分:0)

另一个问题array by malloc on function lu decomposition引用了更早的问题https://stackoverflow.com/a/12462760/3088138:自C99以来,最短且最经济的矩阵分配是

float (*matrix)[n] = malloc(sizeof(float[m][n]));

避免了分层指针到指针的结构。

Per http://c-faq.com/aryptr/ary2dfunc3.html,传递可变长度2D数组的方法是

void f2(float *aryp, int nrows, int ncols);

....

f2(*matrix, m, n);

但是,您(可能)失去了从2D寻址到扁平地址的隐式转换,您必须通过matrix[i][j]模拟aryp[ncols*i+j]

可以非破坏性地传递平面2D阵列,在c-faq链接的源代码示例中提供为f4(仅与C99一样)。示例,适用于最新版本的gcc:

#include <stdlib.h>
#include <stdio.h>

void print_matrix( int nrows, int ncols, float mat[nrows][ncols]) {
    int i,j;
    for(i=0; i<nrows; i++) {
        for(j=0; j<ncols; j++) printf("%10.4e\t", mat[i][j]);
        puts("");
    }
}

int main() {
    int m=5, n = 10;
    float (*matrix)[n] = malloc(sizeof(float[m][n]));

    int i,j;
    for(i=0; i<m; i++) {
        for(j=0; j<n; j++) matrix[i][j] = i+1.0/(1+j);

    }
    print_matrix(m,n,matrix);
    return 0;
}