Rekenmachine Maken C

C Programma Rekenmachine

C Code:

                
Resultaat:
Uitleg:

Complete Gids: Een Rekenmachine Maken in C

Het maken van een rekenmachine in C is een uitstekende oefening voor beginnende programmeurs om vertrouwd te raken met de basisconcepten van programmeren, zoals variabelen, operators, controle structuren en functies. Deze gids behandelt alles wat je nodig hebt om een functionele rekenmachine in C te bouwen, van eenvoudige rekenkundige bewerkingen tot geavanceerdere functionaliteiten.

1. Basisconcepten voor een C Rekenmachine

1.1 Essentiële C Concepten

  • Variabelen en datatypes: Integers (int), floating-point numbers (float, double), en characters (char) zijn essentieel voor het opslaan van gebruikersinvoer en resultaten.
  • Operators: Rekenkundige operators (+, -, *, /, %), bitwise operators, en logische operators.
  • Invoer/uitvoer: Gebruik scanf() voor invoer en printf() voor uitvoer.
  • Controle structuren: if-else statements en switch-case voor het bepalen van welke bewerking moet worden uitgevoerd.
  • Functies: Modulaire code schrijven met functies voor elke bewerking.

1.2 Stappenplan voor het Bouwen van een Rekenmachine

  1. Definieer de vereisten (welke bewerkingen moeten worden ondersteund).
  2. Ontwerp de gebruikersinterface (command-line of menu-gedreven).
  3. Implementeer de logica voor elke bewerking.
  4. Voeg foutafhandeling toe (bijv. delen door nul).
  5. Test en debug de code.
  6. Optimaliseer en voeg extra functionaliteiten toe (bijv. geschiedenis, geavanceerde wiskundige functies).

2. Een Eenoudige Rekenmachine in C Bouwen

2.1 Basis Code Structuur

Hier is een eenvoudig voorbeeld van een rekenmachine die de vier basisbewerkingen (optellen, aftrekken, vermenigvuldigen, delen) ondersteunt:

#include <stdio.h>

int main() {
    char operator;
    double num1, num2, result;

    printf("Voer een operator in (+, -, *, /): ");
    scanf("%c", &operator);

    printf("Voer twee getallen in: ");
    scanf("%lf %lf", &num1, &num2);

    switch(operator) {
        case '+':
            result = num1 + num2;
            break;
        case '-':
            result = num1 - num2;
            break;
        case '*':
            result = num1 * num2;
            break;
        case '/':
            if (num2 != 0) {
                result = num1 / num2;
            } else {
                printf("Fout: Delen door nul is niet toegestaan.\n");
                return 1;
            }
            break;
        default:
            printf("Fout: Ongeldige operator.\n");
            return 1;
    }

    printf("Resultaat: %.2lf %c %.2lf = %.2lf\n", num1, operator, num2, result);
    return 0;
}

2.2 Uitleg van de Code

  • #include <stdio.h>: Standaard bibliotheek voor invoer/uitvoer functies.
  • char operator;: Slaat de operator op die door de gebruiker is ingevoerd.
  • double num1, num2, result;: Variabelen voor de getallen en het resultaat (gebruik double voor precisie).
  • scanf(): Leest de invoer van de gebruiker.
  • switch-case: Bepaalt welke bewerking moet worden uitgevoerd op basis van de operator.
  • Foutafhandeling voor delen door nul.

3. Geavanceerde Functionaliteiten Toevoegen

3.1 Bitwise Bewerkingen

Bitwise bewerkingen werken direct op de bits van gehele getallen. Voorbeelden zijn AND (&), OR (|), XOR (^), NOT (~), left shift (<<), en right shift (>>).

#include <stdio.h>

