/* Einfache Adressenverwaltung AN DEN STELLEN MIT DER KENNZEICHNUNG "FUNKTION IMPLEMENTIEREN" DEN ENTSPRECHENDEN CODE EINFUEGEN. ES HANDELT SICH UM FOLGENDE FUNKTIONEN: adressenListeEinfuegen adressenListeLoeschenn adressenListeSuchen Kompilieren (erzeugt ausfuehrbare Datei a.out): gcc AdressenListe.c Ausfuehren: ./a.out kommandos.txt */ #include /* stdio = Standard Input/Output */ #include /* stdlib = Standard Library */ #include typedef int bool; /* C hat keinen boolean-Datentyp */ #define TRUE 1 #define FALSE 0 #define STRING_MAX_SIZE 256 /* maximale Stringlaenge 255 Zeichen, das */ /* 256. Zeichen wird fuer das */ /* Stringendezeichen ('\0') benoetigt */ #define FORMAT_STRING "%255s" /* Formatstring fuer fscanf setzen */ /* maximale Stringlaenge 255 Zeichen */ /* readString Einlesen einer Zeichenkette aus einer Datei Parameter: file - file pointer string - Zeiger auf das char-Array Rueckgabe: TRUE, wenn eine Zeichenkette gelesen werden konnte FALSE, sonst Bemerkung: Die maximale Stringlaenge ist in der Konstanten FORMAT_STRING festgelegt */ int readString (FILE* file, char* string) { /* fscanf liest in diesem Fall eine Zeichenkette aus einer Datei. Dabei werden zunaechst fuehrende whitespaces (d.h. Leerzeichen, Tabs und Zeilenumbrueche) ueberlesen. Es werden solange Zeichen in das char-Array eingelesen, bis die maximale Zeichenanzahl (im FORMAT_STRING angegeben) erreicht ist oder als naechstes Zeichen ein whitespace folgt */ int result = fscanf (file, FORMAT_STRING, string); return (result != EOF) ? TRUE : FALSE; } /* ListenElement Datenstruktur zum Abspeichern einer Adresse sowie der Verkettungsinformation */ struct ListenElement { struct ListenElement* nachfolger; char* name; char* strasse; char* ort; }; /* wir machen uns das Leben leichter: Ohne diesen typedef muessten wir im folgenden immer struct ListenElement* e; schreiben. Mit dem typedef reicht ListenElement* e; aus. */ typedef struct ListenElement ListenElement; /* listenElementErzeugen Erzeugt ein Listenelement, dabei werden die Adressinformationen gesetzt und der Zeiger auf den Nachfolger geloescht Parameter: name, strasse, ort - Adressinformationen Rueckgabe: Zeiger auf das neu erzeugt Listenelement JAVA: In Java wuerden wir hierfuer den Konstruktor nehmen */ ListenElement* listenElementErzeugen (const char* name, const char* strasse, const char* ort) { /* Speicher fuer das Listenelement anlegen INFO Die Funktion void *malloc (size_t size) aus der Bibliothek stdlib.h allokiert die Anzahl der Bytes, die in "size" angegeben ist. Sie liefert einen Zeiger auf den Speicherblock. Allerdings ist dieser Zeiger vom Typ void*, d.h. wir benoetigen einen cast, um den Zeiger auf den richtigen Datentyp zu setzen Weitere Infos mit "man 3 malloc" (unter Unix) */ ListenElement* neuesElement = (ListenElement*) malloc (1 * sizeof (ListenElement)); if (neuesElement == NULL) { /* INFO printf ist vergleichbar mit System.out.println (...) unter Java */ printf ("Nicht genuegend Speicher vorhanden.\n"); /* INFO Die Funktion void exit(int status) stammt aus stdlib.h. Sie bewirkt den Abbruch des Programms. Der Wert in status wird an das Betriebssystem uebergeben. Weitere Infos mit "man 3 exit" (unter Unix) */ exit (1); } /* Speicher fuer die Adressinformation anlegen */ neuesElement->name = (char*) malloc (STRING_MAX_SIZE * sizeof(char)); neuesElement->strasse = (char*) malloc (STRING_MAX_SIZE * sizeof(char)); neuesElement->ort = (char*) malloc (STRING_MAX_SIZE * sizeof(char)); if (neuesElement->name == NULL || neuesElement->strasse == NULL || neuesElement->ort == NULL) { printf ("Nicht genuegend Speicher vorhanden.\n"); exit (1); } neuesElement->nachfolger = NULL; /* es gibt keinen Nachfolger */ /* Adressinfos kopieren INFO Die Funktion char *strcpy(char *dest, const char *src); stammt aus string.h. Es wird die Zeichenkette auf die src zeigt in den Bereich kopiert auf den dest verweist. Weitere Infos mit "man 3 strcpy" (unter Unix) */ strcpy (neuesElement->name, name); strcpy (neuesElement->strasse, strasse); strcpy (neuesElement->ort, ort); return neuesElement; } /* listenElementZerstoeren Gibt den Speicher eines Listenelements frei Parameter: Das zuzerstoerende Listenelement JAVA: Dank garbage collection ist eine explizite Speicherfreigabe nicht noetig */ void listenElementZerstoeren (ListenElement* e) { /* INFO Die Funktion void free(void *ptr) aus stdlib.h gibt den Speicher auf den der Zeiger ptr verweist frei. Eine Angabe der Groesse des freizugebenden Speicherbereichs ist nicht notwendig, da dieses vom Betriebssystem ermittelt wird. Weitere Infos mit "man 3 free" (unter Unix). */ free (e->name); /* Speicher fuer die Adressinfos freigeben */ free (e->strasse); free (e->ort); free (e); /* Speicher fuer das Listenelement freigeben */ } /* listenElementAusgeben Gibt die Adressinformationen eines Listenelements aus Parameter: Listenelement, dessen Adressinfos ausgegeben werden sollen JAVA: In Java brauchen wir den Parameter e nicht, da haben wir die Referenz "this". */ void listenElementAusgeben (ListenElement* e) { printf ("%s;%s;%s\n", e->name, e->strasse, e->ort); } /* AdressenListe Datenstruktur zur Verwaltung einer Adressenliste */ struct AdressenListe { ListenElement* listenAnfang; /* Zeiger auf den Anfang der Liste */ }; /* s.o. (typedef struct ListenElement ...) */ typedef struct AdressenListe AdressenListe; /* adressenListeErzeugen Erzeugt eine leere Adressenliste Rueckgabe: Zeiger auf die neu erzeugte Adressenliste */ AdressenListe* adressenListeErzeugen () { AdressenListe* neueListe = (AdressenListe*) malloc (1 * sizeof (AdressenListe)); if (neueListe == NULL) { printf ("Nicht genuegend Speicher vorhanden.\n"); exit (1); } neueListe->listenAnfang = NULL; return neueListe; } /* adressenListeZerstoeren Gibt den Speicher der gesamten Adressenliste frei Parameter: Die zuzerstoerende Adressenliste JAVA: Dank garbage collection ist eine explizite Speicherfreigabe nicht noetig */ void adressenListeZerstoeren (AdressenListe* liste) { ListenElement* pos = liste->listenAnfang; ListenElement* nachfolger; /* Zwischenspeicher fuer den Nachfolger eines Elements */ while (pos != NULL) { nachfolger = pos->nachfolger; /* Nachfolger merken */ listenElementZerstoeren (pos); /* Listenelement explizit freigeben */ pos = nachfolger; } free (liste); } /* adressenListeEinfuegen Fuegt ein Listenelement in die Adressenliste ein, dabei wird aufsteigend nach dem Namen sortiert. Parameter: liste - Adressenliste in die eingefuegt werden soll e - einzufuegendes Element JAVA: In Java waere der Parameter liste unnoetig, da wir dort die this-Referenz haben. */ void adressenListeEinfuegen (AdressenListe* liste, ListenElement* e) { /* FUNKTION IMPLEMENTIEREN */ } /* adressenListeLoeschen Loescht alle Listenelemente mit dem als Parameter uebergebenem Namen Parameter: liste - Adressenliste aus der geloescht werden soll name - Listenelemente mit dem Namen "name" werden geloescht */ void adressenListeLoeschen (AdressenListe* liste, char* name) { /* FUNKTION IMPLEMENTIEREN */ } /* adressenListeSuchen Gibt alle Listenelemente aus, in deren Adressinformation der als Parameter uebergebene Name steht. Wird kein entsprechender Datensatz gefunden, so wird "LEER" ausgegeben. Parameter: liste - die zu durchsuchende Liste name - Suchschluessel */ void adressenListeSuchen (AdressenListe* liste, char* name) { /* FUNKTION IMPLEMENTIEREN */ } /* adressenListeAusgeben Gibt die Adressinformationen aller Listenelemente aus. Ist die Adressenliste leer, so erfolgt die Ausgabe "LEER" Parameter: liste - auszugebende Adressenliste */ void adressenListeAusgeben (AdressenListe* liste) { ListenElement* i; /* Listenanfang pruefen */ if (liste->listenAnfang == NULL) printf ("LEER\n"); /* gesamte Liste durchlaufen */ for (i = liste->listenAnfang; i != NULL; i = i->nachfolger) listenElementAusgeben (i); } int main (int argc, char* argv[]) { char kommando[STRING_MAX_SIZE]; /* Speicher fuer die Kommandos */ char arg1[STRING_MAX_SIZE]; /* Speicher fuer die bis zu 3 Argumente */ char arg2[STRING_MAX_SIZE]; char arg3[STRING_MAX_SIZE]; ListenElement* e; /* Listenelement fuer das Einfuegen anlegen */ AdressenListe* liste = adressenListeErzeugen (); FILE* inputFile = fopen (argv[1], "r"); /* Datei zum Lesen oeffnen */ if (!inputFile) { printf ("File %s not found.\n", argv[1]); exit (1); } /* Kommandos abarbeiten */ while (readString(inputFile, kommando) == TRUE) { if (strcmp (kommando, "add") == 0) { readString(inputFile, arg1); /* Argumente name, strasse, ort */ readString(inputFile, arg2); readString(inputFile, arg3); e = listenElementErzeugen (arg1, arg2, arg3); adressenListeEinfuegen (liste, e); } else if (strcmp (kommando, "delete") == 0) { readString(inputFile, arg1); /* Argument name */ adressenListeLoeschen (liste, arg1); } else if (strcmp (kommando, "search") == 0) { readString(inputFile, arg1); /* Argument name */ adressenListeSuchen (liste, arg1); } else if (strcmp (kommando, "print") == 0) { adressenListeAusgeben (liste); } } /* Speicher der gesamten Adressenliste freigeben. Wir haben ja keine garbage collection :-( */ adressenListeZerstoeren (liste); return 0; }