Sie sind auf Seite 1von 5

Labor Informatik 2 Beck, Dausmann, Warendorf

Blatt 1 Programme aus mehreren Dateien, Speicherklassen

Aufgabe 1.1 Programme aus mehreren Dateien.

Schreiben Sie ein Programm, welches 2 float-Zahlen a und b mit der Funktion
einlesen()einliest, und dann mit der Funktion average() den Durchschnitt, mit der
Funktion quotient() den Quotienten, mit der Funktion produkt() das Produkt, mit der
Funktion summe() die Summe und mit der Funktion differ()die Differenz berechnet. Alle
Funktionen sollen in main() aufgerufen werden. Jede Funktion steht in einer eigenen Datei.
Der Dateiname bildet sich aus dem jeweiligen Funktionsnamen und der Endung .c .

Die Zahl a soll eine globale Variable sein und in der Datei main.c definiert sein. Die Zahl b
soll über die Parameterliste übergeben werden. Die Ergebnisse der arithmetischen
Operationen sollen bei average(), quotient() und produkt() über die Parameterliste,
bei summe() und differ() als Rückgabewert übergeben werden.

Hier die Datei main.c:


#include <stdio.h>
extern void einlesen (float *, float *);
extern void average (float, float *);
extern void quotient (float, float *);
extern void produkt (float, float *);
extern float summe (float);
extern float differ (float);

float a;

int main (void)


{
float b;
float mittel, quot, prod, summ, diff;

einlesen (&a, &b);


average (b, &mittel);
quotient (b, &quot);
produkt (b, &prod);

summ = summe (b);


diff = differ (b);
printf ("\n a = %6.2f, b = %6.2f", a,b);
printf ("\n der Mittelwert von a und b ist %6.2f", mittel);
printf ("\n das Produkt a*b ist %6.2f", prod);
printf ("\n der Quotient a/b ist %6.2f", quot);
printf ("\n die Summe a + b ist %6.2f", summ);
printf ("\n die Differenz ist %6.2f", diff);
return 0;
}

Blatt 1 Seite 1 Version 1.1 vom 10.3.2006


Labor Informatik 2 Beck, Dausmann, Warendorf

Aufgabe 1.2 Statische lokale Variablen

Schreiben Sie ein Programm aus den Funktionen main(), eingabe() und zaehl-
routine(). Die Funktion eingabe() soll einen ganzzahligen Wert N einlesen und an das
Hauptprogramm übergeben (über die Parameterliste, nicht über globale Variablen). Das
Hauptprogramm soll in einer Schleife die Funktion zaehlroutine() N-mal aufrufen.

Die Funktion zaehlroutine() soll mitzählen, wie oft sie aufgerufen wurde und soll bei
jedem Aufruf in die Datei ZAEHL.TXT mit Hilfe von fprintf() ausgeben:
function zaehlroutine() wurde jetzt zum x-ten Mal aufgerufen.
Dabei muss x der aktuellen Anzahl der Aufrufe entsprechen.

Hinweis: Wenn Sie als Dateiname bei der Funktion fopen() einen String wie etwa
"ZAEHL.TXT" angeben, wird die Datei im aktuellen Arbeitsverzeichnis abgelegt. Was das
gerade ist, hängt davon ab, wie Sie Ihr Programm starten, welche Entwicklungsumgebung Sie
benutzen, etc. Suchen Sie die Datei mit dem Windows-Explorer, damit Sie wissen, wo solche
Dateien abgelegt werden.

Aufgabe 1.3 Modularisierung, Headerdateien


Schreiben Sie ein Programm, das von der Standardeingabe zeichenweise einliest und prüft, ob
alle darin vorkommenden Klammern - also (), [] und {} -paarig und richtig geschachtelt sind.
Da die Klammern beliebig tief geschachtelt sein können, benötigt man zur Lösung der
Aufgabe einen Stack. Dieser Stack ist als eigenes Modul mit Header- und C-Datei zu
realisieren.

Ein Stack (von Zeichen) benötigt mindestens folgende Funktionen void push(char) und
char pop() zum Ablegen bzw. Abholen eines Zeichens (hier einer Klammer). Darüber
hinaus sind nützliche Funktionen: int is_empty() und void reset() um zu prüfen, ob
der Stack leer ist bzw. um ihn ggf. komplett zu leeren. Einen Stack kann man mit Hilfe eines
Arrays realisieren, die Anzahl der Elemente ist dann fest als Konstante vorgegeben.
Stackoverflow (push bei vollem Stack) und Stackunderflow (pop bei leerem Stack) führen zu
einer Fehlermeldung und Programmabbruch. Der Stackpointer ist ein Index für dieses Array,
der auf das nächste freie Element zeigt. Bei leerem Stack hat der Stackpointer den Wert 0.