int main() {
    int num1, num2, result;
    char operator;

    printf("Voer een bitwise operator in (&, |, ^, ~, <<, >>): ");
    scanf("%c", &operator);

    if (operator != '~') {
        printf("Voer twee gehele getallen in: ");
        scanf("%d %d", &num1, &num2);
    } else {
        printf("Voer een geheel getal in: ");
        scanf("%d", &num1);
    }

    switch(operator) {
        case '&':
            result = num1 & num2;
            break;
        case '|':
            result = num1 | num2;
            break;
        case '^':
            result = num1 ^ num2;
            break;
        case '~':
            result = ~num1;
            break;
        case '<<':
            result = num1 << num2;
            break;
        case '>>':
            result = num1 >> num2;
            break;
        default:
            printf("Fout: Ongeldige operator.\n");
            return 1;
    }

    if (operator != '~') {
        printf("Resultaat: %d %c %d = %d\n", num1, operator, num2, result);
    } else {
        printf("Resultaat: %c%d = %d\n", operator, num1, result);
    }

    return 0;
}

3.2 Logische Bewerkingen

Logische bewerkingen (&&, ||, !) worden gebruikt om logische uitdrukkingen te evalueren. Deze returnen 1 (waar) of 0 (onwaar).

#include <stdio.h>

int main() {
    int num1, num2, result;
    char operator;

    printf("Voer een logische operator in (&&, ||, !): ");
    scanf(" %c", &operator); // Let op de spatie voor %c om witruimte te negeren

    if (operator != '!') {
        printf("Voer twee gehele getallen in (0 voor onwaar, niet-0 voor waar): ");
        scanf("%d %d", &num1, &num2);
    } else {
        printf("Voer een geheel getal in (0 voor onwaar, niet-0 voor waar): ");
        scanf("%d", &num1);
    }

    switch(operator) {
        case '&':
            result = num1 && num2;
            break;
        case '|':
            result = num1 || num2;
            break;
        case '!':
            result = !num1;
            break;
        default:
            printf("Fout: Ongeldige operator.\n");
            return 1;
    }

    if (operator != '!') {
        printf("Resultaat: %d %c %d = %d\n", num1, operator, num2, result);
    } else {
        printf("Resultaat: %c%d = %d\n", operator, num1, result);
    }

    return 0;
}

3.3 Geheugenallocatie Bewerkingen

In C kun je dynamisch geheugen alloceren met malloc(), calloc(), en realloc(). Deze functies returnen een pointer naar het gealloceerde geheugen.

#include <stdio.h>
#include <stdlib.h>

int main() {
    int size, count, i;
    char operation;
    int *ptr;

    printf("Kies een geheugen bewerking (m: malloc, c: calloc, r: realloc): ");
    scanf(" %c", &operation);

    switch(operation) {
        case 'm':
            printf("Voer de grootte in (bytes): ");
            scanf("%d", &size);
            ptr = (int*)malloc(size);
            if (ptr == NULL) {
                printf("Fout: Geheugenallocatie mislukt.\n");
                return 1;
            }
            printf("Geheugen succesvol gealloceerd met malloc(%d). Pointer: %p\n", size, ptr);
            free(ptr);
            break;

        case 'c':
            printf("Voer het aantal elementen en de grootte van elk element in: ");
            scanf("%d %d", &count, &size);
            ptr = (int*)calloc(count, size);
            if (ptr == NULL) {
                printf("Fout: Geheugenallocatie mislukt.\n");
                return 1;
            }
            printf("Geheugen succesvol gealloceerd met calloc(%d, %d). Pointer: %p\n", count, size, ptr);
            // Demonstreer dat calloc geheugen initialiseert naar 0
            for (i = 0; i < count; i++) {
                printf("ptr[%d] = %d\n", i, ptr[i]);
            }
            free(ptr);
            break;

        case 'r':
            printf("Voer de initiele grootte in (bytes): ");
            scanf("%d", &size);
            ptr = (int*)malloc(size);
            if (ptr == NULL) {
                printf("Fout: Geheugenallocatie mislukt.\n");
                return 1;
            }
            printf("Initieel geheugen gealloceerd met malloc(%d). Pointer: %p\n", size, ptr);

            printf("Voer de nieuwe grootte in (bytes): ");
            scanf("%d", &size);
            ptr = (int*)realloc(ptr, size);
            if (ptr == NULL) {
                printf("Fout: Geheugen herallocatie mislukt.\n");
                return 1;
            }
            printf("Geheugen succesvol hergealloceerd met realloc(..., %d). Nieuwe pointer: %p\n", size, ptr);
            free(ptr);
            break;

        default:
            printf("Fout: Ongeldige bewerking.\n");
            return 1;
    }

    return 0;
}

