C Clean Code

C Clean Code


Wer sauberen Code schreibt, spart sich eine Menge stressige Stunden mit  Fehlersuchen! Was ist sauberer Code? Sauberer Code zielt darauf ab ein Programm möglichst verständlich zu schreiben und in sinnvolle Teile zu untergliedern.

Dieses Programm soll z.B. die Zahlen 1, …, 5 durchlaufen und bei jeder Primzahl n ((n + 1) / 2) ^ ((n - 1) / 2) ausgeben:

#include <stdio.h>
int main(void) {
       for(int n = 1; n <= 5; n++)
       {
             int chk = 1;
             for(int i = 2; i < n; i++) if(n % i == 0) { chk =  -1; break; }
             if(chk == 1) {
                    int v = 1;
                    for(int i = 1; i < (n - 1) / 2; i++) v *= (n + 1) / 2;
                    printf("result: %d\n", v);
             }
       } 

       return 0;

}


Ok das da oben ist ziemlicher Dreck! Wir wissen nicht, was das Programm macht und was uns der Programmierer uns damit sagen will. Das Programm ist schlecht strukturiert und die Variablen Null aussagekräftig. In dieser Form könnte es Stunden dauern den Fehler zu finden!

Schritt 1: Variablen umbenennen, Kommentare hinzufügen und das Programm ordentlich Formatieren.

#include <stdio.h>

int main(void)
{
       for(int number = 1; number <= 5; number++)
       {
             // überprüfe ob number eine primzahl ist
             int is_prime = 1;
             for(int i = 2; i < number; i++)
                    if(number % i == 0)
                    {
                           is_prime =  -1;
                           break;
                    } 

             if(is_prime == 1)
             {
                    // berechne ((number + 1) / 2) ^ ((number - 1) / 2)
                    int base = (number + 1) / 2;
                    int exp = (number - 1) / 2; 

                    int result = 1;
                    for(int i = 1; i < exp; i++)
                           result *= base;
      
                    // gib ergebnis aus
                    printf("result: %d\n", result);
             }
       } 

       return 0;
}



Das ist schon besser, aber dem Programm fehlt eine klare Struktur. Schauen wir uns das Ganze an, wenn das Programm in sinnvolle Funktionen untergliedert ist:

Schritt 2: Das Programm in separate, einfach zu testende, Teile untergliedern

#include <stdio.h>

/*
 * Überprüft, ob eine Zahl eine Primzahl (nur durch 1 und sich selbst teilbar ist)
 * Gibt 1 zurück, wenn dies der Fall ist und -1 sonst.
 */
int is_prime (int number)
{
       for(int i = 2; i < number; i++)
       {
             if(number % i == 0)
                    return -1;
       } 

       return 1;
} 

/*
 * Berechnet die potenz base ^ exp
 */
int pow(int base, unsigned int exp)
{
       int result = 1;
       for(int i = 1; i < exp; i++)
             result *= base;
       return result;
}

int main(void)
{
       for(int number = 1; number <= 5; number++)
       {
             if(is_prime(number) == 1)
             {
                    int base = (number + 1) / 2;
                    int exp = (number - 1) / 2;

                    printf("result: %d\n", pow(base, exp));
             }
       } 

       return 0;
}

Fertig!  

Jetzt ist das Fehlerfinden eine Sache von  3 bis 4 Minuten. Schauen wir uns einfach an, ob die Funktionen is_prime und exp ordentlich Funktionieren: 

int main(void)
{
       printf("TESTE: Primzahlen zwischen 1 und 5\n  Ausgabe:\n");
       for(int number = 1; number <= 5; number++)
       {
             if(is_prime(number) == 1)

                    printf("%d ", number);

       }

       printf("\n\n");
       printf("TESTE: pow\n  Ausgabe:\n");
       printf("%d ^ %d = %d\n", 3, 0, pow(3, 0));
       printf("%d ^ %d = %d\n", 3, 2, pow(3, 2));

       getchar();
       return 0;
}




Offensichtlicher Weise ist unsere pow Methode kaputt, denn scheinbar berechnen wir statt 3^2 3^1:

/*
 * Berechnet die potenz base ^ exp
 */
int pow(int base, unsigned int exp)
{
       int result = 1;

       // FIX: i müsste bei 0 beginnen, damit wir exp-mal
       // (von 0, 1, ...,exp-1) base aufmultiplizieren:
       for(int i = 1; i < exp; i++)
             result *= base;
       return result;
}


/*
 * Berechnet die potenz base ^ exp
 */
int pow(int base, unsigned int exp)
{
       int result = 1;
       // jetzt passt es!
       for(int i = 0; i < exp; i++)
             result *= base;
       return result;
}

Keine Kommentare:

Kommentar veröffentlichen

Inhalt