Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

C-Kurs/Zahlen sagen/Musterlösung

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

/** Größe des Puffers für den Ergebnisstring */
#define BUFFER_SIZE 1000

/** Einerstellen zur allgemeinen Zusammensetzung. */
const char* EINER[] = {NULL, "eins", "zwei", "drei", "vier",
    "fünf", "sechs", "sieben", "acht", "neun"};

/** Zehnerstellen zur allgemeinen Zusammensetzung */
char* ZEHNER[] = {NULL, "zehn", "zwanzig", "dreißig", "vierzig",
    "fünfzig", "sechzig", "siebzig", "achtzig", "neunzig"};

/** Anzahl der vorhandenen Ausnahmen */
#define ANZAHL_AUSNAHMEN 18

/** Ausnahmen, die sich nicht zusammensetzen lassen. */
char* AUSNAHMEN[] =
	{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	 "elf", "zwölf", NULL, NULL, NULL, "sechzehn", "siebzehn"};
 
/** Anzahl der vorhandenen 1000er-Potenzen */
#define ANZAHL_POTENZEN 4

/** 1000er-Potenzen in ihrer Einzahl */
char* POTENZEN_SINGULAR[] = {"", "tausend", " Million ", " Milliarde ", " Billion "};

/** 1000er-Potenzen in ihrer Mehrzahl */
char* POTENZEN_PLURAL[] = {"", "tausend", " Millionen ", " Milliarden ", " Billionen "};


/**
 * Kopiert die übergebene Zahl 0 < x < 1000 als Zahlwort
 * in den übergebenen Puffer.
 */
 void say_short_number(long int x, char *buffer, int bufsize) {
	/* Hunderterstelle ausrechnen */
	int hunderter = x/100;
	if (hunderter > 0) {
		/* an den Pufferstring anhängen */
        if (hunderter == 1) {
            /* Ausnahme: "einhundert" statt "einshundert" */
            strncat(buffer, "ein", bufsize-strlen(buffer)-1);
        } else {
            strncat(buffer, EINER[hunderter], bufsize-strlen(buffer)-1);
        }
		strncat(buffer, "hundert", bufsize-strlen(buffer)-1);

		/* Hunderterstelle entfernen */
		x %= 100;
	}

	if ((x < ANZAHL_AUSNAHMEN) && (AUSNAHMEN[x] != NULL)) {
		/* eine Ausnahme wie "zwölf", oder */
		strncat(buffer, AUSNAHMEN[x], bufsize - strlen(buffer) - 1);
	} else {
		/* Rest aus Einer- und Zehnerstelle zusammensetzen */
		int zehner = x/10, einer = x%10;
		if (einer > 0)
			strncat(buffer, EINER[einer], bufsize - strlen(buffer) - 1);

		if (zehner > 0) {
			if ((zehner > 1) && (einer > 0))
				strncat(buffer, "und", bufsize - strlen(buffer) - 1);      /* ab 20 ein "und" einfügen */
			strncat(buffer, ZEHNER[zehner], bufsize - strlen(buffer) - 1);
		}
	}
}
 
/**
 * Generiert die natürlichsprachliche Repräsentation (Zahlwort) der
 * übergebenen Zahl und kopiert diese in den angegebenen Puffer.
 */
void say_number(long int x, char* buffer, int bufsize) {
	int i;
	
	/* Der Null kommt wie immer eine Sonderbehandlung zugute */
	if (x == 0) {
		strncat(buffer, "null", bufsize - strlen(buffer) - 1);
		return;
	}

	/* Alle relevanten 1000er-Potenzen durchgehen */
	for (i=ANZAHL_POTENZEN-1; i>=0;  i--) {
		/* Potenz für relevante Stellen ausrechnen */
		long int power = floor(pow(10, i*3) + 0.5);

		/* Stellen für diese Potenz extrahieren */
		int value = x/power;
		if (value > 0) {
			if ((value == 1) && (i >= 1)) {
                if (i == 1) {
                    /* Ausnahme: "eintausend" statt "einstausend" */
                    strncat(buffer, "ein", bufsize - strlen(buffer) - 1);
				} else {
                    /* Ausnahme: "eine Million" etc. statt "eins Million" */
                    strncat(buffer, "eine", bufsize - strlen(buffer) - 1);
				}
                /* Einzahl von Million etc. berücksichtigen */
                strncat(buffer, POTENZEN_SINGULAR[i], bufsize - strlen(buffer) - 1);
			} else {
				say_short_number(value, buffer, bufsize);
				strncat(buffer, POTENZEN_PLURAL[i], bufsize - strlen(buffer) - 1);
			}
            
			/* bereits ausgegebene Stellen abschneiden */
			x %= power;
		}
	}
}

int main(int argc, char **argv) {
    long int number;
    char *buffer;
    
	/* überprüfen, ob notwendige Kommandozeilenparameter angegeben wurden */
	if (argc != 2) {
		printf("Usage: %s NUMBER \n", argv[0]);
		exit(1);
	}

	/* numerischen String zu Ganzzahl konvertieren */
	number = atol(argv[1]);
	if (number <= 0 || number == LONG_MAX) {
        printf("Invalid number.\n");
		exit(1);
	}
	
	/* Puffer für Ergebnisstring allozieren */
	buffer = malloc(BUFFER_SIZE);
	if (!buffer) {
		printf("Unable to allocate memory.\n");
		exit(1);
	}
	
	/* Speicher mit Nullbyte initialisieren (= leerer String) */
	buffer[0] = '\0';

	/* Zahlwort in den Puffer schreiben */
	say_number(number, buffer, BUFFER_SIZE);
	
	/* und ausgeben */
	printf("%s\n", buffer);
	
	/* Speicher freigeben */
	free(buffer);

	/* Alles ok, Fehlercode 0 */
    return 0;
}