4. Foutafhandeling en Robuustheid

4.1 Veelvoorkomende Fouten en Hoe Ze te Vermijden

Fout Oorzaak Oplossing
Delen door nul Gebruiker voert 0 in als deler Controleer of de deler niet 0 is voordat je deelt
Ongeldige operator Gebruiker voert een niet-ondersteunde operator in Gebruik een switch-case met een default case voor foutafhandeling
Geheugenlek Gealloceerd geheugen wordt niet vrijgegeven Gebruik altijd free() na malloc(), calloc(), of realloc()
Buffer overflow Te veel data wordt in een array geschreven Gebruik veilige functies zoals fgets() in plaats van gets() en controleer array grenzen
Type mismatches Verkeerd datatype gebruikt in scanf() of bewerkingen Zorg ervoor dat de format specifiers in scanf() en printf() overeenkomen met de variabele types

4.2 Robuuste Invoer Validatie

Het valideren van gebruikersinvoer is cruciaal voor een betrouwbare rekenmachine. Hier is een voorbeeld van hoe je kunt controleren of de invoer een geldig getal is:

#include <stdio.h>
#include <stdbool.h>

bool isValidNumber(const char *input) {
    int i = 0;
    bool hasDecimal = false;

    // Controleer op leegte
    if (input[0] == '\0') return false;

    // Controleer op optioneel min-teken
    if (input[0] == '-') {
        i = 1;
        if (input[1] == '\0') return false; // Alleen een min-teken is ongeldig
    }

    // Controleer de rest van de karakters
    for (; input[i] != '\0'; i++) {
        if (input[i] == '.') {
            if (hasDecimal) return false; // Meer dan één decimaal punt
            hasDecimal = true;
        } else if (input[i] < '0' || input[i] > '9') {
            return false; // Geen cijfer
        }
    }

    return true;
}

int main() {
    char input[100];
    double number;

    printf("Voer een getal in: ");
    fgets(input, sizeof(input), stdin);

    // Verwijder newline karakter als aanwezig
    input[strcspn(input, "\n")] = '\0';

    if (!isValidNumber(input)) {
        printf("Fout: Ongeldige invoer. Voer een geldig getal in.\n");
        return 1;
    }

    // Converteer naar double
    if (sscanf(input, "%lf", &number) != 1) {
        printf("Fout: Kon het getal niet parsen.\n");
        return 1;
    }

    printf("Je hebt ingevoerd: %.2lf\n", number);
    return 0;
}

5. Geavanceerde Onderwerpen

5.1 Grafische Rekenmachine met ncurses

Voor een meer geavanceerde rekenmachine kun je de ncurses bibliotheek gebruiken om een tekstgebaseerde grafische interface te maken. Hier is een eenvoudig voorbeeld:

#include <ncurses.h>
#include <stdlib.h>
#include <string.h>

#define MAX_INPUT 50

void drawCalculator(WINDOW *win) {
    box(win, 0, 0);
    mvwprintw(win, 1, 1, "Rekmachine in C met ncurses");
    mvwprintw(win, 3, 1, "Voer een uitdrukking in (bijv. 2+3):");
    wrefresh(win);
}

double evaluateExpression(const char *expr) {
    // Deze functie zou een echte parser implementeren
    // Voor dit voorbeeld retourneert het gewoon een dummy waarde
    return 42.0;
}

