2016-04-22 50 views
7

当处理二维数组时,您需要经常访问元素的矩阵。这样做的直接方法是通过两个嵌套循环:如何在C中实现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

+0

您可以创建一个可以生成这些循环的宏。 – Crozin

+0

是的,你可以在这种情况下使用函数或宏。 –

+0

一个宏可能是混乱的(对读者来说是非显而易见的)来调用或者会创建幻影隐藏的'i'和'j' vars(对读者来说也是非显而易见的),如果你创建隐藏的变量,他们也不能嵌套。 – DaveRandom

回答

3

第一份工作:考虑重铸datastruct代表矩阵,或者,做不到这一点,一个简单的typedef。我会假设你做前者。

// do something with data[i][j]”可以是功能(一个foo说),其采用ij,和一个指向矩阵struct作为参数。

然后你只需要一个函数,它的循环:该函数将功能指针到适当的foo,基质struct指针。

您的工作是根据您的要求,然后执行各种foo

不要使用宏:他们使调试困难,特别是如果他们采用硬编码的变量名状ij

+0

嗯,我想我需要像增强绑定这样的东西来制作量身定制的游客。到目前为止,嵌套函数(这是一个GCC扩展,我是这方面的一半:http://pastebin.com/3rUz9gEH)但我不会将宏用于符合标准的嵌套函数代码,也不会使用库依赖性,例如http://www.haible.de/bruno/packages-ffcall.html,参见例如http://stackoverflow.com/questions/216037/what-tools-are-there-for-functional-programming-in-c。也许它可能使用可变参数函数呢? – math

+0

使用可变参数函数的实现可能如下所示:http://pastebin.com/N8JtCfve – math

0

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

注意:感谢joop,因此我们需要一个额外的函数调用,这可能会在宏解决方案中被忽略。

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

顺便说一句:在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); 
} 

可变参数功能:

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

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

感谢您的反馈。

+0

请注意,回调函数不会内联,因此每个矩阵元素都需要实际的函数调用。 – joop