Die Prüfung der Klammerung funktioniert mit diesem Stack folgendermaßen: Jede öffnende
Klammer wird auf den Stack gelegt. Trifft man auf eine schließende Klammer in der Eingabe,
darf der Stack nicht leer sein und als oberstes Zeichen muss auf dem Stack die entsprechende
öffnende Klammer sein. Am Ende der Eingabe (EOF) muss auch der Stack leer sein.

Hinweis zur zeichenweise Eingabe:

Der einfachste Eingabemechanismus besteht darin, ein einzelnes Zeichen von der
Standard-Eingabe, normalerweise von der Tastatur, mit Hilfe von getchar() zu lesen.

Blatt 1 Seite 2 Version 1.1 vom 10.3.2006


Labor Informatik 2 Beck, Dausmann, Warendorf

Die Syntax von getchar() ist:


int getchar (void)

getchar() dient zum Einlesen einzelner Zeichen von der Standardeingabe (in der
Regel der Tastatur). Die Standardeingabe ist zeilengepuffert, d.h. getchar() wartet,
bis eine Zeile mit der Return-Taste abgeschlossen wird. Der Rückgabewert ist nicht
vom Typ char, sondern vom Typ int.

Beispiel:
int c;

/* hiermit wird c das eingelesene Zeichen zugewiesen */


c = getchar ();

Tritt ein Fehler auf oder wird das Dateiende erreicht, so liefert getchar() den Wert
EOF. EOF ist eine ganze Zahl, die in <stdio.h> vereinbart ist und steht für "End Of
File". Die Variable c ist vom Typ int. Damit kann c auch negative Werte aufnehmen.
Die Konstante EOF hat in der Regel den Wert -1. Wird von der DOS-
Eingabeaufforderung aus per Tastatur eingegeben (das ist für Sie bis jetzt der
Normalfall, da Sie Console-Projekte anlegen) so kann EOF durch das Eingeben von
Strg-Z mit anschließender Eingabe eines Wagenrücklaufes (Return-Zeichen) in einer
einzelnen Zeile eingegeben werden. Generell ist es so, dass getchar() erst dann ein
Zeichen an c zuweist, wenn Return-Zeichen eingegeben wird. Erst dann werden alle
bisher in der Zeile eingegebenen Zeichen, einschließlich des Return-Zeichens ('\n'),
in einem Tastaturpuffer abgelegt, aus dem dann mit jedem Aufruf von c =
getchar() ein weiteres Zeichen (von links nach rechts) entnommen wird, bis der
Tastaturpuffer geleert ist. Dann wird wieder gewartet, bis eine Zeile, beendet durch ein
Return, eingegeben wird.

Der eigentliche Hintergrund von EOF ist der: Es wird dann zugewiesen, wenn aus einer
Datei gelesen wird und man beim Lesen an deren Ende angekommen ist. Ende der
Datei eben. Das können Sie testen, in dem Sie Ihr Programm nicht aus der
Programmierumgebung heraus aufrufen sondern aus einer DOS-Eingabeaufforderung,
die man mit "Start.Programme.DOS-Eingabeaufforderung" startet. Dort gehen
Sie zunächst auf das Z-Laufwerk und dann mit dem mit dem cd Befehl (change
directory) in das Verzeichnis, in dem Ihr Programm steht:

z:

cd inf2\cc\bl1afg13\Debug

Dort können Sie – wenn Sie Aufgabe 1.3d fertig haben – zum Beispiel prüfen, ob die
Klammerung Ihrer C-Datei korrekt ist:

bl1afg13.exe < ..\bl1afg13.c

Blatt 1 Seite 3 Version 1.1 vom 10.3.2006


Labor Informatik 2 Beck, Dausmann, Warendorf

Dabei steht "<" für die Eingabeumleitung. Das heißt, Ihr Programm erwartet die
Eingabe nicht mehr von der Tastatur, sondern von der Datei ..\bl1afg13.c. Diese
Datei hat – wie jede andere Datei auch – das EOF an ihrem Ende.

a) Machen Sie sich zuerst anhand eines Bildes die Arbeitsweise des Stacks klar.

b) Zu erstellen sind die Dateien main.c, stack.h und stack.c. Welche Reihenfolge
wählen Sie?