int main() {
    WINDOW *win;
    char input[MAX_INPUT];
    double result;

    initscr();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);

    win = newwin(10, 50, (LINES - 10) / 2, (COLS - 50) / 2);

    drawCalculator(win);

    echo();
    mvwgetstr(win, 4, 1, input);
    noecho();

    result = evaluateExpression(input);
    mvwprintw(win, 6, 1, "Resultaat: %.2lf", result);
    wrefresh(win);

    getch();
    endwin();
    return 0;
}

Voor een complete implementatie zou je een parser moeten schrijven of een bibliotheek zoals exprtk gebruiken om wiskundige uitdrukkingen te evalueren.

5.2 Rekenmachine met Geschiedenis Functionaliteit

Je kunt een geschiedenis van berekeningen bijhouden met behulp van een array of linked list. Hier is een voorbeeld met een array:

#include <stdio.h>
#include <string.h>

#define MAX_HISTORY 10
#define MAX_EXPR_LEN 50

typedef struct {
    char expression[MAX_EXPR_LEN];
    double result;
} Calculation;

Calculation history[MAX_HISTORY];
int historyCount = 0;

void addToHistory(const char *expr, double res) {
    if (historyCount >= MAX_HISTORY) {
        // Verschuif alle elementen één positie naar voren
        for (int i = 1; i < MAX_HISTORY; i++) {
            strcpy(history[i-1].expression, history[i].expression);
            history[i-1].result = history[i].result;
        }
        historyCount--;
    }

    strcpy(history[historyCount].expression, expr);
    history[historyCount].result = res;
    historyCount++;
}

void printHistory() {
    printf("\nGeschiedenis van berekeningen:\n");
    for (int i = 0; i < historyCount; i++) {
        printf("%d: %s = %.2lf\n", i+1, history[i].expression, history[i].result);
    }
}

int main() {
    char expr[MAX_EXPR_LEN];
    double num1, num2, result;
    char op;

    while (1) {
        printf("\nVoer een uitdrukking in (bijv. 2+3) of 'q' om te stoppen: ");
        fgets(expr, MAX_EXPR_LEN, stdin);
        expr[strcspn(expr, "\n")] = '\0'; // Verwijder newline

        if (strcmp(expr, "q") == 0) break;

        if (sscanf(expr, "%lf%c%lf", &num1, &op, &num2) == 3) {
            switch(op) {
                case '+': result = num1 + num2; break;
                case '-': result = num1 - num2; break;
                case '*': result = num1 * num2; break;
                case '/':
                    if (num2 != 0) {
                        result = num1 / num2;
                    } else {
                        printf("Fout: Delen door nul.\n");
                        continue;
                    }
                    break;
                default:
                    printf("Fout: Ongeldige operator.\n");
                    continue;
            }
            printf("Resultaat: %.2lf\n", result);
            addToHistory(expr, result);
        } else {
            printf("Fout: Ongeldige invoer. Gebruik formaat zoals '2+3'.\n");
        }
    }

    printHistory();
    return 0;
}

5.3 Rekenmachine met Meerdere Datatypes

Je kunt de rekenmachine uitbreiden om verschillende datatypes te ondersteunen, zoals int, float, en double:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum { INT, FLOAT, DOUBLE } DataType;

typedef union {
    int intValue;
    float floatValue;
    double doubleValue;
} Value;

Value performOperation(DataType type, char op, Value a, Value b) {
    Value result;

    switch(type) {
        case INT:
            switch(op) {
                case '+': result.intValue = a.intValue + b.intValue; break;
                case '-': result.intValue = a.intValue - b.intValue; break;
                case '*': result.intValue = a.intValue * b.intValue; break;
                case '/':
                    if (b.intValue != 0) {
                        result.intValue = a.intValue / b.intValue;
                    } else {
                        printf("Fout: Delen door nul.\n");
                        exit(1);
                    }
                    break;
            }
            break;

        case FLOAT:
            switch(op) {
                case '+': result.floatValue = a.floatValue + b.floatValue; break;
                case '-': result.floatValue = a.floatValue - b.floatValue; break;
                case '*': result.floatValue = a.floatValue * b.floatValue; break;
                case '/':
                    if (b.floatValue != 0) {
                        result.floatValue = a.floatValue / b.floatValue;
                    } else {
                        printf("Fout: Delen door nul.\n");
                        exit(1);
                    }
                    break;
            }
            break;

        case DOUBLE:
            switch(op) {
                case '+': result.doubleValue = a.doubleValue + b.doubleValue; break;
                case '-': result.doubleValue = a.doubleValue - b.doubleValue; break;
                case '*': result.doubleValue = a.doubleValue * b.doubleValue; break;
                case '/':
                    if (b.doubleValue != 0) {
                        result.doubleValue = a.doubleValue / b.doubleValue;
                    } else {
                        printf("Fout: Delen door nul.\n");
                        exit(1);
                    }
                    break;
            }
            break;
    }

    return result;
}

