How to implement DRY principle in C for cyclization over matrices

When working with two-dimensional arrays, for example. matrices, you need to frequent elements. The direct way to do this is with two nested loops:

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

This code principle is then often copied over and over throughout the code. How do you solve this to become DRY? I think the only way to solve this problem is to use the visitor function with function pointers, right?

Edit: To be more constructive, suppose you have a matrix type typedef double** Matrix; .

For C ++, this can be solved this way: The cycle of matrix elements using a variable function

+7
c loops dry
source share
2 answers

First assignment: consider the data transformation as a struct representing the matrix, or, if it is not, just a typedef . I guess you do the first.

" // do something with data[i][j] " can be a function (a foo say) that takes i , j and a pointer to a struct matrix as arguments.

Then you need only one function that executes the loop: this function takes a pointer to the corresponding foo and a pointer to the struct matrix.

Then your task is to implement various foo s, according to your requirements.

Do not use macros for this: they make debugging difficult, especially if they enter hard-coded variable names like i and j .

+3
source share

Thanks to Bathsheba for the tips, I finally came up with solutions containing pointers to functions that I'm not sure about. The main problem is the creation of specific functions that may require additional parameters.

Note. Thanks to joop, we need an extra function call, which can be omitted with a macro solution.

For example, such a visitor resets all matrix elements with a given value. Another visitor may change items using a set of parameters or not even need one parameter. So basically I come across the question of flexible type definition of a vistor function.

BTW: in C ++, this can be solved either using std::bind or using templates .

Nested Functions:

Nested functions are an extension of GCC and, for example, are not available in Clang. However, here is a sample code:

 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 functions:

 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 ); } 

void pointer:

 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 ); } 

Maybe there are other ways, I’m thinking about using static function variables to initialize the visitor function, also related to variational functions.

Thanks for your feedback.

0
source share

All Articles