C语言中的可变大小矩阵

4

我如何在C语言中实现可变大小的矩阵(int类型)?为了澄清,我必须能够根据情况添加行和列(在if语句内部)。

谢谢,Vi。

6个回答

3
你可以编写一个可重用的组件,将界面与实现分离。你需要做出的主要决定是实现稀疏分配方案还是密集分配方案。
假设采用密集分配方案,对象可以在matrix.h中实现。
#include <stdio.h>

typedef struct matrix {
  int nrows, ncols, *data;
} matrix;

matrix* allocate(matrix *mat, int nrows, int ncols);
int *cell(const matrix *mat, int row, int col);
matrix *addrow(matrix *mat);
matrix *addcol(matrix *mat);
matrix *print(FILE *f, matrix *mat);

在 matrix.c 文件中。
#include "matrix.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>

matrix* allocate(matrix *mat, int nrows, int ncols)
{
  assert(nrows > 0 && ncols > 0);
  mat->nrows = nrows;
  mat->ncols = ncols;
  mat->data = malloc(sizeof(int) * nrows * ncols);
  return mat;
}

int *cell(const matrix *mat, int row, int col)
{
  assert(row >= 0 && row < mat->nrows);
  assert(col >= 0 && col < mat->ncols);
  return mat->data + row * mat->ncols + col;
}

matrix *addrow(matrix *mat)
{
  mat->nrows++;
  mat->data = realloc(mat->data, sizeof(int) * mat->nrows * mat->ncols);
  return mat;
}

/* adding a column it's an expensive operation */
matrix *addcol(matrix *mat)
{
  mat->ncols++;
  mat->data = realloc(mat->data, sizeof(int) * mat->nrows * mat->ncols);

  /* shift rows' elements, to make room for last column */
  for (int r = mat->nrows - 1; r > 0; --r)
  {
    int *dest = mat->data + r * mat->ncols,
        *orig = mat->data + r * (mat->ncols - 1);
    memmove(dest, orig, sizeof(int) * (mat->ncols - 1));
  }
  return mat;
}

matrix *print(FILE *f, matrix *mat)
{
    for (int r = 0; r < mat->nrows; ++r)
    {
        for (int c = 0; c < mat->ncols; ++c)
            fprintf(f, "%4d ", *cell(mat, r, c));
        fprintf(f, "\n");
    }
    return mat;
}

int main_matrix(int argc, char **argv)
{
    matrix m;
    allocate(&m, 3, 5);

    for (int r = 0; r < m.nrows; ++r)
        for (int c = 0; c < m.ncols; ++c)
            *cell(&m, r, c) = 35;
    print(stdout, &m);
    fprintf(stdout, "\n");

    addrow(&m);
    for (int c = 0; c < m.ncols; ++c)
        *cell(&m, m.nrows - 1, c) = 45;
    print(stdout, &m);
    fprintf(stdout, "\n");

    addcol(&m);
    for (int r = 0; r < m.nrows; ++r)
        *cell(&m, r, m.ncols - 1) = 46;
    print(stdout, &m);
    fprintf(stdout, "\n");

    // remember to free memory
    free(m.data);

    return argc;
}

测试输出:

  35   35   35   35   35 
  35   35   35   35   35 
  35   35   35   35   35 

  35   35   35   35   35 
  35   35   35   35   35 
  35   35   35   35   35 
  45   45   45   45   45 

  35   35   35   35   35   46 
  35   35   35   35   35   46 
  35   35   35   35   35   46 
  45   45   45   45   45   46 

2

我看您不想这样声明: int arr[5][5];

您可以使用mallocrealloc 来实现动态创建。例如,创建一个动态二维数组:

int nrows;
int ncolumns;

scanf("%d %d", &nrows, &ncolumns);

int **arr = malloc(nrows * sizeof(int *));
    for(i = 0; i < nrows; i++)
        arr[i] = malloc(ncolumns * sizeof(int));

如果你想改变大小,可以使用realloc。使用realloc的优点是,在无法在同一区域扩展内存的情况下,它会自动处理从原始内存位置复制值到新位置的操作。

请注意,这里是针对二维数组的。如果您想要更改维度本身或者想要能够修改维度,则可以编写类似上面的代码,并为每种情况编写不同的函数。同样,这看起来可能有些丑陋。但是在C中没有更加优雅的方法来做这些事情。


1

一旦你知道大小,你就必须在堆上分配足够的空间来容纳该大小。你可以使用malloccalloc在堆上分配空间。

例如:

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

void set_value(int * matrix, int row, int col, int value);
int get_value(int * matrix, int row, int col);

int main() {
    int rows = 5; /* arbitrary */
    int cols = 3; /* arbitrary */
    int * matrix = (int *) calloc(rows * cols, sizeof(int));

    if (matrix == NULL) {
        printf("Error with allocation!\n");
        return -1;
    }

    set_value(matrix, 0, 0, 5);
    set_value(matrix, 0, 1, 2);
    set_value(matrix, 4, 2, 1);

    printf("%d\n", get_value(matrix, 0, 0));
    printf("%d\n", get_value(matrix, 0, 1));
    printf("%d\n", get_value(matrix, 4, 2));

    free(matrix);

    return 0;
}

void set_value(int * matrix, int row, int col, int value) {
    *(matrix + col * sizeof(int) + row) = value;
}

int get_value(int * matrix, int row, int col) {
    return *(matrix + col * sizeof(int) + row);
}

请确保您始终检查对 malloccalloc 的调用是否成功,并始终使用 free 释放内存。

如果您需要调整矩阵的大小,则必须使用 realloc 或请求更多堆空间,将值复制到新空间中,并释放旧内存。


我开始时不知道大小。根据条件子句,我会逐步添加行和列。 - user1288707

1

仅仅因为C语言没有对面向对象的思想,如封装和信息隐藏提供语言支持,并不意味着你不能在你的代码中使用它们;你只需要更加努力地将它们付诸实践。

我已经很久没有写C语言了,但是斯坦福大学的Eric Roberts在一门C编程课程中教授了一些很棒的技巧。我建议你去了解一下。

这个想法是,你将不得不重新分配新大小矩阵的内存,将旧元素复制到其中,初始化新值,清理旧内存,并将新矩阵分配给指针变量。如果你将所有这些都隐藏在一个方法中,你的代码客户端只需调用它,而不必担心你在底层所做的魔术。你不必在多个地方重复这些复杂性。你只需要调用一个方法就可以完成。


0

我认为你可以使用动态内存分配函数"malloc"来创建缓冲区


1
欢迎来到SO!在回答问题时,请尽量具体,并在可能的情况下包含代码。 - lnafziger

-2

我刚写好了... 希望它能正常工作。

int **matrix;

int m=10;
int n=10;

int i,j;

matrix = (int)** malloc (m*sizeof(int*));
for(i=0;i<m;i++){
matrix[i]= (int)* malloc (n*sizeof(int));
for(j=0;j<n;j++)
matrix[i][j] = (10.0*rand());
}

free(matrix);

释放matrix时出现了大内存泄漏。 - William Morris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接