2016-04-22 5 views
7

Wenn mit zweidimensionalen Arrays, z. Matrizen müssen Sie Elemente oft besuchen. Der gerade vorwärts Weg, dies zu tun, ist durch zwei verschachtelte Schleifen:Wie DRY-Prinzip in C für das Looping über Matrizen zu implementieren

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

Dieser Code Prinzip dann oft kopiert werden immer und immer wieder über den gesamten Code. Wie löst man das, um DRY zu werden? Ich denke, der einzige Weg, dies zu lösen, ist eine Besucherfunktion mit Funktionszeigern, oder?

Edit: Um konstruktiver zu sein, nehmen wir an, Sie haben Matrix-Typ typedef double** Matrix;. Loop over matrix elements applying variable function

+0

Sie könnten ein Makro erstellen, das diese Schleifen generiert. – Crozin

+0

Ja, Sie könnten in diesen Fällen Funktion oder Makro verwenden. –

+0

Ein Makro wäre wahrscheinlich entweder chaotisch (nicht offensichtlich für den Leser) zu rufen oder würde Phantom versteckte "i" und "j" vars (auch nicht offensichtlich für den Leser) erstellen, Wenn Sie die versteckten vars erstellen, sie auch konnte nicht verschachtelt werden. – DaveRandom

Antwort

3

Erster Job: betrachten data als struct Neufassung der Matrix darstellt, oder andernfalls eine einfache typedef

Für C++ dies könnte auf diese Weise gelöst werden. Ich nehme an, Sie tun das erstere.

"// do something with data[i][j]" könnte eine Funktion sein (a foo sagen), die i, j und ein Zeiger auf die Matrix struct als Argument annimmt.

Dann brauchen Sie nur eine Funktion, die die Looping tut: die Funktion übernimmt die Funktion Zeiger auf einen geeigneten foo und die Matrix struct Zeiger.

Ihre Aufgabe ist es dann, die verschiedenen foo s entsprechend Ihren Anforderungen zu implementieren.

hierfür nicht Verwendung von Makros tun: Das Debugging schwierig, vor allem, wenn sie hartcodierte Variablennamen wie i und j einzuführen.

+0

Hmm, ich denke, ich brauche etwas wie Boost Bind, um maßgeschneiderte Besucher zu machen. Bisher bei verschachtelten Funktionen (die eine GCC-Erweiterung sind bin ich halbwegs dabei: http://pastebin.com/3rUz9gEH) Aber ich werde keine Makros für standardkonformen Code verschachtelter Funktionen verwenden, noch eine Bibliotheksabhängigkeit wie http://www.haible.de/bruno/packages-ffcall.html, siehe z http://StackOverflow.com/Questions/216037/What-Tools-are-there-Funktions-Programming-in-c. Vielleicht ist es möglich, variadic Funktionen dafür zu verwenden? – math

+0

Die Implementierung mit Variadic-Funktionen könnte so aussehen: http://pastebin.com/N8JtCfve – math

0

Dank Bathsheba, um Hinweise zu geben, habe ich schließlich Lösungen mit Funktionszeigern entwickelt, mit denen ich nicht vertraut bin. Das Hauptproblem ist die Erstellung der spezifischen Funktionen, die zusätzliche Parameter benötigen könnten.

Hinweis: Dank Joop benötigen wir daher einen zusätzlichen Funktionsaufruf, der bei einer Makrolösung entfallen kann.

Zum Beispiel setzt ein solcher Besucher alle Matrixelemente mit einem gegebenen Wert zurück. Ein anderer Besucher kann die Elemente mit einer Reihe von Parametern modifizieren oder braucht nicht einmal einen einzigen Parameter. Im Grunde stelle ich mich der Frage nach einer flexiblen Definition des Funktionstyps "vistor".

BTW: In C++ kann dies entweder mit std::bind oder mit templates gelöst werden.

Nested Funktionen:

verschachtelte Funktionen sind eine Erweiterung GCC und z.B. Nicht verfügbar mit Clang.Dennoch ist hier das Codebeispiel:

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

Variadische Funktionen:

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

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

Vielleicht andere Möglichkeiten gibt es, glaube ich statische Funktion des Verwendens Variablen für die Initialisierung der Besucherfunktion, auch mit variadischen Funktionen.

Vielen Dank für Ihr Feedback.

+0

Beachten Sie, dass Callback-Funktionen nicht inline sind, so dass ein tatsächlicher Funktionsaufruf für jedes Matrixelement erforderlich ist. – joop