int main() {
    DataType type;
    char typeStr[10], op;
    Value a, b, result;

    printf("Kies datatype (int, float, double): ");
    scanf("%s", typeStr);

    if (strcmp(typeStr, "int") == 0) {
        type = INT;
        printf("Voer twee integers in: ");
        scanf("%d %d", &a.intValue, &b.intValue);
    } else if (strcmp(typeStr, "float") == 0) {
        type = FLOAT;
        printf("Voer twee floats in: ");
        scanf("%f %f", &a.floatValue, &b.floatValue);
    } else if (strcmp(typeStr, "double") == 0) {
        type = DOUBLE;
        printf("Voer twee doubles in: ");
        scanf("%lf %lf", &a.doubleValue, &b.doubleValue);
    } else {
        printf("Fout: Ongeldig datatype.\n");
        return 1;
    }

    printf("Voer een operator in (+, -, *, /): ");
    scanf(" %c", &op);

    result = performOperation(type, op, a, b);

    switch(type) {
        case INT: printf("Resultaat: %d\n", result.intValue); break;
        case FLOAT: printf("Resultaat: %f\n", result.floatValue); break;
        case DOUBLE: printf("Resultaat: %lf\n", result.doubleValue); break;
    }

    return 0;
}

6. Optimalisatie en Best Practices

6.1 Code Optimalisatie

  • Gebruik efficiënte algoritmen: Voor complexe berekeningen, kies algoritmen met een lagere tijdcomplexiteit.
  • Vermijd onnodige berekeningen: Cache resultaten van dure bewerkingen als ze meerdere keren nodig zijn.
  • Gebruik de juiste datatypes: Kies int voor gehele getallen en double voor decimaal precisie.
  • Minimaliseer geheugengebruik: Geef geheugen vrij wanneer het niet meer nodig is om memory leaks te voorkomen.
  • Gebruik compiler optimalisaties: Compileer met flags zoals -O2 of -O3 voor betere prestaties.

6.2 Best Practices voor Onderhoudbare Code

  • Modulaire ontwerp: Verdeel de code in functies, elk met een enkele verantwoordelijkheid.
  • Duidelijke naamgeving: Gebruik beschrijvende namen voor variabelen en functies.
  • Commentaar: Voeg commentaar toe om complexe logica uit te leggen, maar vermijd overbodig commentaar.
  • Consistente stijl: Houd je aan een consistente codeerstijl (bijv. K&R, GNU, of Allman).
  • Foutafhandeling: Voeg robuuste foutafhandeling toe voor onverwachte invoer.
  • Testen: Schrijf unit tests om de functionaliteit van individuele functies te verifiëren.

6.3 VeiligheidsOverwegingen

  • Buffer overflows voorkomen: Gebruik veilige functies zoals snprintf() in plaats van sprintf().
  • Invoer validatie: Valideer altijd gebruikersinvoer om kwaadaardige invoer te voorkomen.
  • Geheugenbeheer: Zorg ervoor dat alle gealloceerde geheugen wordt vrijgegeven om memory leaks te voorkomen.
  • Integer overflows: Controleer op integer overflows bij rekenkundige bewerkingen.
  • Gebruik statische analyse tools: Tools zoals clang-tidy of cppcheck kunnen helpen bij het identificeren van potentiële problemen.

