如何在C中实现DRY原则来循环矩阵

时间:2016-04-22 06:58:02

标签: c loops dry

处理二维数组时,例如你需要经常访问元素的矩阵。直接的方法是通过两个嵌套循环:

for( int i=0; i < n; ++i ) {
  for( int j=0; j < m; ++j ) {
     // do something with data[i][j]
  }
}

这段代码原则经常在整个代码中反复复制。你是如何解决这个问题的?我认为解决这个问题的唯一方法是使用带函数指针的访问者函数,对吗?

编辑:为了更具建设性,我们假设你有矩阵类型typedef double** Matrix;

对于C ++,这可以通过这种方式解决:Loop over matrix elements applying variable function

2 个答案:

答案 0 :(得分:3)

第一份工作:考虑将data重新表示为代表矩阵的struct,或者,如果没有,则为简单的typedef。我假设你做了前者。

&#34; // do something with data[i][j]&#34;可以是函数(一个foo说),它将ij和指向矩阵struct的指针作为参数。

然后你只需要一个执行循环的函数:该函数将函数指针指向适当的foo和矩阵struct指针。

然后,您的工作就是根据您的要求实施各种foo

不要为此使用宏:它们使调试变得困难,特别是如果它们引入了ij这样的硬编码变量名称。

答案 1 :(得分:0)

感谢Bathsheba提供的提示,我终于提出了涉及功能指针的解决方案,我对此并不满意。主要问题是创建可能需要其他参数的特定功能。

注意:感谢joop,我们需要一个额外的函数调用,宏解决方案可能会省略它。

例如,这样的访问者重置具有给定值的所有矩阵元素。另一个访问者可能使用一组参数修改元素,或者甚至不需要单个参数。所以基本上我面对的是关于vistor函数类型的灵活定义的问题。

BTW:在C ++中,这可以通过std::bindtemplates来解决。

嵌套函数:

嵌套函数是GCC扩展名,例如不适用于Clang。尽管如此,这是代码示例:

typedef double** Matrix;     
typedef void (*MatrixElementVisitor) ( double* element );

void visitMatrixElements( Matrix m, size_t rows, size_t cols, MatrixElementVisitor fn ) {
  for( size_t i = 0; i < rows; ++i ) {
    for( size_t j = 0; j < cols; ++j ){
      fn( &m[i][j] );
    }
  }
}

void filM( Matrix m, size_t rows, size_t cols, double val ) {
  void fill( double *element ) {
    *element = val;
  }
  visitMatrixElements( m, rows, cols, fill );
}

Variadic功能:

typedef double** Matrix;
typedef void (*MatrixElementVisitor) ( double* element, va_list args );

void visitMatrixElements( Matrix m, size_t rows, size_t cols, MatrixElementVisitor fn, ... ) {
  va_list args,copy;
  va_start( args, fn );
  for( size_t i = 0; i < rows; ++i ) {
    for( size_t j = 0; j < cols; ++j ){
      va_copy( copy, args );
      fn( &m[i][j], copy );
      va_end( copy );
    }
  }
  va_end( args );
}

void fill( double *element, va_list args ) {
  *element = va_arg( args, double );
}

void filM( Matrix m, size_t rows, size_t cols, double val ) {
  visitMatrixElements( m, rows, cols, fill, val );
}

无效指针:

typedef double** Matrix;
typedef void (*MatrixElementVisitor) ( double* element, void *args );

void visitMatrixElements( Matrix m, size_t rows, size_t cols, MatrixElementVisitor fn, void *args ) {
  if( m ) {
    for( size_t i = 0; i < rows; ++i ) {
      if( m[i] ) {
        for( size_t j = 0; j < cols; ++j ){
          fn( &m[i][j], args );
        }
      }
    }
  }
}

void fill( double* element, void *args ) {
  if( !args ) {
    return;
  }
  *element = *((double*)args);
}


void filM( Matrix m, size_t rows, size_t cols, double val ) {
  visitMatrixElements( m, rows, cols, fill, &val );
}

也许存在其他方式,我想使用静态函数变量初始化访问者函数,也涉及可变函数。

感谢您的反馈。