繁体   English   中英

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

[英]How may I create a matrix in C using malloc and avoiding memory problems? How I can use C99 syntax to pass the matrix to a function?

有没有关于使用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语言管理它们!

使用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之间映射的等式。

我认为管理矩阵的更好方法是在下面的代码中。 下面的代码说明了如何使用单个malloc来管理矩阵,但是如果你需要使用矩阵样式m [y] [x],这段代码将向你展示如何只使用两个malloc而不是每行使用malloc 。

下面是代码,其中两个示例都在主要:

  • 第一个示例用(y + 1)* 100 +(x + 1)的值填充矩阵元素(y,x),并使用公式y * columns + x指向矩阵元素。 这涉及一个malloc。

  • 第二个示例使用(rows-y)* 100 +(columns-x)的值填充矩阵元素(y,x),并使用样式m [y] [x]指向矩阵元素。 这涉及两个mallocs然后使用更多字节的内存。

编码:

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

void print_matrix1(int *m, int r, int c);
void print_matrix2(int **m,int r,int c);

void print_matrix1(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*c+x]);
        }
    }
}

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_memory;

    int **matrix; /* for example 2 */

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

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

    /* Example one */
    for(y=0;y<rows;y++)
        for(x=0;x<columns;x++)
            matrix_memory[y*columns+x]=(y+1)*100+(x+1);

    print_matrix1(matrix_memory,rows,columns);
    puts("--------------------------------------------");

    /* Example two */
    matrix=malloc(sizeof(*matrix)*rows);
    if (matrix!=NULL) {
        for(y=0;y<rows;y++)
            matrix[y]=matrix_memory+y*columns;

        /* Enable to print the data of example 1 using matrix[y][x]
        print_matrix2(matrix,rows,columns);
        puts("--------------------------------------------");
        */

        for(y=0;y<rows;y++)
            for(x=0;x<columns;x++)
                matrix[y][x]=(rows-y)*100+(columns-x);

        print_matrix2(matrix,rows,columns);
    }

    /* end and free memory */
    free(matrix_memory);

    if (matrix!=NULL) {
        free(matrix);
        return 0;
    }

    return errno;
}

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

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*通过一次性分配矩阵成员及其缓冲区进行一些小的调整。

有一些微妙的点可以使动态创建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来解释为2D数组。 这种方法提供了一种更简单的方法来处理一维数组中的底层数组数据,但模拟二维数组的逻辑变得更加复杂,以适应底层的一维数组。 您可以自由地从包含size & stride信息的结构中删除label数据,我发现在使用多个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

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

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

它使用单个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;
}

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

来自函数lu分解的另一个问题数组由函数lu分解引用更早的问题https://stackoverflow.com/a/12462760/3088138 :自C99起,最短且最经济的矩阵分配是

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

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


根据http://c-faq.com/aryptr/ary2dfunc3.html ,传递可变长度2D阵列的方法是

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

....

f2(*matrix, m, n);

但是,您(可能)失去了从2D寻址到平面地址的隐式转换,您必须通过aryp[ncols*i+j]模拟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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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