7. Vergelijking van Rekenmachine Implementaties

Hier is een vergelijking van verschillende benaderingen voor het implementeren van een rekenmachine in C:

Benadering Voordelen Nadelen Geschikt voor
Eenvoudige command-line Makkelijk te implementeren, weinig code Beperkte functionaliteit, geen grafische interface Beginners, eenvoudige berekeningen
Menu-gedreven Gebruiksvriendelijker, ondersteunt meerdere bewerkingen Meer code, complexere logica Intermediaire gebruikers, educatieve doeleinden
ncurses gebaseerd Interactieve interface, beter gebruikerservaring Vereist extra bibliotheek, complexere implementatie Geavanceerde gebruikers, projecten die een betere UI nodig hebben
GUI met GTK/Qt Volledige grafische interface, zeer gebruiksvriendelijk Vereist kennis van GUI frameworks, complexe implementatie Professionele toepassingen, eindgebruikers software
Web-based (CGI) Toegankelijk via webbrowser, platformonafhankelijk Vereist webserver, beveiligingsrisico’s Web applicaties, remote toegankelijke tools

8. Bronnen en Verdere Lezing

Voor meer informatie over programmeren in C en het bouwen van rekenmachines, raadpleeg de volgende bronnen:

Voor academische bronnen:

9. Veelgestelde Vragen

9.1 Hoe kan ik een rekenmachine in C maken die wiskundige functies zoals sin, cos, en sqrt ondersteunt?

Je kunt de wiskundige functies uit de math.h bibliotheek gebruiken. Hier is een voorbeeld:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

int main() {
    double angle, result;
    char func;

    printf("Kies een functie (s: sin, c: cos, t: tan, q: sqrt, l: log, e: exp): ");
    scanf("%c", &func);

    if (func != 'q') {
        printf("Voer een waarde in: ");
        scanf("%lf", &angle);
    } else {
        printf("Voer een positieve waarde in: ");
        scanf("%lf", &angle);
        if (angle < 0) {
            printf("Fout: Negatieve waarde voor vierkantswortel.\n");
            return 1;
        }
    }

    switch(func) {
        case 's':
            result = sin(angle);
            printf("sin(%.2lf) = %.2lf\n", angle, result);
            break;
        case 'c':
            result = cos(angle);
            printf("cos(%.2lf) = %.2lf\n", angle, result);
            break;
        case 't':
            result = tan(angle);
            printf("tan(%.2lf) = %.2lf\n", angle, result);
            break;
        case 'q':
            result = sqrt(angle);
            printf("sqrt(%.2lf) = %.2lf\n", angle, result);
            break;
        case 'l':
            if (angle <= 0) {
                printf("Fout: Logaritme gedefinieerd voor positieve getallen.\n");
                return 1;
            }
            result = log(angle);
            printf("log(%.2lf) = %.2lf\n", angle, result);
            break;
        case 'e':
            result = exp(angle);
            printf("exp(%.2lf) = %.2lf\n", angle, result);
            break;
        default:
            printf("Fout: Ongeldige functie.\n");
            return 1;
    }

    return 0;
}

Vergeet niet om met de -lm flag te compileren om de math bibliotheek te linken: gcc programma.c -o programma -lm.

9.2 Hoe kan ik een rekenmachine maken die complexe getallen ondersteunt?

Je kunt complexe getallen in C vertegenwoordigen met een struct of de ingebouwde complex.h bibliotheek (C99 en later). Hier is een voorbeeld met complex.h:

#include <stdio.h>
#include <complex.h>
#include <math.h>

