C Programma Rekenmachine
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 enprintf()voor uitvoer. - Controle structuren:
if-elsestatements enswitch-casevoor 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
- Definieer de vereisten (welke bewerkingen moeten worden ondersteund).
- Ontwerp de gebruikersinterface (command-line of menu-gedreven).
- Implementeer de logica voor elke bewerking.
- Voeg foutafhandeling toe (bijv. delen door nul).
- Test en debug de code.
- 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 (gebruikdoublevoor 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
intvoor gehele getallen endoublevoor 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
-O2of-O3voor 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 vansprintf(). - 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-tidyofcppcheckkunnen 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:
- GNU C Manual – Officiële documentatie voor de GNU C compiler.
- ISO/IEC 9899:2018 (C18 Standard) – De officiële C programmeertaal specificatie.
- GeeksforGeeks C Programming – Uitgebreide tutorials en voorbeelden voor C programmeren.
- cppreference.com – C Reference – Gedetailleerde referentie voor alle C standaard bibliotheek functies.
- TutorialsPoint C Programming – Stapsgewijze tutorials voor beginners.
Voor academische bronnen:
- Harvard CS50 – Week 2 (C Programming) – Inleiding tot C programmeren van Harvard University.
- C Programming For Beginners (Coursera) – Online cursus van de University of California.
- MIT Practical Programming in C – Cursusmateriaal van het Massachusetts Institute of Technology.
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!