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

标签 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]);
        }
    }
}

我发现的唯一方法是更改​​原型(prototype):

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

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

如果是这样,我觉得这个 C99 改进并不是解决问题的 final方法,我认为解决矩阵管理的最好和简单的方法是使用经典的 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 之间的方程.

关于c - 我如何使用 malloc 在 C 中创建矩阵并避免内存问题?如何使用 C99 语法将矩阵传递给函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29981528/

相关文章:

c - C99 标准是否允许编译器转换代码,以便在满足某些推导条件后不再评估相同的表达式?

我能否在调试时准确控制函数返回的内容(即 rand())?

矩阵的 R 索引用于确定 R 中超过 8 小时的最大值的索引

r - "Large Matrix"和常规数值矩阵有什么区别?

c - 如何修复创建缓冲区并将其直接写入磁盘(WriteFile)

c - int 数组在末尾显示一个奇数

c++ - 这个指针类型是什么以及如何使用它?

c++ - 有没有办法告诉 C++ 中指针实际指向什么类型

用于删除指针的 C++ 仿函数似乎有效

matlab - 矩阵内的操作避免循环