int main() {
    double complex z1, z2, result;
    double real, imag;
    char op;

    printf("Voer het eerste complexe getal in (real imag): ");
    scanf("%lf %lf", &real, &imag);
    z1 = real + imag * I;

    printf("Voer een operator in (+, -, *, /): ");
    scanf(" %c", &op);

    printf("Voer het tweede complexe getal in (real imag): ");
    scanf("%lf %lf", &real, &imag);
    z2 = real + imag * I;

    switch(op) {
        case '+':
            result = z1 + z2;
            break;
        case '-':
            result = z1 - z2;
            break;
        case '*':
            result = z1 * z2;
            break;
        case '/':
            if (cabs(z2) == 0) {
                printf("Fout: Delen door nul.\n");
                return 1;
            }
            result = z1 / z2;
            break;
        default:
            printf("Fout: Ongeldige operator.\n");
            return 1;
    }

    printf("Resultaat: %.2lf %+.2lfi\n", creal(result), cimag(result));
    return 0;
}

9.3 Hoe kan ik mijn C rekenmachine uitbreiden met matrix bewerkingen?

Voor matrix bewerkingen kun je 2D arrays gebruiken. Hier is een eenvoudig voorbeeld voor matrix optelling en vermenigvuldiging:

#include <stdio.h>

#define MAX_SIZE 10

void addMatrices(int rows, int cols, int a[rows][cols], int b[rows][cols], int result[rows][cols]) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            result[i][j] = a[i][j] + b[i][j];
        }
    }
}

void multiplyMatrices(int rows1, int cols1, int a[rows1][cols1],
                     int rows2, int cols2, int b[rows2][cols2],
                     int result[rows1][cols2]) {
    if (cols1 != rows2) {
        printf("Fout: Aantal kolommen van eerste matrix moet gelijk zijn aan aantal rijen van tweede matrix.\n");
        return;
    }

    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols2; j++) {
            result[i][j] = 0;
            for (int k = 0; k < cols1; k++) {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
}

void printMatrix(int rows, int cols, int matrix[rows][cols]) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d\t", matrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int rows1, cols1, rows2, cols2;
    int a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE][MAX_SIZE], result[MAX_SIZE][MAX_SIZE];
    char op;

    printf("Voer het aantal rijen en kolommen voor matrix A in: ");
    scanf("%d %d", &rows1, &cols1);

    printf("Voer de elementen van matrix A in:\n");
    for (int i = 0; i < rows1; i++) {
        for (int j = 0; j < cols1; j++) {
            scanf("%d", &a[i][j]);
        }
    }

    printf("Voer een operator in (+, *): ");
    scanf(" %c", &op);

    if (op == '+') {
        printf("Voer het aantal rijen en kolommen voor matrix B in: ");
        scanf("%d %d", &rows2, &cols2);

        if (rows1 != rows2 || cols1 != cols2) {
            printf("Fout: Matrices moeten dezelfde afmetingen hebben voor optelling.\n");
            return 1;
        }

        printf("Voer de elementen van matrix B in:\n");
        for (int i = 0; i < rows2; i++) {
            for (int j = 0; j < cols2; j++) {
                scanf("%d", &b[i][j]);
            }
        }

        addMatrices(rows1, cols1, a, b, result);
        printf("Resultaat van optelling:\n");
        printMatrix(rows1, cols1, result);
    } else if (op == '*') {
        printf("Voer het aantal rijen en kolommen voor matrix B in: ");
        scanf("%d %d", &rows2, &cols2);

        printf("Voer de elementen van matrix B in:\n");
        for (int i = 0; i < rows2; i++) {
            for (int j = 0; j < cols2; j++) {
                scanf("%d", &b[i][j]);
            }
        }

        multiplyMatrices(rows1, cols1, a, rows2, cols2, b, result);
        printf("Resultaat van vermenigvuldiging:\n");
        printMatrix(rows1, cols2, result);
    } else {
        printf("Fout: Ongeldige operator.\n");
        return 1;
    }

    return 0;
}

9.4 Hoe kan ik mijn C rekenmachine een grafische interface geven?

Voor een grafische interface kun je bibliotheken zoals GTK, Qt, of zelfs SDL gebruiken. Hier is een eenvoudig voorbeeld met GTK:

#include <gtk/gtk.h>

static GtkWidget *entry;
static GtkWidget *result_label;