c) Programmieren Sie die Dateien main.c, stack.h und stack.c unter Beachtung der
Kriterien der Datenkapselung und des Information Hidings. Nutzen Sie in stack.c die
Möglichkeiten des Präprozessors zur Fehlermeldung und geben Sie außerdem die
Fehlermeldung auf die Standardfehlerausgabe aus.

e) Testen Sie Ihr Programm wie gewohnt über die Standardeingabe.

f) Nutzen Sie den Hinweis und testen Sie nun Ihr Programm an verschiedenen Dateien,
beispielsweise auch an C-Dateien. Ggf. ist beim Testen noch eine weitere Funktion im
Stackmodul hilfreich: print() zur Ausgabe des kompletten Stackinhalts.

Aufgabe 1.4 Modularisierung

a) Schreiben Sie eine Funktion zum Einlesen eines Integer-Arrays. Gegeben ist der folgende
unvollständige Prototyp:

/* Ein Integer-Array einlesen: */


void scanArray(
max, /* Maximale Anzahl Elemente in array (stets >0)*/
array, /* Zu fuellende Reihung */
n /* Anzahl der Elemente in Reihung */
);

Die Funktion scanArray() soll wie folgt einlesen: Es werden int-Werte von der Tastatur
eingelesen, bis entweder das Array komplett gefüllt ist (also max Elemente eingelesen sind)
oder bis über die Tastatur etwas eingegeben wird, was scanf() nicht mit dem
Formatelement %i einlesen kann (erkennbar am Rückgabewert von scanf()).
Beispielsweise kann die Eingabe des Buchstabens q zu einem solchen Verhalten führen. Die
Funktion scanArray() gibt über den Parameter n die Anzahl der tasächlich gefüllten
Elemente des Arrays zurück (Anzahl korrekt gelesener Zahlen oder max).

b) Schreiben Sie eine Funktion zur Ausgabe eines Integer-Arrays (je 8 Zahlen auf eine Zeile,
pro Zahl 6 Stellen). Gegeben ist der folgende unvollständige Prototyp:

Blatt 1 Seite 4 Version 1.1 vom 10.3.2006


Labor Informatik 2 Beck, Dausmann, Warendorf

/* Ein Integer-Array ausgeben: */


void printArray(
array, /* Zu druckende Reihung */
n /* Anzahl der Elemente in Reihung */
);

c) Schreiben Sie eine weitere Funktion fillArray() mit gleichem Parameterprofil wie
scanArray, die das Array mit Zufallszahlen füllt. Der Parameter der die aktuelle Zahl der
gefüllten Elemente angibt, soll hier ebenfalls durch den Zufallsgenerator bestimmt werden.
Diese Zahl muss zwischen 0 und dem Parameter max liegen!

Hinweis: Ein Zufallsgenerator ist implementiert durch die Funktion rand() aus der
Bibliothek stdlib.h. Initialisiert wird dieser Zufallsgenerator durch die Funktion
srand(). Damit bei jeder Neuinitialisierung der Zufallsgenerator eine andere Zahlenfolge
liefert, wird er am besten jedesmal anders initialisiert. Dies geschieht am einfachsten mit der
aktuellen Zeit. Die aktuelle Zeit liefert die Funktion time() aus der Bibliothek time.h.
Lesen Sie die Hilfen zu diesen Funktionen durch, dort finden Sie auch Beispiele für die
Anwendung. Beachten Sie auch das Intervall, in dem die Zufallszahlen liegen: ggf. müssen
Sie die Ergebnisse von rand() noch Ihrer Anwendung anpassen!

d) Schreiben Sie ein Hauptprogramm, das ein Array mit Elementen füllt (mit scanArray()),
es anschließend ausgibt, den Mittelwert berechnet und auch diesen ausgibt. Überlegen Sie
eine nützliche Modularisierung der Funktionen. Erstellen Sie Header- und C-Dateien.

e) Ersetzen Sie in Ihrem Hauptprogramm den Aufruf von scanArray() durch den Aufruf
von fillArray() und testen Sie so auch diese Funktion.

Aufgabe 1.5 Schnittstellenvergleich


Vergleichen Sie die Lösungen der Aufgaben 1.3 und 1.4. Die Tatsache, dass in einem Fall ein
char-Array im anderen Falle ein int-Array bearbeitet wird, ist hier unerheblich. Wo
befinden sich die Daten? Erklären Sie die Unterschiede in den Parameterprofilen.

Blatt 1 Seite 5 Version 1.1 vom 10.3.2006