【问题标题】:Generic matrix: how to pass a type in a function argument通用矩阵:如何在函数参数中传递类型
【发布时间】:2013-05-23 07:45:27
【问题描述】:

我创建了一个这样的通用矩阵结构:

typedef struct mat_t {
  /**
   * \brief matrix structure
   */
  unsigned int c, l;
  void **matrice;
}* mat;

我的问题是学习如何为矩阵分配内存,因为它可以包含复数、浮点数或其他... 因此,我想知道如何将类型传递给我的函数参数以分配内存。

mat allocate_mat(unsigned int l, unsigned int c, **<type>** )

也许,我应该为此函数使用定义宏吗?

【问题讨论】:

  • 为什么不只传递类型的大小?比如,mat allocate_mat(unsigned int l, unsigned int c, unsigned int size) 然后这样称呼它:allocate_mat(10,5,sizeof(float))

标签: c generics matrix


【解决方案1】:

也许,我应该为此函数使用定义宏吗?

是的,你可以定义一个宏来接受最后一个参数的类型,然后调用真正的函数,这个函数在最后一个参数中接受一个大小。

#define allocate_mat(MAT_L, MAT_C, MAT_TYPE) allocate_mat_sz(MAT_L, MAT_C, sizeof(MAT_TYPE))
mat allocate_mat_sz (unsigned l, unsigned c, size_t size);

【讨论】:

  • 对不同的做事方式的不容忍总是让我感到惊讶。太没有灵感了。
  • 在没有任何解释的情况下投了反对票,这当然很糟糕。也许是因为您从本质上改变了语言,例如allocate_mat(2,3,float); 仅与您的宏一起编译。不过方法很有趣。
  • @MattPhillips:嗯,C 标准本身并不是没有先例。 va_arg() 浮现在脑海中。
  • @Jens:除了第二行是allocate_mat_sz()的函数原型,而宏是allocate_mat()的,扩展成对原型函数的调用。
  • 哈,我见过 va_* 构造,但从未使用过它们,直到 +1。
【解决方案2】:

问题 1:奇怪的变量名。 lc 应该是什么意思? “线”,“计数”? C 中没有任何东西可以阻止您使用完整的单词作为变量名...

问题 2:您最有可能使用带有指针对指针表示法的虚假 2D 数组,这会导致堆碎片惨败。它不仅速度慢并导致堆碎片,而且不能与 memset()、memcpy() 等基本 C 函数一起使用。而是在相邻内存中分配一个真正的二维数组。

问题3:为什么在struct typedef 的末尾有* mat?这没有任何意义。

这是一个动态矩阵的基本实现,使用通用 C 编程:

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

typedef struct mat_t
{
  void** data;
  size_t row_n;
  size_t col_n;
  size_t obj_size;
} matrix_t;


bool matrix_init (matrix_t* mat, 
                  size_t    row_n, 
                  size_t    col_n,
                  size_t    obj_size)
{
  mat->row_n = row_n;
  mat->col_n = col_n;
  mat->obj_size = obj_size;

  mat->data = calloc(row_n * col_n, obj_size);

  return mat->data != NULL;
}


void matrix_free (matrix_t* mat)
{
  free(mat);
}


void matrix_set (matrix_t* mat,
                 size_t    x,
                 size_t    y,
                 void*     val)
{
  size_t data_offset = y * mat->row_n * mat->obj_size + 
                       x * mat->obj_size;

  memcpy (mat->data + data_offset,
          val,
          mat->obj_size);
}


void* matrix_get (const matrix_t* mat,
                  size_t x,
                  size_t y)
{
  size_t data_offset = y * mat->row_n * mat->obj_size + 
                       x * mat->obj_size;

  return mat->data + data_offset;
}


int main()
{
  matrix_t mat;
  const int ROWS=3;
  const int COLS=2;

  // allocate memory
  matrix_init(&mat, ROWS, COLS, sizeof(int));


  // fill memory with data 1,2,3...
  int count =0;
  for(int row=0; row<ROWS; row++)
  {
    for(int col=0; col<COLS; col++)
    {
      count++;
      matrix_set (&mat, row, col, &count);
    }
  }

  // print the matrix
  for(int row=0; row<ROWS; row++)
  {
    printf("[ ");
    for(int col=0; col<COLS; col++)
    {
      printf("%d ", *(int*)matrix_get(&mat, row, col));
    }
    printf("]\n");
  }

  matrix_free(&mat);
  return 0;
}

【讨论】:

  • “没有任何意义”是什么意思?这就是 typedef 的本质! typedef struct mat_t {/*matrix*/ unsigned int c, l; void **matrice} * mat; 说,“这是struct mat_t 的样子,现在创建类型mat,它将是一个指向结构的指针struct mat_t。”
  • @ElchononEdelson 我的意思是,将指针声明隐藏在 typedef 后面没有任何意义,尤其是在这种情况下。它只会使代码容易出错且难以阅读。
  • 啊。从你说的方式来看,这一点都不清楚。然而,不管你认为它使代码容易出错且难以阅读,在我看来,这似乎是一个相当普遍的习惯用法。
  • @ElchononEdelson 软件错误也相当普遍。有很多不好的编程习惯是常用的,一个人可以写一整本书。
  • 指针结构定义在我看来很有意义,但感谢您的所有建议!
【解决方案3】:

您可以传递矩阵元素的大小:

mat allocate_mat(unsigned int l, unsigned int c, unsigned int size_of_matrix_element )

【讨论】:

  • 是的,但我的矩阵需要两个 malloc。所以,我需要两个 sizeof(),一个用于元素指针,一个用于元素。如果我只传递矩阵元素的大小,我该如何处理?
  • @user2412542 所有指针大小相同;例如sizeof(void*) 会告诉你它是什么。
  • @MattPhillips 好的,我认为使用 sizeof(void *) 制作 malloc 会是一个错误,但看起来不错!谢谢
  • 您可以使用多维数组的线性表示为您的矩阵分配内存: void matrix = malloc(row_countcolumn_columnsize_of_element);之后,您可以处理矩阵的任何元素: ((yourtype)&matrix[row*column_count+column])
猜你喜欢
  • 2021-11-20
  • 1970-01-01
  • 2019-04-08
  • 2013-09-10
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 2022-11-01
  • 1970-01-01
相关资源
最近更新 更多