static void on_button_clicked(GtkWidget *widget, gpointer data) {
    const char *expr = gtk_entry_get_text(GTK_ENTRY(entry));
    // Hier zou je de expressie parsen en evalueren
    double result = 0; // Vervang dit met de echte berekening
    char result_str[50];
    snprintf(result_str, 50, "Resultaat: %.2lf", result);
    gtk_label_set_text(GTK_LABEL(result_label), result_str);
}

static void activate(GtkApplication *app, gpointer user_data) {
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *button;

    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Rekmachine");
    gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);

    grid = gtk_grid_new();
    gtk_container_add(GTK_CONTAINER(window), grid);

    entry = gtk_entry_new();
    gtk_grid_attach(GTK_GRID(grid), entry, 0, 0, 2, 1);

    button = gtk_button_new_with_label("Bereken");
    g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), NULL);
    gtk_grid_attach(GTK_GRID(grid), button, 0, 1, 1, 1);

    result_label = gtk_label_new("Resultaat: ");
    gtk_grid_attach(GTK_GRID(grid), result_label, 0, 2, 2, 1);

    gtk_widget_show_all(window);
}

int main(int argc, char **argv) {
    GtkApplication *app;
    int status;

    app = gtk_application_new("org.example.calculator", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

Om dit te compileren heb je de GTK ontwikkelbibliotheken nodig. Op Ubuntu/Debian kun je deze installeren met:

sudo apt-get install libgtk-3-dev

Compileer dan met:

gcc `pkg-config --cflags gtk+-3.0` programma.c -o programma `pkg-config --libs gtk+-3.0`

9.5 Hoe kan ik mijn C rekenmachine testen?

Testen is essentieel om ervoor te zorgen dat je rekenmachine correct werkt. Hier zijn enkele benaderingen:

  • Handmatig testen: Test elke bewerking handmatig met verschillende invoerwaarden, inclusief randgevallen.
  • Unit tests: Schrijf kleine testprogramma’s die individuele functies testen.
  • Automatische tests: Gebruik frameworks zoals Check of Unity voor geautomatiseerd testen.
  • Fuzz testing: Voer willekeurige invoer in om onverwacht gedrag te ontdekken.

Hier is een voorbeeld van een eenvoudig unit test framework:

#include <stdio.h>
#include <assert.h>

// De functie die we willen testen
int add(int a, int b) {
    return a + b;
}

// Test functie
void test_add() {
    assert(add(2, 3) == 5);
    assert(add(-1, 1) == 0);
    assert(add(0, 0) == 0);
    assert(add(100, 200) == 300);
    printf("Alle add tests geslaagd!\n");
}

int main() {
    test_add();
    return 0;
}

10. Conclusie

Het bouwen van een rekenmachine in C is een uitstekende manier om vertrouwd te raken met de fundamenten van programmeren. Door te beginnen met eenvoudige rekenkundige bewerkingen en geleidelijk aan geavanceerdere functionaliteiten toe te voegen, kun je je vaardigheden in C aanzienlijk verbeteren.

In deze gids hebben we de volgende onderwerpen behandeld:

  • Basisconcepten voor het bouwen van een rekenmachine in C
  • Implementatie van eenvoudige en geavanceerde rekenmachines
  • Foutafhandeling en robuustheid
  • Geavanceerde onderwerpen zoals bitwise bewerkingen, geheugenbeheer, en grafische interfaces
  • Testen en optimalisatie technieken

Met deze kennis kun je nu je eigen rekenmachine in C bouwen en uitbreiden met additional functionaliteiten naargelang je behoeften. Of je nu een eenvoudige command-line tool wilt maken of een geavanceerde grafische applicatie, de principes die in deze gids zijn besproken zullen je helpen om een robuuste en betrouwbare rekenmachine te creëren.

Vergeet niet om je code goed te documenteren, te testen, en te optimaliseren voor de beste prestaties en gebruikerservaring. Veel succes met je C programmeringsavonturen!

Leave a Reply

Your email address will not be published. Required fields are marked *