96
C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit ¨ Ubungsaufgaben 1

C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

C Programmierung

W. Kippels

11. Februar 2011

Eine Anleitung mit Ubungsaufgaben

1

Page 2: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Inhaltsverzeichnis

1 Grundlegendes 5

2 Der Compiler 6

3 Das erste Programm 8

4 Arbeiten mit Variablen 104.1 Variablentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104.2 Deklaration von Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . 124.3 Rechnen mit Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

5 Ein-/Ausgabe-Routinen 155.1 Die Ausgabefunktion printf . . . . . . . . . . . . . . . . . . . . . . . . . 155.2 Aufgabe 1: Programm SUMME2 . . . . . . . . . . . . . . . . . . . . . . 165.3 Die Eingabefunktion scanf . . . . . . . . . . . . . . . . . . . . . . . . . . 165.4 Ein-/Ausgabe von Einzelzeichen . . . . . . . . . . . . . . . . . . . . . . . 17

6 Einfache Verzweigung 196.1 Die if-Abfrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196.2 Vergleichsoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

7 Ubungsaufgaben Teil 1 207.1 Aufgabe 1.1: Programm TASTE1 . . . . . . . . . . . . . . . . . . . . . . 207.2 Aufgabe 1.2: Programm TASTE2 . . . . . . . . . . . . . . . . . . . . . . 207.3 Aufgabe 1.3: Programm TASTE3 . . . . . . . . . . . . . . . . . . . . . . 207.4 Aufgabe 1.4: Programm QUADRAT . . . . . . . . . . . . . . . . . . . . 217.5 Aufgabe 1.5: Programm PRIMZAHL . . . . . . . . . . . . . . . . . . . . 21

8 Schleifen 228.1 Kopfgesteuerte while-Schleife . . . . . . . . . . . . . . . . . . . . . . . . . 228.2 Fußgesteuerte while-Schleife . . . . . . . . . . . . . . . . . . . . . . . . . 238.3 Die for-Schleife . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

9 Verzweigungen mit switch 26

10 Ubungsaufgaben Teil 2 2810.1 Aufgabe 2.1: Programm RECHNER1 . . . . . . . . . . . . . . . . . . . . 2810.2 Aufgabe 2.2: Programm RECHNER2 . . . . . . . . . . . . . . . . . . . . 2810.3 Aufgabe 2.3: Programm RECHNER3 . . . . . . . . . . . . . . . . . . . . 2910.4 Aufgabe 2.4: Programm RECHNER4 . . . . . . . . . . . . . . . . . . . . 2910.5 Aufgabe 2.5: Programm RECHNER5 . . . . . . . . . . . . . . . . . . . . 2910.6 Aufgabe 2.6: Programm FAKTOR . . . . . . . . . . . . . . . . . . . . . 30

11 Unterprogramme / Funktionen 31

2

Page 3: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

12 Ubungsaufgaben Teil 3 3312.1 Aufgabe 3.1: Programm GROSS1 . . . . . . . . . . . . . . . . . . . . . . 3312.2 Aufgabe 3.2: Programm GROSS2 . . . . . . . . . . . . . . . . . . . . . . 3412.3 Aufgabe 3.3: Programm KOMPLEX . . . . . . . . . . . . . . . . . . . . 35

13 Vektoren / Felder 3613.1 Vektoren (Eindimensionale Felder) . . . . . . . . . . . . . . . . . . . . . 3613.2 Arrays (Mehrdimensionale Felder) . . . . . . . . . . . . . . . . . . . . . . 40

13.2.1 Aufbau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4013.2.2 Verwendung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4013.2.3 Mehrdimensionale Felder in Funktionen . . . . . . . . . . . . . . . 41

14 Ubungsaufgaben Teil 4 4214.1 Aufgabe 4.1: Programm GROSS3 . . . . . . . . . . . . . . . . . . . . . . 4214.2 Aufgabe 4.2: Programm SKALAR . . . . . . . . . . . . . . . . . . . . . . 4214.3 Aufgabe 4.3: Programm KREUZ . . . . . . . . . . . . . . . . . . . . . . 4414.4 Aufgabe 4.4: Programm DET3 . . . . . . . . . . . . . . . . . . . . . . . . 4614.5 Aufgabe 4.5: Programm LIN . . . . . . . . . . . . . . . . . . . . . . . . . 48

14.5.1 Das Prinzip des Gauß-Jordan-Verfahrens . . . . . . . . . . . . . . 4814.5.2 Das Gauß-Jordan-Verfahren in der Anwendung . . . . . . . . . . 5214.5.3 Umsetzung in C: . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

15 Rekursive Funktionen 55

16 Zeiger/Pointer 5716.1 Einfache Zeiger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

17 Ubungsaufgaben Teil 5 6217.1 Aufgabe 5.1: Programm FAKULTAET . . . . . . . . . . . . . . . . . . . 6217.2 Aufgabe 5.2: Programm DETERMINANTE . . . . . . . . . . . . . . . . 63

18 Tabellen 6518.1 Steuerzeichen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6518.2 Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6518.3 Formatbeschreiber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6618.4 Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6718.5 Vergleichsoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

19 Losungsbeispiele Teil 1 6819.1 Aufgabe 1: Programm SUMME2 . . . . . . . . . . . . . . . . . . . . . . 6819.2 Aufgabe 1.1: Programm TASTE1 . . . . . . . . . . . . . . . . . . . . . . 6819.3 Aufgabe 1.2: Programm TASTE2 . . . . . . . . . . . . . . . . . . . . . . 6919.4 Aufgabe 1.3: Programm TASTE3 . . . . . . . . . . . . . . . . . . . . . . 6919.5 Aufgabe 1.4: Programm QUADRAT . . . . . . . . . . . . . . . . . . . . 7019.6 Aufgabe 1.5: Programm PRIMZAHL . . . . . . . . . . . . . . . . . . . . 70

3

Page 4: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20 Losungsbeispiele Teil 2 7120.1 Aufgabe 2.1: Programm RECHNER1 . . . . . . . . . . . . . . . . . . . . 7120.2 Aufgabe 2.2: Programm RECHNER2 . . . . . . . . . . . . . . . . . . . . 7220.3 Aufgabe 2.3: Programm RECHNER3 . . . . . . . . . . . . . . . . . . . . 7320.4 Aufgabe 2.4: Programm RECHNER4 . . . . . . . . . . . . . . . . . . . . 7420.5 Aufgabe 2.5: Programm RECHNER5 . . . . . . . . . . . . . . . . . . . . 7520.6 Aufgabe 2.6: Programm FAKTOR . . . . . . . . . . . . . . . . . . . . . 76

21 Losungsbeispiele Teil 3 7721.1 Aufgabe 3.1: Programm GROSS1 . . . . . . . . . . . . . . . . . . . . . . 7721.2 Aufgabe 3.2: Programm GROSS2 . . . . . . . . . . . . . . . . . . . . . . 7821.3 Aufgabe 3.3: Programm KOMPLEX . . . . . . . . . . . . . . . . . . . . 80

22 Losungsbeispiele Teil 4 8322.1 Aufgabe 4.1: Programm GROSS3 . . . . . . . . . . . . . . . . . . . . . . 8322.2 Aufgabe 4.2: Programm SKALAR . . . . . . . . . . . . . . . . . . . . . . 8422.3 Aufgabe 4.3: Programm KREUZ . . . . . . . . . . . . . . . . . . . . . . 8622.4 Aufgabe 4.4: Programm DET3 . . . . . . . . . . . . . . . . . . . . . . . . 8722.5 Aufgabe 4.5: Programm LIN . . . . . . . . . . . . . . . . . . . . . . . . . 90

23 Losungsbeispiele Teil 5 9223.1 Aufgabe 5.1: Programm FAKULTAET . . . . . . . . . . . . . . . . . . . 9223.2 Aufgabe 5.2: Programm DETERMINANTE . . . . . . . . . . . . . . . . 93

4

Page 5: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

1 Grundlegendes

Wie man schon am Namen der Programmiersprache erkennt, ist die Philosophie die-ser Sprache ein minimalistischer Ansatz. Der Programmierer soll mit moglichst wenigenTastendrucken das Programm schreiben konnen. Daher sind etliche Ausdrucke etwaskryptisch und entsprechend gewohnungsbedurftig geraten. Das werden wir spater imeinzelnen erkennen.

Ein Unterschied zu vielen anderen Programmiersprachen liegt darin, dass bei C zwischenGroß- und Kleinschreibung unterschieden wird. Eine Variable mit dem Namen wert isteine andere, als die Variable Wert oder WERT. Das gilt naturlich auch fur alle Befehls-und Funktionsnamen. Als Zeichen sind (wie in den meisten anderen Sprachen auch) dieBuchstaben des Alphabetes ohne Umlaute, die Ziffern von 0 bis 9 sowie der Unterstrichzulassig.

Kommentare werden durch die Zeichen /* und */ eingeschlossen. Dabei konnen beliebigviele Zeilen dazwischen liegen. Beispiele:

/* Dies ist ein Kommentar */

/* Dies ist ein

mehrzeiliger Kommentar. */

Nicht in ANSI-C zulassig, aber unter C++ definiert ist eine Moglichkeit, nur die Zeichenin einer einzigen Zeile auszukommentieren, ahnlich dem Semikolon bei ASSEMBLER.Hierfur wird die Zeichenkombination // verwendet. Ein Beispiel:

// Dies ist ein Kommentar,

// der auf diese Weise

// dann auch in mehreren

// Zeilen gesetzt werden kann.

Vor diesen Kommentaren konnen dann jeweils gultige Befehlszeichen stehen.

Im Gegensatz zu PASCAL ist C nicht als Lehrsprache gedacht, sondern tatsachlich zurErstellung hochkomplexer Programme. Daher ist diese Sprache von vornherein dafureingerichtet, dass mehrere Entwickler gemeinsam daran arbeiten konnen. Aus diesemGrund darf ein C-Programm nicht nur aus einer sondern auch aus mehreren Dateienbestehen. Außerdem

”lebt“ die Sprache von umfangreichen Bibliotheken, die bei Bedarf

mit eingebunden werden konnen.

Um dies alles bewerkstelligen zu konnen, lauft der Vorgang des Compilierens in mehre-ren Stufen ab. Zunachst durchsucht ein sogenannter Praprozessor den Quelltext nachHinweisen, ob und welche Funktionen aus bestimmten Bibliotheken eingebunden werdensollen. Er hat auch noch andere Aufgaben, die hier aber noch nicht zur Debatte stehen.Danach nimmt sich der eigentliche Compiler den Quelltext vor und erzeugt daraus eine

5

Page 6: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Objektdatei. Anschließend beginnt der Linker mit seiner Arbeit und bindet alle Objekt-dateien zum endgultigen ausfuhrbaren Programm zusammen.

2 Der Compiler

C-Compiler gibt es viele. Ich empfehle den GNU-C-Compiler gcc. Linux-Nutzer habenihn sowieso auf ihrem Rechner, denn er gehort bei allen gangigen Distributionen zurGrundausstattung. Es gibt aber auch eine Version fur den Mac und auch eine fur Win-dows. Da dieser Compiler als Teil des GNU-Projektes unter der General Public Licensesteht, ist er kostenfrei im Internet erhaltlich.

Seine Bedienung ist recht einfach. Man schreibt einfach an der Kommandozeile:

gcc -o Zieldatei Quelldatei

Hierin bedeutet

Zieldatei: Name der zu erzeugenden ausfuhrbaren Datei.

Quelldatei: Name der Datei mit dem Quellcode.

Ein Beispiel dazu: Wir wollen unser erstes Programm mit dem Namen hallo erzeugen.Dazu haben wir mit einem beliebigen systemkonformen Editor die Textdatei hallo.c1

geschrieben, die den Quellcode darstellt. Damit lautet der Befehl zum compilieren:

gcc -o hallo hallo.c

Nach der Befehlsausfuhrung haben wir eine ausfuhrbare Datei mit dem Namen hallo

im aktuellen Verzeichnis auf unserem Rechner.2

Laßt man den Schalter -o und den nachfolgenden Namen der Zieldatei weg, dann wirdstandardmaßig eine ausfuhrbare Datei mit dem Namen a.out3 erzeugt. Deshalb ist esschon sinnvoll, den Namen der Zieldatei mit anzugeben.

Der Compiler hat noch weitere Optionen, die man sich mit gcc --help anzeigen lassenoder ausfuhrlicher in den Man-Pages nachlesen kann. Fur unsere ersten Versuche istsicher davon nur eine interessant, namlich die Option -Wall. Das steht fur Warnings all.Hierdurch wird die Ausgabe aller Warnungen eingeschaltet. Wenn der Compiler etwasfeststellt, dass ihm suspekt ist, dann warnt er entsprechend. Hat man beispielsweise eine

1Die Konvention besagt, dass der Quelltext eines C-Programms immer die Endung .c haben sollte.2Anmerkung fur Windows-Nutzer: Da es unter Windows kein Modus-Byte fur Dateien gibt, wird

eine ausfuhrbare Datei durch spezielle Endungen im Dateinamen – hier mit der Endung .EXE –gekennzeichnet. Diese Endung hangt der GCC fur Windows selbsttatig mit an, sie braucht also nichtmit angegeben zu werden.

3Unter Windows heißt diese Datei – so weit ich weiß – a.exe.

6

Page 7: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Variable deklariert, ohne sie zu benutzen, hindert das den Compiler nicht daran, denausfuhrbaren Code zu erzeugen, aber er gibt eine entsprechende Warnung aus. Es istsehr sinnvoll, diese Option immer zu nutzen! Damit sieht der Befehl zum Compilierenso aus:

gcc -Wall -o hallo hallo.c

Eine Alternative zur Nutzung des gcc an der Kommandozeile ist die”Entwicklungsum-

gebung“ mit dem Namen dev-cpp. Letztlich arbeitet diese Entwicklungsumgebung auchmit dem gcc, jedoch ist eine grafische Benutzeroberflache mit einem eingebauten Editordaruber gesetzt worden. Fur Mausschieber ist es sicher ein Vorteil, wenn man nur aufeine Schaltflache klicken muss, um ein Programm zu compilieren. Allerdings erkauft mansich das mit ein paar Nachteilen:

• dev-cpp ist eine Entwicklungsumgebung, die fur große Projekte mit einer Vielzahlvon Quelldateien konzipiert ist. Daher muss fur jedes neue Programm zunachstein

”Projekt angelegt werden“. Fur große Projekte ist das sicher sehr sinnvoll,

fur unsere Mini-Ubungsprogramme ist das aber ein wenig wie mit Kanonen aufSpatzen zu schießen.

• dev-cpp lauft im grafischen Modus, unsere Ubungsprogramme jedoch an der Kom-mandozeile. Will man ein Programm aus der Entwicklungsumgebung heraus testen,dann offnet dev-cpp zunachst ein Textfenster, lasst das Programm darin ablau-fen und schließt anschließend das Textfenster wieder. Hat das Programm nochirgendwelche Ausgaben in das Textfenster geschrieben, dann sind diese beim Pro-grammende zusammen mit dem Textfenster verschwunden. Damit diese dennochgelesen werden konnen, muss man eine

”Krucke“ im Programm einbauen, die dafur

sorgt, dass noch auf einen weiteren Tastendruck gewartet wird, bis sich das Pro-gramm beendet.

• Unter Windows gibt es noch ein weiteres Problem. Da man es im Hause Micro-soft fur sinnvoll halt, im Textmodus eine andere Codierung fur die Umlaute zuverwenden, als im graphischen Modus, kann man mit dem internen Editor vondev-cpp keine Umlaute fur Textausgaben im Textmodus schreiben. dev-cpp isthalt eine Entwicklungsumgebung fur große Projekte, die im graphischen Moduslaufen. Alternativ kann man naturlich auch die Umlaute durch die entsprechendeCodierung ersetzen, beispielsweise a durch 0x84. Das erfordert dann aber gehorigAufwand. Daher fuhrt das dann eventuell dazu, dass man sich dazu hinreißen lasst,die Umlaute in Textausgaben gleich durch ae, oe und ue zu ersetzen, wie das inder Steinzeit der Computertechnik ublich war. In der heutigen Zeit ist es ein ganzschlechter Stil, die deutsche Sprache ohne Not so zu vergewaltigen und dafur dieSchuld auch noch der Entwicklungsumgebung zu geben, anstatt sich die eigeneUnfahigkeit einzugestehen!

Aus diesen Grunden empfehle ich, den gcc an der Kommandozeile zu nutzen. Letztlichmuss das aber jeder fur sich selbst entscheiden.

7

Page 8: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

3 Das erste Programm

Wir schauen uns zum Einstieg mal das ubliche Hallo-Welt-Programm an.

/* Beispielprogramm 1 */

#include <stdio.h> /* Anweisung an Praprozessor */

int main(void) /* Definition Hauptprogramm */

{ /* Anfang des Hauptprogramms */

printf("Hallo Welt!\n"); // Textausgabe (Kommentar nicht ANSI-C!)

return 0; /* Ruckgabewert ans Betriebssystem */

} /* Ende des Hauptprogramms */

In der ersten Zeile steht nur der Name des Programms als Kommentar. Diese Anweisungwird vom Compiler nicht beachtet. Danach folgt eine Anweisung an den Praprozessor.Alle Praprozessoranweisungen beginnen mit einem #. Der Befehl #include <stdio.h>

weist ihn an, die Standard-Eingabe-Ausgabe-Bibliothek stdio.h mit einzubinden. Dar-in ist unter anderem die Funktion printf enthalten, mit der wir die Textausgabedurchfuhren.

In der dritten Zeile ist das Hauptprogramm definiert. Vom Grundprinzip unterscheidetes sich nicht von Unterprogrammen (die unter C ubrigens alle Funktionen heißen). Ledig-lich durch seinen Namen main ist es als das Hauptprogramm gekennzeichnet. In jedemC-Programm muss es genau eine Funktion mit dem Namen main geben. Vor dem Namenmain steht der Typ der Funktion, der hier int heißt. Jede Funktion hat einen bestimm-ten Typ, der durch den Variablentyp gekennzeichnet ist, den die Funktion zuruckliefert.Beim Hauptprogramm ist das ein Integerwert, den es dem Betriebssystem zuruckliefert.Dieser ist ublicherweise 0, wenn das Programm ordnungsgemaß beendet wird. Der Befehlreturn 0 in der 5. Zeile erzeugt in unserem Programm diesen Ruckgabewert.

Hinter dem Funktionsnamen main steht noch (void). Dazu muss man wissen, dass jederFunktion vom Grundprinzip Ubergabeparameter mitgegeben werden. Ubergabeparame-ter beim Hauptprogramm sind die Angaben, mit denen man das Programm an derKommandozeile aufruft. Diese kommen in die runden Klammern. Will man einer Funk-tion keine Werte ubergeben, dann schreibt man void in die Klammern, oder man lasstdie Klammern leer, etwa so: int main( ). Funktionsanfang und Funktionsende werdendurch geschweifte Klammern { } gekennzeichnet. Um eine ubersichtliche strukturierteForm im Quelltext zu erhalten, schreibt man die Klammern gern auf gleicher Hohe anden Spaltenanfang, denn Zeilenumbruche und Leerzeichen im Quelltext konnen beliebiggesetzt werden.

Innerhalb der Klammern { } stehen die Befehle, die die jeweilige Funktion (hier alsodas Hauptprogramm) bilden. Jeder Befehl ist mit einem Semikolon abgeschlossen. Inunserem Programm sind es nur zwei Befehle. Dabei ist der erste

”Befehl“ eigentlich kein

Befehl, sondern ein Unterprogramm, eine Funktion. Wie wir schon gehort haben, stehtes in einer Standardbibliothek. Dieser Funktion wird genau ein Parameter ubergeben,

8

Page 9: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

namlich der String "Hallo Welt!\n". Die Anfuhrungszeichen kennzeichnen das ganzeals String. Der Text Hallo Welt! ist wohl klar, das angehangte \n vielleicht weniger.Es bedeutet das Zeichen

”Newline“, also einen Zeilenumbruch. Der Cursor springt an

den Anfang der nachsten Zeile. Weitere Steuerzeichen sind in einer Tabelle im Anhangaufgelistet.

Fassen wir noch einmal kurz zusammen. Das minimale”Grundgerust“ eines C-Pro-

gramms, aber auch jeder Funktion sieht wir folgt aus. (Bei Funktionen steht anstellevon main der Funktionsname.)

int main( )

{

...}

Anstelle der Punkte stehen naturlich die eigentlichen Befehle des Programms (die jeweilsmit einem Semikolon abgeschlossen sind).

An welchen Stellen Zeilenumbruche im Quelltext gemacht werden, ist gleichgultig. DasProgramm konnte also auch in einer einzigen Zeile stehen:

int main( ){ ... }

In aller Regel wird man das aber im Interesse der Ubersichtlichkeit nicht tun. Dei tri-vialen Funktionen kann das allerdings eventuell sinnvoll sein.

Im Hauptprogramm sollte immer als letzter Befehl:

return 0;

stehen, auch wenn das nicht zwingend erforderlich ist.4

4Die 0”sagt“ dem Betriebssystem, dass das Programm orgdungsgemaß abgelaufen ist. Andere Werte

konnen verwendet werden, um bestimmte Fehlertypen zu signalisieren. Unter DOS/Windows sinddiese Werte als ERRORLEVEL bekannt. Aber auch andere Betriebssysteme verwenden diese Artder Kommunikation.

9

Page 10: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

4 Arbeiten mit Variablen

4.1 Variablentypen

In jedem vernunftigen Programm werden Variablen verwendet. Gekennzeichnet werdensie mit Namen, die – wie bereits beschrieben – aus Buchstaben, Ziffern und dem Unter-strich bestehen konnen. Jede Variable hat . . .

1. einen Namen,

2. eine bestimmte Speicherlange,

3. ein bestimmtes internes Format.

Die Speicherlange und das interne Format bilden das, was man Datentyp nennt. DieDatentypen lassen sich in zwei Gruppen einteilen:

• Ganzzahlige Datentypen und

• Gleitkommazahlen.

Ganzzahlige Datentypen

Schreibweisen der ganzzahligen Datentypen Im Normalfall wird man Zahlen imDezimalsystem schreiben. Das ist unter C der Standard. Die Zahl

1235

wird also als Dezimalzahl interpretiert. Will man dagegen Zahlen im Hexadezimalsys-tem verwenden, setzt man 0x vor die Zahl, also etwa so:

0x13B4

Dadurch weiß der C-Compiler, dass hier eine Hexadezimalzahl gemeint ist.Ist der Code eines ASCII-Zeichens gemeint, dann schreibt man das Zeichen in Hoch-komma (siehe auch nachstes Kapitel). Es ist also:

’7’ = 0x37 = 55

10

Page 11: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Beginnen wir mit den verschiedenen Datentypen der Große nach.

Datentyp char Dieser Datentyp hat die Große 1 Byte. Er wird hauptsachlich zumSpeichern von Einzelzeichen wie ASCII-Zeichen benutzt, kann aber genauso auch zumSpeichern kleiner numerischer Werte dienen. PASCAL beispielsweise unterscheidet zwi-schen CHAR, BYTE und BOOLEAN, alle mit der Lange 1 Byte. Man kann also unter Cschreiben:

char c = ’A’;

oder auch:

char c = 65;

Beides bewirkt, dass die Variable c als 1-Byte-Variable definiert wird und mit dem Wert65dez=41hex=’A’=1000001bin initialisiert wird. Beim Rechnen wird dieser Variablentypals vorzeichenbehaftet interpretiert. (Fur Insider: Beim Multiplizieren und Dividierenwerden die Assemblerbefehle IMUL und IDIV verwendet und nicht MUL und DIV.) Willman das nicht, dann definiert man die Variable als unsigned char, etwa so:

unsigned char c = 65;

Datentyp int Dieser Datentyp ist langer als 1 Byte. Die tatsachliche Lange ist vomBetriebssystem abhangig (siehe Tabelle). Als Untertypen gibt es noch short int undlong int, wobei das Schlusselwort int in dieser Zusammensetzung entfallen kann. Esreicht also short oder long als Kennzeichnung fur die kurzen oder langen Typen zuverwenden. Die jeweiligen Langen sind in nachfolgender Tabelle dargestellt.

Betriebssystem short int long

16-Bit, z.B. DOS 2 2 432-Bit, z.B. Linux, Unix, Windows 2 4 464-Bit, z.B. Linux (je nach Kernel) 2 4 8

Dieser Datentyp ist vorzeichenbehaftet. Es gibt sie auch vorzeichenlos. Dann heißensie:

• unsigned short fur vorzeichenlosen short-int-Typ

• unsigned int fur vorzeichenlosen int-Typ

• unsigned long fur vorzeichenlosen long-int-Typ

11

Page 12: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Gleitkomma-Datentypen Auch hier beginnen wir der Große nach.

Datentyp float Das ist eine meist 4 Byte lange Gleitkommazahl. Die interne Darstel-lung sieht so aus:1 Vorzeichenbit + 8-Bit-Exponent + 23-Bit-Mantisse

Datentyp double Das ist eine doppelt so genaue, meist 8 Byte lange Gleitkommazahl.Interne Darstellung:1 Vorzeichenbit + 11-Bit-Exponent + 52-Bit-Mantisse

Datentyp long double Das ist eine 10 Byte lange Gleitkommazahl. Die interne Dar-stellung sieht so aus:1 Vorzeichenbit + 16-Bit-Exponent + 63-Bit-Mantisse

Eine Tabelle mit den Speicherlangen und Wertebereiche der C-Datentypen befindet sichder Tabellensammlung im Anhang.

4.2 Deklaration von Variablen

Variablen mussen innerhalb der jeweiligen Funktion (bzw. des Hauptprogramms) vorder ersten Benutzung deklariert werden. Werden sie innerhalb der jeweiligen Funkti-on (bzw. des Hauptprogramms) deklariert, dann sind es lokale Variable. Sie sind nurinnerhalb dieser Funktion gultig. Sie werden auf dem Stapelspeicher angelegt, derZugriff erfolgt uber das Zeigerregister EBP. Werden sie vor dem Hauptprogramm undaußerhalb jeder Funktion deklariert, dann sind es globale Variable. Sie werden imDatensegment angelegt und es kann von jeder Stelle im Programm darauf zugegriffenwerden.

Die Deklaration kann mit oder ohne Initialisierung mit einem Startwert geschehen.Eine Deklaration ohne Initialisierung geschieht dadurch, dass man den Variablentyphinschreibt und dahinter die Variable mit ihrem Namen. Es konnen auch mehrere Varia-blen auf einmal deklariert werden, indem man sie – mit Kommata voneinander getrennt– hinter den Typ schreibt. Hier ein Beispiel zur Deklaration ohne Initialisierung:

int main(void)

{

char a; /* Eine Variable a Typ char wird definiert */

int b, c; /* Zwei Integervariablen b und c werden definiert */

...}

12

Page 13: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Ein anderes Beispiel, diesmal mit Initialisierung:

int main(void)

{

char a=3; /* Variable a wird definiert und mit 3 initialisiert */

int b=12; /* Entsprechendes mit b */

int c=0;

...}

4.3 Rechnen mit Variablen

Als Rechenzeichen stehen die Zeichen + und − fur das Addieren bzw. Subtrahierensowie die Zeichen * und / fur die Multiplikation bzw. die Division zur Verfugung. Dabeiist zu beachten, dass bei der Division von ganzzahligen Datentypen nur das ganzzahligeErgebnis ohne

”Rest“ entsteht. Will man nur diesen Divisionrest erhalten (das wird

auch Modulo-Funktion genannt), dann verwendet man das Zeichen %. Die Zuweisungdes Rechenergebnisses erfolgt durch ein einfaches Gleichheitszeichen, also nicht durchdie Zeichenkombination := wie in einigen anderen Sprachen. Eine Tabelle mit allenOperatoren befindet sich im Anhang. Hierzu einige Beispiele:

a = b+c; /* a wird die Summe b+c zugewiesen */

a = a+1; /* a wird um 1 erhoht */

a = a/2; /* a wird halbiert, der Rest entfallt */

a = a%4; /* a wird auf den Divisionsrest von a/4 gesetzt */

Hier noch ein Hinweis. Anstelle von

a = a+1; /* a wird um 1 erhoht */

kann man besser schreiben:

a++; /* Erhohungsoperator */

Letztere Variante ist der ersten vorzuziehen, denn sie erzeugt einen effizienteren Code.Die erste Variante wird namlich so ubersetzt5:

mov EAX,a

add EAX,1

mov a,EAX

die zweite dagegen so:

inc a

5Es gibt allerdings moderne C-Compiler (wie auch den GNU-C-Compiler), die einen solchen Befehlerkennen und entsprechend umbauen konnen, damit er effizient ubersetzt wird.

13

Page 14: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Auch ohne ASSEBMLER-Kenntnisse kann man wohl erkennen, dass die zweite Varianteschneller ablauft. Wenn man dann noch weiß, dass der inc-Befehl zudem im Prozessordeutlich weniger Taktzyklen benotigt (namlich nur einen einzigen), als ein add-Befehl,dann versteht man erst recht, warum Variante 2 bevorzugt werden sollte.

Schaun wir uns einmal ein Beispielprogramm an. Es soll die Zahlen von 1 bis 100 addierenund dann ausgeben.

/* Beispielprogramm 2 */

#include <stdio.h>

int main(void)

{

int i, j; /* Deklaration von i und j als Integer */

i=0; /* Startwert fur i zuweisen */

j=1; /* Startwert fur j zuweisen */

while (j<=100)

{

i = i+j; /* Nachste Zahl zu altem Wert addieren */

j++; /* j um 1 hochzahlen */

}

printf("Summe von 1 bis 100 = %d\n",i);

return 0;

}

In diesem Programm wurden i und j zunachst deklariert und bekamen erst in einerweiteren Anweisung einen Startwert zugewiesen. Eine Alternative stellt nachfolgendesBeispiel dar. Das Programm macht genau das gleiche.

/* Beispielprogramm 3 */

#include <stdio.h>

int main(void)

{

int i=0; /* Deklaration fur i mit Zuweisung */

int j=1; /* Deklaration fur j mit Zuweisung */

while (j<=100)

{

i = i+j; /* Nachste Zahl zu alter Summe addieren */

j++; /* j um 1 hochzahlen */

}

printf("Summe von 1 bis 100 = %d\n",i);

return 0;

}

Was dazu noch zu klaren ware, ist die while-Schleife sowie die Textausgabe. Zu derwhile-Schleife sei zunachst nur so viel gesagt, dass die Befehle, die innerhalb der nach-folgenden Klammern { } stehen, so lange immer wieder abgearbeitet werden, wie die

14

Page 15: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Bedingung in den runden Klammern (j<=100) erfullt ist. Kummern wir uns zunachstausfuhrlicher um die Ausgabe.

5 Ein-/Ausgabe-Routinen

5.1 Die Ausgabefunktion printf

Fur fast alle Ausgaben bietet sich die Funktion printf aus der Standard-Ein-Ausgabe-Bibliothek an. Sie stellt insofern eine Besonderheit dar, dass man ihr eine beliebige An-zahl von Argumenten ubergeben kann. Dabei ist das erste Argument immer ein String,der in Anfuhrungszeichen gesetzt wird. Enthalt diese Formatzeichenkette aber Format-beschreiber, so werden diese vor der Ausgabe ersetzt durch eine druckaufbereitete Formdes jeweils nachsten Argumentes. Die Druckaufbereitung besteht in Form einer Konver-tierung des Argumentes aus seiner internen Darstellung in eine darstellbare Zeichenkette.Um zu verdeutlichen, was darunter zu verstehen ist, schaun wir uns die Ausgabe ausdem letzten Beispiel an.

printf("Summe von 1 bis 100 = %d\n",i);

Tatsachlich sorgt dieser Befehl fur die Ausgabe:

Summe von 1 bis 100 = 5050

Der Ausgabetext ist identisch mit dem String zwischen den Anfuhrungszeichen bis aufdas %d und das abschließende \n. Das \n ist leicht erklart, es bewirkt lediglich einenZeilenumbruch nach der Textausgabe. Weitere mogliche Steuerzeichen befinden sich ineiner Tabelle im Anhang.

Etwas diffiziler verhalt es sich mit dem %d. An der Stelle, wo dieser Formatbeschreiber imString steht, wird die Variable eingesetzt, die hinter dem String und einem trennendenKomma steht. Dabei gibt der Formatbeschreiber an, wie die Variable zu interpretierenist. Das %d in unserem Beispiel bedeutet, dass die Variable i als Dezimalzahl darge-stellt werden soll. Wenn sie beispielsweise als Hexadezimalzahl dargestellt werden sollte,musste der Befehl so aussehen:

printf("Summe von 1 bis 100 = %x\n",i);

Die Ausgabe sahe damit so aus:

Summe von 1 bis 100 = 13ba

Im Anhang befindet sich eine Tabelle mit den ganigen Formatbeschreibern und ihre Be-deutung.

Es ist auch moglich, mehrere Variablen innerhalb eines String auszugeben. Dann stehenmehrere Formatbeschreiber als Platzhalter darin. Hinter dem String stehen dann genauso viele Variablen, durch Kommata getrennt. Auch dazu ein Beispiel:

15

Page 16: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

char anzahl = 3;

int gewicht = 4;

int summe;

summe = anzahl * gewicht;

printf("%d Akkus zu je %d kg wiegen %d kg.\n",anzahl,gewicht,summe);

Dabei erhalt man folgende Textausgabe:

3 Akkus zu je 4 kg wiegen 12 kg.

Es ist sogar moglich, die gleiche Variable mehrfach, etwa in unterschiedlicher Interpre-tation einzubauen, etwa so:

int i=78;

printf("%d dezimal = %x hexadezimal = %o oktal.\n", i, i, i);

Dabei erhalt man folgende Textausgabe:

78 dezimal = 4e hexadezimal = 116 oktal.

5.2 Aufgabe 1: Programm SUMME2

Erganzen Sie das Beispiel-Programm 3 so, dass nicht nur das Gesamtergebnis, sondernauch jede Zwischensumme ausgegeben wird. Damit alles auf einen Bildschirm passt,lassen Sie nur die Summe der Zahlen von 1 bis 15 berechnen. Die Ausgabe soll etwa wiefolgt aussehen;

0 + 1 = 1

1 + 2 = 3

3 + 3 = 6

6 + 4 = 10

10 + 5 = 15

15 + 6 = 21...

5.3 Die Eingabefunktion scanf

Das Gegenstuck zur Funktion printf ist die Funktion scanf. Damit wird eine Zeichen-kette von der Ein-Ausgabeeinheit, also normalerweise von der Tastatur gelesen. DieseFunktion bietet auch einigen Komfort; ahnlich wie die Funktion printf bei der Ausga-be kann die Funktion scanf bei der Eingabe den Eingabestring beispielsweise als Zahlinterprtieren und bei Bedarf entsprechend umwandeln. Auch hier dienen die erwahntenFormatbeschreiber als Mittel zur Beschreibung des Wunsches.Ein Beispiel:

char st[15]; /* Definition eines String mit 15 Zeichen */

scanf("%s",&*st); /* Einlesen des String von der Tastatur */

16

Page 17: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Zu beachten ist hier, dass der Variable st zusatzlich noch ein & vorangstellt werdenmuss. Um die Hintergrunde dazu werden wir uns spater kummern.Ein anderes Beispiel:

int z;

scanf("%d",&z); /* Eine Dezimalzahl wird eingelesen */

In diesem Beispiel wird eine (mehrstellige) Zahl eingegeben. Der Eingabestring wird vonscanf nicht als String interpretiert, sondern direkt in eine Zahl umgewandelt.Man kann auch mehrere Zahlen

”am Stuck“ von der Tastatur holen, wie nachfolgendes

Beispiel zeigt.

int a,b,c;

scanf("%d%d%x",&a,&b,&c);

Hier werden drei Zahlen erwartet, die ersten beiden im Dezimalformat und die dritte alshexadezimale Zahl. Man muss sie bei der Eingabe nur durch ein Leerzeichen voneinandertrennen.

5.4 Ein-/Ausgabe von Einzelzeichen

Hierfur stehen die Funktionen getchar( ) und putchar( ) zur Verfugung. Ein Aufrufvon getchar( ) liefert ein eingegebenes Zeichen als Funktionswert zuruck. Aus bestimm-ten Kompatibilitatsgrunden, auf die hier nicht naher eingegangen werden soll, ist dieseFunktion als Typ int definiert. Auch putchar( ) erwartet entsprechend das auszuge-bende Zeichen als int-Wert.

Ein Beispiel:

/* Beispielprogramm 4 */

#include <stdio.h>

int main(void)

{

int c=getchar(); /* Ein Zeichen holen (gleichzeitig Deklaration) */

printf("Eingegebenes Zeichen: %c, Nachfolger: ",c);

c ++; /* Zeichen in nachfolgendes wandeln */

putchar(c); /* gewandeltes Zeichen ausgeben */

putchar(10); /* Einen Zeilenumbruch ausgeben */

return 0;

}

Im Hauptprogramm wird zunachst die Integer-Variable c definiert und gleichzeitig mitder Funktion getchar() auf das Zeichen gesetzt, was eingegeben wird. Mit dem Befehl

printf("Eingegebenes Zeichen: %c, Nachfolger: ",c);

17

Page 18: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

wird das Zeichen in bekannter Form in den Text eingebaut und zusammen mit dem Textausgeben. Beachtenswert ist allenfalls, dass kein \n am Stringende steht. Dadurch bleibtder Cursor dort stehen, wo der Ausgabestring zuende ist. Nun wird mit c++; der Zah-lenwert erhoht, also das Nachfolgezeichen berechnet. Dieses wird dann mit putchar(c);an der Cursorstelle ausgegeben. Es steht also direkt hinter dem alten String.

Der nachste Befehl putchar(10); gibt dann das Zeichen fur den Zeilenumbruch aus. Wieman sieht, kann die Funktion putchar also nicht nur Variablen, sondern auch Konstan-ten ausgeben. Wer unter DOS oder WINDOWS programmiert, musste jetzt eigentlichzusatzlich mit dem Befehl putchar(13); das Zeichen fur den Rucksprung des Cursorszum Zeilenanfang ausgeben. Bei diesen Betriebssystemen besteht der Zeilenumbruch auszwei Zeichen.

Leider ist die Funktion getchar nicht ganz sauber. Sie liefert zwar nur ein einzelnesZeichen zuruck, man muss aber bei der Eingabe nach dem gewunschten Zeichen nochein <Enter> eingeben. Das bleibt im Tastaturpuffer, bis moglicherweise getchar erneutaufgerufen wird. Der zweite Aufruf liefert dann das Enterzeichen zuruck, ohne auf eineneue Eingabe zu warten. Daher muss man ggf. bei Schleifen mit mehreren Eingaben einzusatzliches getchar einbauen, um das abzufangen.

18

Page 19: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

6 Einfache Verzweigung

6.1 Die if-Abfrage

Jedes vernunftige Programm benotigt Verzweigungen. Die einfachste Methode ist wohldie Abfrage mit if. Hinter dem if-Befehl steht in runden Klammern eine Bedingung.Ist sie erfullt, dann werden die Anweisungen innerhalb der nachfolgenden geschweif-ten Klammern ausgefuhrt, anderenfalls eben nicht. Es kann noch eine else-Anweisungangehangt werden; deren Befehle werden dann quasi

”ersatzweise“ fur die nicht aus-

gefuhrten Befehle ausgefuhrt. Das”Gerust“ sieht etwa so aus:

if (Bedingung)

{Anweisungen;}

else {Anweisungen;}

Ein Beispiel soll das verdeutlichen.

if (i==10)

{

printf("i ist gleich 10\n");

}

else

{

printf("i ist ungleich 10\n");

}

Falls i gleich 10 ist, wird der erste Text ausgegeben, anderenfalls der zweite.

6.2 Vergleichsoperatoren

Fur die Bedingungen werden Vergleichsoperatoren verwendet, wie beispielsweise ==,>, <, >= oder <=. Eine Tabelle dieser Vergleichsoperatoren befindet sich im Anhang.

In dem Zusammenhang soll noch einmal darauf hingewiesen werden, dass das einfacheGleichheitszeichen nur fur eine Zuweisung und nicht fur Vergleiche verwendet wird.

19

Page 20: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

7 Ubungsaufgaben Teil 1

7.1 Aufgabe 1.1: Programm TASTE1

Erstellen Sie ein Programm mit dem Namen TASTE1, das folgendes macht:

• Zunachst gibt es den”Anleitungstext“aus: Bitte eine Taste drucken!

• Dann wartet es auf Eingaben und gibt zu einem eingegebenen Zeichen den Tasta-turcode in hexadezimaler Form aus.

• Danach beendet sich das Programm.

Die Ausgabe soll etwa so aussehen:

Bitte eine Taste drucken!

x

Taste: x Zeichencode: 78 hex

7.2 Aufgabe 1.2: Programm TASTE2

Erganzen Sie das Programm TASTE1 so, dass insgesamt 10 Zeichen eingegeben wer-den mussen, bevor sich das Programm beendet. Der Anleitungstext wird nur einmal zuBeginn ausgegeben, der andere Text bei jedem Tastendruck. Das neue Programm heißtjetzt: TASTE2.

7.3 Aufgabe 1.3: Programm TASTE3

Andern Sie das Programm TASTE2 so, dass nun so lange eine Ausgabe erfolgt, bis dieTaste q betatigt wird. Erganzen Sie auch den

”Anleitungstext“ wie folgt:

Bitte eine Taste drucken, Ende mit Taste q!

Sie konnen eine while-Schleife wie in Beispielprogramm 2 oder 3 verwenden. Als Bedin-gung benotigen Sie moglicherweise

”solange ungleich“. Dazu wird die Zeichenkombi-

nation != verwendet. Das Programm nennen Sie jetzt TASTE3.

20

Page 21: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

7.4 Aufgabe 1.4: Programm QUADRAT

Schreiben Sie ein Programm mit dem Namen QUADRAT, das der Reihe nach zu denZahlen von 1 bis 15 die Quadrate berechnet und zeilenweise ausgibt. Die Ausgabe siehtdann etwa so aus:

1^2=1

2^2=4

3^2=9

4^2=16

5^2=25...

15^2=225

7.5 Aufgabe 1.5: Programm PRIMZAHL

Schreiben Sie ein Programm mit dem Namen PRIMZAHL, das die ersten 15 Primzahlenberechnet und zeilenweise ausgibt. Die Ausgabe sieht dann etwa so aus:

1

2

3

5

7

11

13

17

19

23

29

31

37

41

43

Ein paar Tips zur Realisierung:Prufen Sie der Reihe nach mit jeder naturlichen Zahl, ob sie ohne Rest durch alle klei-neren Zahlen (großer als 1!) teilbar sind. Das geht mit dem Operator %. a%b liefertals Ergebnis den Rest der Division a:b. Wenn eine Zahl gefunden wurde, durch dieunsere Zahl teilbar ist, dann war sie keine Primzahl und man kann mit der nachstenweitermachen. Hat man alle kleineren Zahlen durchprobiert, dann kann sie als Primzahlausgegeben werden. Sicherlich gibt es erheblich effizientere Algorithmen, aber so ist daszunachst am einfachsten.

21

Page 22: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

8 Schleifen

Es gibt mehrere Moglichkeiten, Programmschleifen zu erstellen. Es gibt die kopfgesteu-erte while-Schleife, die fußgesteuerte while-Schleife und die Zahlschleife.

8.1 Kopfgesteuerte while-Schleife

Bei der kopfgesteuerten Schleife wird die Bedingung vor dem ersten Schleifendurchlaufabgefragt. Es kann also durchaus passieren, dass die Bedingung nie erfullt ist und dieSchleife deshalb nie durchlaufen wird. Der grundsatzliche Aufbau dieser Konstruktionsieht so aus:

while (Bedingung)

{

Befehle;

}

Eine solche Schleife haben wir bereits in unserem 2. Beispielprogramm gesehen.

/* Beispielprogramm 2 */

#include <stdio.h>

int main(void)

{

int i, j; /* Deklaration von i und j als Integer */

i=0; /* Startwert fur i zuweisen */

j=1; /* Startwert fur j zuweisen */

while (j<=100)

{

i = i+j; /* Nachste Zahl zu altem Wert addieren */

j++; /* j um 1 hochzahlen */

}

printf("Summe von 1 bis 100 = %d\n",i);

return 0;

}

So lange die Bedingung (j ≤ 100) erfullt ist, wird der Schleifenkorper

{

i = i+j; /* Nachste Zahl zu altem Wert addieren */

j++; /* j um 1 hochzahlen */

}

ausgefuhrt. Wenn irgendwann j den Wert 101 angenommen hat, ist die Bedingung nichtmehr erfullt und der Schleifenkorper wird ubersprungen. Die Schleife ist damit abgear-beitet.

22

Page 23: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

8.2 Fußgesteuerte while-Schleife

Die Uberprufung der fußgesteuerten Schleife erfolgt nach der Abarbeitung der Befehledes Schleifenkorpers. Die Schleife wird also in jedem Fall mindestens einmal durch-laufen. Wenn am Schluss die Bedingung nicht erfullt ist, wird die Schleife verlassen. DieStruktur der Schleife sieht folgendermaßen aus:

do

{

Befehle;

}

while (Bedingung);

Das Semikolon in der letzten Zeile darf nicht vergessen werden! Das Programm aus demvorangegangenen Beispiel mit einer fußgesteuerten Schleife sahe dann so aus:

/* Beispielprogramm 4 */

#include <stdio.h>

int main(void)

{

int i, j; /* Deklaration von i und j als Integer */

i=0; /* Startwert fur i zuweisen */

j=1; /* Startwert fur j zuweisen */

do

{

i = i+j; /* Nachste Zahl zu altem Wert addieren */

j++; /* j um 1 hochzahlen */

}

while (j<0); /* Abfrage der Bedingung */

printf("Summe von 1 bis 100 = %d\n",i);

return 0;

}

Ob eine kopf- oder fußgesteuerte Schleife angesagt ist, hangt vom Einzelfall ab und mussjeweils vom Programmierer entschieden werden.

23

Page 24: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

8.3 Die for-Schleife

Steht fest, dass eine Schleife eine ganz bestimmte Anzahl von Schleifendurchlaufen ma-chen soll, dann bietet sich die for-Schleife an. Sie wird manchmal auch Zahlschleife ge-nannt. Der Name ist jedoch etwas missverstandlich, denn diese Schleifenform kann mehr.

In dem Kopf der Schleife mussen drei Anweisungen stehen:

1. ein Startwert fur den Zahler

2. eine Durchlaufbedingung (fur das weitere Abarbeiten der Schleife)

3. eine Anweisung zum Weiterstellen des Zahlers

Das sehen wir uns im nachfolgenden Beispiel an.

int z;

for (z=1; z<100; z++)

{

printf("Schleifendurchlauf Nummer %d\n", z);

}

In der Klammer hinter for stehen diese drei Anweisungen. Mit z=1; wird der Zahlerauf einen Startwert gesetzt. Das kann jede beliebige Zahl sein. Die zweite Anweisungz<100; stellt eine Bedingung dar, unter der die Schleife weiter durchlaufen wird. Diedritte Anweisung z++ gibt an, auf welche Weise der

”Zahler“ bei jedem Schleifendurch-

lauf weitergestellt wird.

Zu beachten ist, dass diese dritte Anweisung nicht mit einem Semikolon abgeschlossenist. Sie wird am Ende der Schleife ausgefuhrt, also unmittelbar, bevor die Prufung furden nachsten Schleifendurchlauf ansteht. Daraus ergibt sich, dass unsere Beispielschleifegenau 99 mal ablauft.

In diesem Fall wird der Zahler jeweils um 1 hochgezahlt, es ist aber auch jede andereAnweisung denkbar. Wenn so, wie in diesem Fall innerhalb der Schleife nur ein einzigerBefehl steht, dann konnen auch die Klammern { } entfallen.

Pragen wir uns den allgemeinen Aufbau der for-Schleife an:

for (Start-Zuweisung; Bedingung; Zahlvorschrift)

{

Schleifenbefehle;

}

24

Page 25: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Die for-Schleife ist aber noch machtiger, als das auf den ersten Blick erscheinen mag.Dazu ein Beispiel:

int n, Zahl, Summe;

printf ("Bitte eine Zahl eingeben: ");

scanf ("%d", &n);

for (Summe=0, Zahl=1; Zahl<n+1; Zahl++) Summe +=Zahl;

printf ("Die Summe der Zahlen von 1 bis %d ist %d.\n", n, Summe);

Als”Startwert“ sind hier gleich zwei Werte gesetzt, namlich Summe und Zahl. Beide

bekommen einen eigenen Startwert. Das geht, indem man das sonst fur eine Anweisungabschließende Semikolon durch ein Komma ersetzt. Das Semikolon teilt schließlich indieser Funktion dem C-Compiler mit, wo die Startwertdefinition endet und die Durch-laufbedingung beginnt.

Die Moglichkeit, gleich mehrere Bedingungen – per Komma getrennt – einzufugen, be-steht im Prinzip auch bei der Durchlaufbedingung und auch bei der Zahlvorschrift. Indiesem Beispiel ist das allerdings nicht der Fall. Die Durchlaufbedingung enthalt hiereinen Term, der erst noch berechnet werden muss: n+1. Auch das ist moglich. Ein Beispielgefallig?

int auf, ab;

for (auf=1, ab=10; auf<11, ab>0; auf++, ab--)

printf ("auf:%3d ab:%3d\n", auf, ab);

Bei dem Term zur Durchlaufbedingung auf<11, ab>0; gilt die ODER-Verknupfung; esmuss also nur eine der Bedingungen erfullt sein, damit die for-Schleife weiterlauft. Manhatte also auch schreiben konnen: auf<11 | | ab>0;

Die Befehle auf++, ab-- werden einfach nacheinander ausgefuhrt. Im Prinzip ware essogar moglich alle Befehle des Schleifenkorpers hier unterzubringen; dann bliebe imSchleifenkorper nur das nackte Semikolon ubrig. In wie weit das sinnvoll ist, mag jederfur sich selbst entscheiden.

Zum Schluss sei noch darauf verwiesen, dass der”Schleifenkorper“ nicht unbedingt in

{ } gesetzt werden muss, wenn er nur aus einer einzigen Anweisung besteht. Davonwurde in den beiden letzten Beispielen Gebrauch gemacht.

25

Page 26: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

9 Verzweigungen mit switch

Wenn in Abhangigkeit eines bestimmten Wertes viele unterschiedliche Aktionen durch-gefuhrt werden sollen, dann bietet sich die switch-Anweisung an. Sie entspricht dercase-Anweisung, die der eine oder andere von PASCAL kennt. Der Aufbau dieses Kon-stuktes sieht im Prinzip wie folgt aus6:

switch (Ausdruck)

{

case Konstante1: Anweisung;

case Konstante2: Anweisung;

case Konstante3: Anweisung;

...

[default: Anweisung;]

}

Bevor wir auf die Wirkungsweise dieser Konstruktion eingehen, sollten erst die Begrif-fe geklart werden. Mit Ausdruck ist ein beliebiger, integraler, bewertbarer Ausdruckgemeint. Das ist in der Regel eine int-Variable, es kann aber auch ein Term sein. Kon-stante1, Konstante2, usw. sind feste Werte, mit denen der Ausdruck verglichen werdenkann. Besteht Ubereinstimmung, dann wird der dahinter stehende Befehl – oder ggf. ei-ne Befehlssequenz in { } – ausgefuhrt. Am Schluss kann noch die default-Anweisungstehen. Da sie optional ist, steht sie hier in [ ]. Die Klammern werden aber nicht miteingegeben! Die default-Anweisung bewirkt, dass der Befehl, der dahinter steht, immerabgearbeitet wird, wenn vorher keine Ubereinstimmung gefunden wurde.

Die Wirkungsweise schaun wir uns am besten an einem Beispiel an.

int z;

printf("Bitte eine Zahl eingeben, 0 beendet das Programm.\n");

do

{

scanf("%d",&z);

switch (z)

{

case 1: printf("Zahl = 1\n");

case 2: printf("Zahl = 2\n");

case 3: printf("Zahl = 3\n");

default: printf("Noch einmal!\n");

}

}

while (z!=0);

6Aufgepasst! In dieser vorgestellten Form ist die Case-Anweisung noch nicht sinnvoll zu verwenden.Das wird im Folgenden genauer beschrieben.

26

Page 27: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Nach der Ausgabe der”Bedienungsanleitung“ kommt eine fußgesteuerte while-Schleife.

Diese wird so lange durchlaufen, bis die Null eingegeben wurde. Innerhalb dieser Schleifewird zunachst mit scanf die Tastatur abgefragt. Danach kommt die switch-Anweisung.Wenn keine 1, 2 oder 3 eingegeben wurde, erfolgt die Textausgabe: Noch einmal!

Gibt man jedoch beispielsweise eine 2 ein, dann erhalt man ein vermutlich unerwartetesErgebnis. Die Ausgabe sieht dann namlich so aus:

Zahl = 2

Zahl = 3

Noch einmal!

Wieso? Nachdem einmal eine Ubereinstimmung gefunden wurde, wird ab der Stelle allesausgefuhrt, was noch an Befehlen (auch hinter anderen case-Anweisungen) folgt. Willman das nicht, dann muss hinter dem letzten noch auszufuhrenden Befehl die Anwei-sung break; gesetzt werden. Diese Anweisung bewirkt, dass an das Ende des gesamtenswitch-Befehls gesprungen wird. In dieser Form entspricht das der case-Anweisung, wiesie in PASCAL verwendet wird. In unserem Beispiel sahe das dann so aus:

int z;

printf("Bitte eine Zahl eingeben, 0 beendet das Programm.\n");

do

{

scanf("%d",&z);

switch (z)

{

case 0: ; break;

case 1: printf("Zahl = 1\n"); break;

case 2: printf("Zahl = 2\n"); break;

case 3: printf("Zahl = 3\n"); break;

default: printf("Noch einmal!\n");

}

}

while (z!=0);

In dieser Form macht das Programm bei jeder Eingabe tatsachlich nur eine einzige Aus-gabe. Auffallig ist noch die erste case-Anweisung. Im Fall z=0 ist die auszufuhrendeAnweisung auf ein einziges Semikolon geschrumpft – es wird eben nichts gemacht. Essoll ja auch nur das Programm beendet werden.

27

Page 28: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

10 Ubungsaufgaben Teil 2

10.1 Aufgabe 2.1: Programm RECHNER1

Erstellen Sie einen einfachen Rechner fur die vier Grundrechenarten. In der Eingabe-zeile sollen stets zwei Zahlen mit einem Rechenoperator dazwischen eingegeben werden.Zunachst sind alle Zahlen vom Typ Integer. Das Programm stellt sich wie folgt dar:Beim Programmstart erscheint folgender Text:

Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:

Dann wartet das Programm auf eine Eingabe. In einer einzigen Zeile soll zunachst ei-ne Zahl, dann ein Leerzeichen, dann ein Rechenzeichen, noch ein Lerzeichen und zumSchluss noch eine Zahl eingegeben werden. Wird beispielsweise 13 + 17 eingegeben,dann steht auf dem Bildschirm:

Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:

13 + 17

13 + 17 = 30

Dann beendet sich das Programm.

Als Rechenzeichen sind die vier Zeichen + - * / moglich. Bei der Division erscheint nurdas ganzzahlige Divisionsergebnis, ansonsten sind die Ergebnisse korrekt.

Wird ein falsches Zeichen anstelle des Rechenzeichens eingegeben, dann erscheint derText:

Falsche Eingabe!

Anschließend beendet sich das Programm.

10.2 Aufgabe 2.2: Programm RECHNER2

Nehmen Sie das Programm RECHNER1 aus vorstehender Aufgabe. Erganzen Sie es so,dass fur die Division nun nicht nur der Schragstrich, sondern auch der Doppelpunkterlaubt ist.

28

Page 29: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

10.3 Aufgabe 2.3: Programm RECHNER3

Nehmen Sie das Programm RECHNER2 aus vorstehender Aufgabe. Erganzen Sie esdahingehend, dass nach erfolgter Rechnung die Frage erscheint:

Noch eine Rechnung? (j/n)

Gibt man ein j ein, dann wartet das Programm auf eine neue Eingabe. Wird ein n ein-gegeben, dann beendet sich das Programm. Wie sich das Programm verhalten soll, wennetwas anderes eingegeben wird, konnen Sie zunachst selbst entscheiden.

10.4 Aufgabe 2.4: Programm RECHNER4

Nehmen Sie das Programm RECHNER3 aus vorstehender Aufgabe. Erganzen Sie es nunso, dass bei jeder anderen Eingabe als j, J, n oder N die Frage:

Noch eine Rechnung? (j/n)

wiederholt wird. Das Programm kann jetzt mit j oder J fortgesetzt bzw. mit n oder Nbeendet werden.

10.5 Aufgabe 2.5: Programm RECHNER5

Nachdem das Programm aus Aufgabe 2.4 so weit ausgereift ist, andern Sie es dahinge-hend ab, dass nun die Zahlen, mit denen gerechnet wird, als Fließkommazahlen definiertsind. Dadurch wird nun auch das Ergebnis einer Division korrekt berechnet.

29

Page 30: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

10.6 Aufgabe 2.6: Programm FAKTOR

Schreiben Sie ein Programm, das folgendes macht:

• Zuerst gibt das Programm die Anweisung aus:

Bitte eine Zahl eingeben!

Dann wartet das Programm auf die Eingabe einer Zahl.

• Sobald diese erfolgt ist, erfolgt die Textausgabe:

Die Zahl wird in Primfaktoren zerlegt...

• Nun wird die Zahl noch einmal an den Anfang der nachsten Zeile geschrieben. Da-hinter steht ein Gleichheitszeichen und es folgt die Zerlegung. Wird beispielsweiseeine 420 eingegeben, ergibt sich folgendes Bildschirmbild:

Bitte eine Zahl eingeben! 420

Die Zahl wird in Primfaktoren zerlegt...

420 = 2 * 2 * 3 * 5 * 7

Die Berechnung im Programm arbeitet wie folgt: Beginnend mit der Zahl 2 werden alleZahlen als Teiler ausprobiert, bis eine Zahl gefunden ist, durch die die gegebene Zahlteilbar ist. Dann wird der Teiler ausgegeben und die gegebene Zahl durch den Teilerdividiert. Wenn die gegebene Zahl dann noch nicht gleich 1 ist, wird auch noch das

”Malzeichen“ ausgegeben. Dann fangt man sozusagen wieder von vorne an und probiert

bei 2 beginnend wieder die Teilbarkeit aus.

30

Page 31: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

11 Unterprogramme / Funktionen

Unterprogramme sind ein wesentliches Element zur ubersichtlichen und effizienten Pro-grammierung. In manchen Programmiersprachen (beispielsweise PASCAL) wird zwi-schen Prozeduren und Funktionen unterschieden. C kennt diese Unterscheidung nicht(wie auch in ASSEMBLER kein Unterschied besteht). In C gibt es ausschließlich Funk-tionen. Aufgerufen wird eine Funktion mit ihrem Namen und dahinter in runden Klam-mern die eventuellen Ubergabeparameter. Das kennen wir bereits von einigen Funktionenwie printf oder scanf aus der Standard-Bibliothek stdio.h. Hier wollen wir uns nunum die Erstellung einer Funktion selbst kummern.

Der Aufbau einer Funktion gleicht sehr dem Aufbau von main. Das ist kein Zufall, dennmain ist vom Prinzip auch nur eine Funktion. So sieht der Aufbau aus:

Typ Funktionsname (Ubergabeparameter)

{

...

return Wert;

}

Eine Funktion gibt in aller Regel einen Wert zuruck. Der Typ dieses Ruckgabewertesist der Funktionstyp. Deshalb muss er hier definiert werden. Der Funktionsname ist einfrei wahlbarer Begriff nach den gleichen Bedinungen, wie fur einen Variablennamen.Die Ubergabeparameter stehen mit Kommata voneinander getrennt in runden Klam-mern. Vor jedem Parameter (dessen Name wie ein Variablenname frei wahlbar ist) stehtder Typ des jeweiligen Parameters. Gibt es keine Ubergabeparameter, dann bleiben dieKlammern leer, oder man schreibt void hinein.

Zum Hintergrund: Das aufrufende Programm legt diese Werte in der Reihenfolge vonrechts nach links auf dem Stapel ab, bevor mit dem call-Befehl das Unterprogrammaufgerufen wird. Dort stehen sie dem Unterprogramm zur Verfugung. Nach Abarbeitungdes Unterprogramms bereinigt das aufrufende Programm den Stapel wieder.

Innerhalb der geschweiften Klammern { } stehen dann die Befehle, die die Funktionausmachen. Als letzter Befehl steht hier return Wert. Damit wird der Ruckgabewertder Funktion gesetzt. Je nach Funktionstyp wird damit bewirkt, dass das Register AL,AX oder EAX oder der letzte Wert auf dem FPU-Stack auf den entsprechenden Wertgesetzt wird, bevor der Rucksprung ins aufrufende Programm erfolgt. Diesen Registerin-halt kann dann das aufrufende Programm weiter verarbeiten. Soll das Unterprogrammkeinen Ruckgabewert liefern (wie beispielsweise bei printf), dann entfallt der return-Befehl.

31

Page 32: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Ein Beispiel soll das verdeutlichen. Wir wollen mit Hilfe der Funktion sum die Summezweier (Integer-) Zahlen bilden. Zugegeben – eine solche Funktion ist nicht sonderlichsinnvoll. Sie kann aber das Prinzip einer Funktion gut zeigen.

int sum(int zahl1, int zahl2) /* Deklaration der Funktion */

{

int ergebnis; /* Deklaration lokale Variable */

ergebnis = zahl1 + zahl2;

return ergebnis; /* Ergebnis zuruckliefern */

}

Die Funktion erhalt den Typ int (wegen des Ruckgabewertes als Integerzahl). ZweiUbergabeparameter von Typ int werden deklariert. Die Namen sind fur den Rest desProgramms ohne Belang; sie sind nur innerhalb der Funktion gultig, stellen also lokaleVariablen dar. Auch die Variable ergebnis kann nur innerhalb der Funktion verwen-det werden, sie wird auf dem Stapel angelegt. (Da nach Abarbeitung der Funktion derzugehorige Stapelbereich wieder freigegeben wird, sind damit die Inhalte weg.) ZumSchluss wird die Summe berechnet und als return-Wert ins Register EAX geschrieben.

Der zugehorige Aufruf konnte dann etwa so aussehen:

int a=3; /* Variablendeklaration */

int b=5; /* Variablendeklaration */

int c; /* Variablendeklaration */

c = sum(a,b); /* Eigentlicher Funktionsaufruf */

Hierbei stellen die ersten drei Zeilen nur klar, wie die verwendeten Variablen deklariertwurden. In der Variablen c steht anschließend die Summe, die in der Funktion gebildetwurde.

Wichtig zu wissen ist, dass die Variablennamen innerhalb der Funktion absolut nichtsmit den Variablennamen außerhalb der Funktion zu tun haben; lediglich der Variablentypbeim Aufruf der Funktion muss mit dem Typ innerhalb der Funktion ubereinstimmen.

32

Page 33: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

12 Ubungsaufgaben Teil 3

12.1 Aufgabe 3.1: Programm GROSS1

Das Programm GROSS1 soll folgendermaßen arbeiten:

• Nach dem Programmstart wartet das Programm auf die Eingabe beliebiger Zei-chen.

• Nach der Eingabe werden alle Kleinbuchstaben des Alphabetes in Großbuchstabengewandelt und wieder ausgegeben. Die anderen Zeichen wie Punkt, Komma, Klam-mern, Ziffern, Großbuchstaben, etc. bleiben erhalten. Die Umlaute sind (zunachst)nicht berucksichtigt.

• Gestalten Sie das Programm so, dass ein Unterprogramm die Umwandlung jedesZeichens in einen Großbuchstaben ubernimmt. Dazu ein Tip: Der Zeichencode einesGroßbuchstabens ist immer um 32 kleiner, als der zugehorige Kleinbuchstabe.

• Es werden so lange Zeichen ausgegeben, bis die Entertaste7 betatigt wurde. Danachbeendet sich das Programm.

Nach der Eingabe der Zeichenkette abcde123ABCaouAOU+#! und abschließendem Entersieht die Bildschirmausgabe so aus:

abcde123ABCaouAOU+#!

ABCDE123ABCaouAOU+#!

Verwenden Sie die Standardfunktionen getchar und putchar zur Zeichenein- und aus-gabe.

7Der Zeichencode der Entertaste hangt vom Betriebssystem ab. Unter Linux ist es der Zeichencode0Ahex=10dez, unter DOS ist es der Zeichencode 0Dhex=13dez. Unter Windows konnen es beideZeichen sein, je nachdem, in welcher Umgebung man arbeitet.

33

Page 34: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

12.2 Aufgabe 3.2: Programm GROSS2

Erganzen Sie das Programm GROSS1 so, dass nun auch die Umlaute in Großbuchstabenumgewandelt werden. Das Programm heißt dann GROSS2. Nach der Eingabe der Zeichen-kette abcde123ABCaouAOU+#! und abschließendem Enter sieht die Bildschirmausgabe soaus:

abcde123ABCaouAOU+#!

ABCDE123ABCAOUAOU+#!

Fur diese Umwandlung (innerhalb des Unterprogramms) bietet sich der switch-Befehlan. Als Hilfestellung dafur hier ein Ausschnitt aus den Zeichensatz-Tabellen modernerBetriebssysteme mit UTF8-Codierung und Windowssystemen im DOS-Modus:

UTF8-Codierung moderner Systeme: DOS-Fenster unter Windows:Zeichen Hex-Code

a C3 A4

A C3 84

o C3 B6

O C3 96

u C3 BC

U C3 9C

Zeichen Hex-Codea 84

A 8E

o 94

O 99

u 81

U 9A

34

Page 35: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

12.3 Aufgabe 3.3: Programm KOMPLEX

Erstellen Sie ein Programm, das einen Rechner fur die vier Grundrechenarten mit Kom-plexen Zahlen darstellt. Verwenden Sie dazu die Struktur des Programms RECHNER5

aus Aufgabe 2.5. Verlegen Sie zumindest die Rechenalgorithmen fur die Mul-tiplikation und die Division in Unterprogramme. Da eine Funktion nur eineneinzigen Wert zuruckliefert, konnen wir nicht ohne weiteres das komplette komplexeErgebnis als Funktionswert darstellen. Daher sollten Sie beispielsweise fur das Produktje eine Funktion fur den Realteil und eine fur den Imaginarteil entwerfen.

Fur alle, denen die Komplexe Rechnung nicht mehr ganz parat ist, hier noch einmal diemathematischen Grundlagen dazu:

Es sei x¯

= a + jb und y¯

= c + jd. Dann ist:

+ y¯

= (a + c) + j(b + d)

x¯− y

¯= (a− c) + j(b− d)

x¯· y¯

= (a · c− b · d) + j(a · d + b · c)x¯y¯

=a · c + b · dc2 + d2

+ jb · c− a · dc2 + d2

Zunachst gibt das Programm eine kleine”Bedienungsanleitung“ aus:

Bitte zwei Komplexe Zahlen mit einem Rechenzeichen dazwischen eingeben!

Eingabeformat:

Realteil1 Imaginarteil1 Rechenzeichen Realteil2 Imaginarteil2

Nach der Eingabe der Werte stellt sich die Ausgabe des Programms dann beispielsweisewie folgt dar:

Bitte zwei Komplexe Zahlen mit einem Rechenzeichen dazwischen eingeben!

Eingabeformat:

Realteil1 Imaginarteil1 Rechenzeichen Realteil2 Imaginarteil2

-12 3 * 14 -8

(-12+j3)*(14-j8)=-144+j138

35

Page 36: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

13 Vektoren / Felder

Manchmal ist es sinnvoll, mehrere Variable zu einer Einheit zusammenzufassen. EinString ist beispielsweise eine solche Zusammenfassung von Buchstaben. So etwas ist einVektor oder ein Feld. Man spricht auch von Tabellen und Arrays.

13.1 Vektoren (Eindimensionale Felder)

Definition: Vektoren sind Datenaggregate, bestehend aus mehreren Elemen-ten des gleichen Datentyps. Alle Elemente des Vektors stehen zusammenhangendim Speicher, jedes Element ist duch einen ganzzahligen Index adressierbar und dannwie eine normale Variable verwendbar. Ein String ist ein Beispiel fur einen solchen Vek-tor vom Variablentyp unsigned char. Die einzelnen Zeichen liegen hintereinander imSpeicher, wobei das Zeichen mit dem Wert 0 als letztes Zeichen eine Stringendemarkedarstellt. Jedes Zeichen kann mit Hilfe seiner Zeichennummer einzeln angesprochen wer-den. Dabei hat das erste Zeichen die Zeichennummer 0, das zweite Zeichen 1 usw. EinBeispiel dazu:

unsigned char string[21];

string[0] = ’G’;

string[1] = ’u’;

string[2] = ’t’;

string[3] = 0;

In der ersten Zeile wird ein String fur 20 Zeichen deklariert. (Das sind inclusive Strin-gendemarke 21.) Mit den nachsten drei Befehlen wird am Stringanfang der Text Gut

hineingeschrieben. Es folgt die Stringendemarke mit dem Wert 0. Ubersetzt werden dieBefehle so:

STRING db 21 dup ?

mov B[STRING+0],’G’

mov B[STRING+1],’u’

mov B[STRING+2],’t’

mov B[STRING+3],0

Hieraus kann man gut erkennen, dass string die Adresse des ersten Zeichens angibt.Die Zahl in [ ] gibt an, wieviele Variablenlangen zur Adresse des aktuellen Zeichenshinzugezahlt werden mussen, um das entsprechende Zeichen zu schreiben oder zu lesen.Besteht der Vektor aus langeren Variablen (z.B. Integer), dann rechnet der Compiler diezu addierenden Adressdifferenzen entsprechend um.

Zur Adressierung durfen nicht nur Konstanten verwendet werden, sondern auch Va-riablen. Diese mussen dann von einem ganzzahligen Typ sein wie char oder int. EinBeispiel dazu:

36

Page 37: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

#include <stdio.h>

int main(void)

{

int a[10]; /* Der Vektor */

int i; /* Indexzahl */

for (i=0;i<10;i++) a[i]=2*i;

for (i=0;i<10;i++) printf("%d\n",a[i]);

return 0;

}

Dieses Beispiel ist zugegebenermaßen nicht sonderlich sinnvoll. Hier wird (in Zeile 4)ein Vektor definiert, dann werden (in Zeile 6) die geraden Zahlen von 0 bis 18 in denVektor hineingeschrieben und anschließend (in Zeile 7) Element fur Element ausgegeben.

An diesem Beispiel wird vielleicht auch ein Problem deutlich, dass beim Umgang mitFeldern immer beachtet werden muss. Verlasst aus irgendeinem Grund der Index i denBereich zwischen 0 ≤ i ≤ 9, dann erfolgt der Zugriff außerhalb des definiertenBereiches . Moglicherweise werden dadurch gnadenlos andere Variablen uberschrieben.Dann zeigen sich allerlei unerwartete Ergebnisse, die oft auch nicht reproduzierbar sind.Bei sehr großen Werten (oder auch sehr groß negativen Werten) fur i kann es auchpassieren, dass der Zugriff in einem fremden Datenbereich passiert. Unter Betriebssyste-men im

”Protected Mode“ wie Linux oder Windows wird dann ein Speicherzugriffsfehler

(unter Windows mit dem Begriff”allgemeine Schutzverletzung“ bezeichnet) gemeldet.

Das Programm hatte dann schlichtweg keine Berechtigung, auf diese Speicherstellen zu-zugreifen. Gerade diese Probleme sind die Quelle vieler Sicherheitslucken vonin C geschriebenen Programmen!

Ein C-Programmierer muss selbst darauf achten,dass der Gultigkeitsbereich seiner Felder

niemals uberschritten werden kann!

Testen Sie das einmal, indem Sie in dem obigen Beispielprogramm in einer der for-Schleifen die 10 im Befehl i<10 durch eine sehr große Zahl wie beispielsweise 10000ersetzen.

Ein Vektor kann sofort bei der Definition mit Anfangswerten initialisiert werden. Dassieht dann beispielsweise so aus:

int liste[5]={7, -5, 12};

Definiert wird hierdurch ein int-Vektor mit Namen liste mit 5 Elementen. Die erstendrei werden mit den Werten 7, −5 und 12 initialisiert, die beiden letzten Elementeerhalten automatisch den Startwert 0. Generell konnen beliebig viele Startwerte gesetztwerden, jedoch nicht mehr, als der Vektor Elemente hat. Initialisiert man alle Elementedes Vektors, dann kann man auch die Angabe der Dimension weglassen. Die Anzahl derStartwerte wird dann automatisch als Dimension unterstellt. Die Definition sieht dannetwa so aus:

37

Page 38: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

int liste[]={7, -5, 12, 0, 3};

Diese Art der Definition ist bei allen Datentypen moglich, sie ist aber nur unmittelbarbei der Definition erlaubt.

Als Sonderfall des Vektors gelten Strings. Er konnte nach dieser Methode so definiertwerden:

char name[]={’F’,’r’,’i’,’t’,’z’,0};

Der Vektor enthalt 6 Elemente, namlich die 5 Buchstaben und die Stringendemarke. Dasist nicht sonderlich bequem einzugeben. Daher ist auch folgende Schreibweise zulassig:

char name[]="Fritz";

Auch hierdurch wird ein Vektor mit 6 Elementen definiert; die Stringendemarke ist im-plizit in der Stringkonstanten enthalten. Sie muss also nicht ausdrucklich angegebenwerden.

Soll ein ganzer Vektor als Argument an eine Funktion ubergeben werden, dann ergibtsich ein Problem. Es ist schlecht moglich, den ganzen Vektor mit allen Elementen vordem Funktionsaufruf auf den Stapel zu legen. Daher wird hierbei nur die Adresse desersten Elementes des Vektors auf den Stapel gelegt. Die Funktion bekommt alsonicht einfach eine Kopie von Variablen zu Gesicht, sie erhalt Zugriff auf die Originale.Damit sind im Gegensatz zu

”normalen“ Ubergabeparametern nicht nur Lesezugriffe,

sondern auch Schreibzugriffe moglich. Weiteres hierzu spater im Kapitel uber Zeiger.

Das hat auch Konsequenzen fur die Gestaltung der Funktion und des Aufrufes. BeimAufruf der Funktion wird der Name des Vektors (ohne []-Klammern) ubergeben. In derFunktion selbst wird dafur als Parameter ein Vektor mit leeren []-Klammern definiert.Ein Beispiel:

38

Page 39: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

#include <stdio.h>

void set(int vek[], int n)

{

int i;

for(i=0;i<n;i++) vek[i]=i+1;

}

int main(void)

{

int i;

int zahlen[5];

set(zahlen, 5);

for(i=0;i<5;i++) printf("%d ", zahlen[i]);

putchar(’\n’);

return 0;

}

Der Vektor zahlen wird beim Aufruf der Funktion set() als Argument ubergeben anvek, der dort als Vektor ohne Anzahl der Elemente definiert ist. Außerdem wird alszweites Argument die Anzahl der Elemente von zahlen an n ubergeben. So

”weiß“ die

Funktion, wie groß der ubergebene Vektor ist. In der Funktion set() wird jedem Ele-ment eine Zahl (1, 2, 3, 4, 5) zugewiesen. Da die Funktion Zugriff auf den Original-Vektorhat, ist dies moglich. Nach der Ruckkehr aus der Funktion set() werden die Elementedes Vektors ausgegeben. Anmerkung am Rande: Da die Funktion set() keinen return-Wert zuruckliefert, ist ihr Typ void.

39

Page 40: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

13.2 Arrays (Mehrdimensionale Felder)

13.2.1 Aufbau

Ein mehrdimensionales Feld besteht aus zusammehangenden Elementen gleichen Daten-typs, die uber mehrere Indizes angesprochen werden konnen. Bei einem zweidimensio-nalen Feld – auch Matrix genannt – konnte man auch sagen, es handelt sich um einenVektor, dessen Elemente ebenfalls Vektoren sind. Die Definition einer 2× 3-Matrix (mit6 float-Elementen) sieht dann etwa so aus:

float matrix[2][3];

Die entsprechende Darstellung einer solchen Matrix in der Mathematik sieht so aus:

A =

(a11 a12 a13a21 a22 a23

)13.2.2 Verwendung

Angesprochen werden diese Felder genauso, wie eindimensionale Felder, nur dass ebenzwei (oder mehr) Indizes angegeben werden. Nachfolgendes Programmbeispiel zeigt, wiediese Matrix von Hand eingegeben werden kann.

float matrix[2][3]; /* Definition der Matrix */

int i,j; /* Definition der Indizes */

for (i=1;i<=2;i++) /* Außere Eingabeschleife */

{

for (j=1;j<=3;j++) /* Innere Eingabeschleife */

{

printf("a%d%d= ",i,j);

scanf("%f", &matrix[i-1][j-1]);

}

}

Durch diese Sequenz wurde die Matrix zeilenweise eingegeben. Durch die verschachtelteSchleife wird zunachst in der außeren Schleife mit i=1 begonnen. Dann geht es bei j=1los, wobei j stufenweise erhoht wird. Danach geht es mit i=2 genau so weiter. Weil dieC-interne Nummerierung bei 0 beginnt, das erste Element aber a11 und nicht a00 heißensoll, werden in dem Befehl

scanf("%f", &matrix[i-1][j-1]);

die Indizes i und j jeweils um 1 vermindert. Der Funktion scanf() wird dabei ein Zeigerauf genau das jeweilige Element der Matrix ubergeben.

40

Page 41: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

13.2.3 Mehrdimensionale Felder in Funktionen

Bleibt noch die Frage, wie mehrdimensionale Felder in einer Funktion deklariert undwie diese an eine Funktion ubergeben werden. Dies sehen wir uns zunachst an einemBeispiel an. Nachfolgend ist die mogliche Deklaration einer Funktion zur Berechnungeiner Determinante dargestellt.

float berechnung (float det[][10], int n)

Der zugehorige Funktionsaufruf konnte dann etwa so aussehen:

d=berechnung(determinante, n);

Auf den ersten Blick sieht die Deklaration etwas misslungen aus. Klar ist, dass dieFunktion einen Ruckgabewert vom Typ float liefert. Klar ist auch, dass auch das Ar-ray Zahlenwerte vom Typ float enthalt. Und klar ist vielleicht auch, dass der Funktiondie Anzahl der Spalten als n ubergeben wird. Wieso aber ist der Inhalt der ersten eckigenKlammern [] leer, wogegen die zweiten Klammern einen Zahlenwert [10] enthalten?Irgendwie erscheint das vermutlich unlogisch.

Zum Verstandnis muss man sich klar machen, was eigentlich ein zwei (oder mehr-) di-mensionales Feld ist. Im Grunde handelt es sich um ein eindimensionales Feld, dessenElemente ebenfalls Felder sind. Wenn das zweite oder dritte

”Unterfeld“ angesprochen

werden soll, muss ein Zeiger auf den Anfang der jeweiligen Struktur weitergestellt wer-den. Dazu muss die Funktion eben

”wissen“, wie viele Bytes diese Struktur lang ist.

Neben dem Variablentyp ist dann auch die Anzahl der Variablen in dieser Strukturwichtig. Wenn also beispielsweise in einer Zeile einer Determinante 10 Werte vom Typfloat (mit 4 Byte Lange) stehen, dann belegt eine Zeile 40 Byte. Soll die Funktion vonZeile 0 auf Zeile 1 weiterschalten, muss der zugehorige Zeiger um 40 Byte weitergestelltwerden. Diese Informationen bezieht die Funktion aus der [10] in der zweiten Klammersowie dem Variablentyp. Wieviele solcher Zeilen vorhanden sind, kann der Funktiongleichgultig sein, zur Berechnung der Adressierung benotigt sie diese Angabe nicht. DerProgrammierer hat gefalligst selbst darauf zu achten, dass nur gultige Bereiche ange-sprochen werden. Daher bleibt die erste Klammer [] leer. Er gibt diese Information mitHilfe einer anderen Variablen (hier n) an die Funktion, wenn er das fur erforderlich halt.

Beim Aufruf der Funktion taucht nur der Variablenname des Feldes auf, genau so,wie bei eindimensionalen Feldern. Die Variable determinante ist in unserem Beispielsicherlich irgendwo als mehrdimensionales float-Feld deklariert worden, auch wenn dasin diesem Auszug nicht auftaucht. Daher wird unter diesem Namen nicht der Inhalt,sondern die Adresse des Anfangs dieser Datenstruktur an die Funktion ubergeben. Damithat die Funktion die Moglichkeit, die Originaldaten zu lesen und auch zu verandern.

41

Page 42: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

14 Ubungsaufgaben Teil 4

14.1 Aufgabe 4.1: Programm GROSS3

Erstellen Sie ein Programm mit dem Namen GROSS3 mit folgenden Bedingungen:Zunachst liest das Programm von der Tastatur mit der Funktion scanf einen beliebigenString ein. Sie haben dazu hoffentlich einen ausreichend langen Bereich als String initia-lisiert. In einer Schleife holen Sie der Reihe nach alle Zeichen aus dem String, wandeln siemit der Funktion, die Sie bereits im Programm GROSS2 erstellt haben, in die zugehorigenGrossbuchstaben und fugen Sie sie anschließend wieder in den String ein. Das fuhrenSie durch, bis Sie auf die Stringendemarke stoßen. Anschließend fugen Sie noch einenZeilenumbruch (Zeichen mit Wertigkeit 10) an. Zum Abschluss geben Sie den String mitprintf wieder aus. Die Bildschirmausgabe sieht dann beispielsweise so aus:

abcdeABCDEaouAOU12345

ABCDEABCDEAOUAOU12345

14.2 Aufgabe 4.2: Programm SKALAR

Erstellen Sie ein Programm, das das Skalarprodukt zweier Vektoren berechnet. Hierzunachst der mathematische Hintergrund.

Ein Vektor ist eine geordnete Liste von Zahlen. Die Anzahl der Komponenten (Zahlen)in einem Vektor heißt: Dimension des Vektors. Vektoren konnen in Spaltenform oderin Zeilenform dargestellt werden. Die Schreibweise fur einen n-dimensionalen Vektorsieht dann so aus:

~a =

a1a2a3...an

= (a1 a2 a3 . . . an)

Vektoren kann man miteinander multiplizieren. Das Skalarprodukt zweier Vektoren ~aund ~b ist wie folgt definiert:

~a ◦~b =

a1a2a3...an

b1b2b3...bn

= a1 · b1 + a2 · b2 + . . . + an · bn

Das Ergebnis ist ein Skalar, also eine”normale“ Zahl, kein Vektor.

42

Page 43: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Kommen wir nun zu der Programmieraufgabe zuruck. Das Programm arbeitet wie folgt.

• Zuerst schreibt das Programm die Uberschrift: Berechnung des Skalarproduktes

• Dann fragt das Programm nach der Dimension der Vektoren. Zulassig ist ei-ne Zahl von mindestens 2 und hochstens 10. Bei einer anderen Eingabe soll dasProgramm erneut fragen, bis ein Wert im richtigen Bereich eingegeben ist.

• Anschließend fragt das Programm nacheinander die Werte fur a1 bis an ab, wobein die eben eingegebene Dimension der Vektoren ist.

• Danach geschieht das gleiche mit b1 bis bn.

• Nach der Eingabe von bn gibt das Programm die beiden Vektoren noch einmal ausund dahinter das Ergebnis des Skalarproduktes.

• Zum Abschluss fragt das Programm nach, ob noch eine weitere Rechnung gewunschtwird. Die Abfrage entspricht der Aufgabe 2.4, Programm RECHNER4.

Nach Beendigung des Programms konnte der Bildschirm etwa so aussehen:

Berechnung des Skalarproduktes

Geben Sie die Dimension ein: 12

Unzulassige Eingabe!

Geben Sie die Dimension ein: 3

a1= 5

a2= -2

a3= 4

b1= 1

b2= 0

b3= -8

(5 -2 4)o(1 0 -8)=-27

Noch eine Rechnung? (j/n) n

43

Page 44: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

14.3 Aufgabe 4.3: Programm KREUZ

Erstellen Sie ein Programm, das das Kreuzprodukt zweier Vektoren berechnet. Hierzunachst der mathematische Hintergrund.

Das Kreuzprodukt – auch Vektorprodukt genannt – ist nur im R3 definiert. Dasbedeutet, es gibt das Kreuzprodukt ausschließlich fur dreidimensionale Vektoren. DieDefinition sieht so aus: a1

a2a3

× b1

b2b3

=

a2 · b3 − a3 · b2a3 · b1 − a1 · b3a1 · b2 − a2 · b1

Alles andere zu Vektoren, was hier von Bedeutung ist, ist bereits zur vorangegangenenAufgabe gesagt worden.

Das Programm, das Sie schreiben sollen, arbeitet wie folgt:

• Zunachst schreibt das Programm die Uberschrift:Berechnung des Kreuzproduktes zweier Vektoren

• Dann werden der Reihe nach die Parameter a1, a2, a3, b1, b2 und b3 abgefragt; derAnwender des Programms gibt sie ein.

• Nach der Eingabe von b3 berechnet das Programm das Kreuzprodukt und gibt alsErgebnis zunachst die beiden eingegebenen Vektoren in Zeilenform und danachdas Vektorprodukt aus.

• Zum Schluss fragt das Programm, ob noch eine weitere Rechnung erfolgen soll.Nach Eingabe von j oder n beginnt die Eingabe von vorn bzw. beendet sich dasProgramm.

44

Page 45: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Nach der Berechnung folgender Aufgabe 1−23

× −4

56

=

−27−18−3

sieht der Bildschirm so aus:

Berechnung des Kreuzproduktes zweier Vektoren

a1 = 1

a2 = -2

a3 = 3

b1 = -4

b2 = 5

b3 = 6

(1 -2 3)x(-4 5 6) = (-27 -18 -3)

Noch eine Rechnung? (j/n) n

45

Page 46: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

14.4 Aufgabe 4.4: Programm DET3

Erstellen Sie ein Programm, das eine dreireihige Determinante berechnet. Zur Berech-nung konnen Sie den Satz von Sarrus verwenden:

a11 a12 a13a21 a22 a23a31 a32 a33

= a11a22a33 + a12a23a31 + a13a21a32 − a31a22a13 − a32a23a11 − a33a21a12

Beim Programmstart erscheint folgender Text auf dem Bildschirm:

Berechnung einer dreireihigen Determinante

Auswahl:

1: Kompletteingabe zeilenweise

2: Kompletteingabe spaltenweise

3: Eine Zeile eingeben

4: Eine Spalte eingeben

5: Determinante berechnen

6: Beenden

Durch Eingabe einer Zahl zwischen 1 und 6 konnen die angegebenen Menupunkte aufge-rufen werden. Bei Eingabe einer 1 werden alle Parameter der Determinante zeilenweiseabgefragt und eingegeben. Nach Eingabe von a33 zeigt das Programm die Determinantenoch einmal an, berechnet die Determinante und gibt das Ergebnis aus. Danach wird dasAuswahlmenu wieder angezeigt. Auf dem Bildschirm ist dann etwa folgendes zu sehen:

a11= 1

a12= 3

a13= -5

a21= 0

a22= 2

a23= 4

a31= -1

a32= -2

a33= -3

| 1 3 -5|

| 0 2 4| = -20

| -1 -2 -3|

1: Kompletteingabe zeilenweise

2: Kompletteingabe spaltenweise

3: Eine Zeile eingeben

4: Eine Spalte eingeben

5: Determinante berechnen

6: Beenden

46

Page 47: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Bei Eingabe einer 2 erfolgt die Eingabe der Parameter spaltenweise; alles andere lauftab, wie bei der zeilenweisen Eingabe. Der Eingabeteil bei der gleichen Determinantensahe dann auf dem Bildschirm so aus:

a11= 1

a21= 0

a31= -1

a12= 3

a22= 2

a32= -2

a13= -5

a23= 4

a33= -3

Wird eine 3 oder eine 4 eingegeben, dann kann man eine einzelne Zeile oder Spalteeingeben. Als erstes fragt das Programm dann nach der Nummer der Zeile oder Spalte.Ist diese eingegeben, dann fragt das Programm ahnlich wie zuvor die Parameter derentsprechenden Zeile oder Spalte einzeln ab. Wiederum wird nach der Eingabe des letz-ten Parameters die komplette Determinante mit der Losung und dem nachfolgendenMenu ausgegeben. Der Bildschirm konnte dann beispielsweise so aussehen:

3

Bitte Zeilennummer eingeben: 2

a21= 1

a22= 2

a23= 3

| 0 0 0|

| 1 2 3| = 0

| 0 0 0|

1: Kompletteingabe zeilenweise

2: Kompletteingabe spaltenweise

3: Eine Zeile eingeben

4: Eine Spalte eingeben

5: Determinante berechnen

6: Beenden

Durch Eingabe einer 5 wird die Determinante erneut berechnet und wie oben beschriebenangezeigt. Wieder wird anschließend das Menu ausgegeben. Die Eingabe einer 6 beendetdas Programm.

47

Page 48: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

14.5 Aufgabe 4.5: Programm LIN

Schreiben Sie ein Programm, das die Losung eines Lineargleichungssystems berech-nen kann. Verwenden Sie dazu das Gauß-Jordan-Verfahren. Hierzu sind zunachsteinige Hintergrundinformationen notwendig.

14.5.1 Das Prinzip des Gauß-Jordan-Verfahrens

Carl Friedrich Gauss hat das Additions-/Subtraktionsverfahren8 systematisiert und wei-terentwickelt. Das von ihm vorgestellte und nach ihm benannte Gaußsche Eliminations-verfahren eignet sich dadurch besonders gut zum schematischen Losen, wie es Rechnerdurchfuhren konnen. Spater wurde das Verahren durch Wilhelm Jordan noch etwas ver-feinert. Auch diese Verbesserung mochte ich mit vorstellen.

Wir gehen von einem Lineargleichungssystem n-ter Ordnung aus, das in Normalformangegeben ist. Das bedeutet, wir haben n Gleichungen und ebensoviele Variablen. DieVariablen sollen x1, x2, . . . , xn heißen. Damit sieht das Gleichungssystem folgendermaßenaus:

a11x1 +a12x2 + . . . +a1nxn = b1a21x1 +a22x2 + . . . +a1nxn = b2

......

... =...

an1x1 +an2x2 + . . . +annxn = bn

Hierbei kommen Doppelindizes vor, beispielsweise a219. Dabei bedeutet die erste Zahl

die Zeile, in der der Koeffizient steht und der zweite die Spalte. Der Koeffizient a21steht also in der zweiten Zeile in der ersten Spalte, der Koeffizient a1n in der 1. Zeile inder n-ten Spalte.

Wir schaun uns dazu ein Beispiel an. Gegeben sei dieses Gleichungssystem:

(1) 3x −2y +2z = 10(2) 4x +2y −3z = 1(3) 2x −3y +2z = 7

In diesem Beispiel ware x = x1, y = x2 und z = x3. Entsprechend ist a11 = 3, a12 = −2,a13 = 2, b1 = 10, usw.

Zur Vereinfachung der Schreibarbeit schreibt man das Gleichungssystem in Form einerMatrix auf. Das sieht dann so aus:

a11 a12 . . . a1n b1a21 a22 . . . a1n b2...

......

...an1 an2 . . . ann bn

8Einzelheiten siehe auch hier: http://members.dokom.net/w.kippels/aufgaben/add.pdf9Gesprochen wird das als

”a Zwei Eins“, nicht als

”a Einundzwanzig“.

48

Page 49: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Es werden also nur die Koeffizienten (einschließlich Vorzeichen) aufgeschrieben, nichtaber die Variablen und die Gleichheitszeichen.

Fur unser Beispiel sieht die Matrix damit folgendermaßen aus: 3 −2 2 104 2 −3 12 −3 2 7

Das Ziel beim Gauß-Jordan-Verfahren besteht darin, die Matrix in folgende Form zubringen.

1 0 . . . 0 k10 1 . . . 0 k2...

.... . .

......

0 0 . . . 1 kn

Wenn es gelingt, die Matrix so umzuformen, dass vorn in der Matrix nur Nullen mitEinsen in der Diagonalen stehen, dann stellen die Parameter k1 . . . kn die Losungen furx1 . . . xn dar, denn dazu wurde das Gleichungssystem in dieser Form passen:

1 · x1 +0 · x2 . . . +0 · xn = k10 · x1 +1 · x2 . . . +0 · xn = k2

......

. . .... =

...0 · x1 +0 · x2 . . . +1 · xn = kn

Noch deutlicher wird das, wenn das Gleichungssystem zusammengefasst wird:

x1 +0 . . . +0 = k10 +x2 . . . +0 = k2...

.... . .

... =...

0 +0 . . . +xn = kn

Das Ziel ist also klar, aber wie kommen wir dahin?

Zunachst muss oben links in der Matrix eine 1 stehen. Dazu dividiert man die erste Zeiledurch a11. Dem entspricht eine Division der ersten Gleichung durch a11.

Es kann nun sein, dass a11 = 0 ist. In diesem Fall musste man durch Null dividieren, wasja bekanntermaßen nicht geht. Dann ist es aber moglich, die erste Zeile (Gleichung) miteiner anderen Zeile (Gleichung) zu tauschen, bei der der erste Parameter ungleich Nullist. Mindestens einer muss ungleich Null sein, anderenfalls ist das Gleichungssystemunterbestimmt.

49

Page 50: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Wir fuhren das nun an unserem Beispiel durch. 3 −2 2 104 2 −3 12 −3 2 7

Da a11 = 3 ist, muss die erste Zeile durch 3 dividiert werden. 1 −2

323

103

4 2 −3 12 −3 2 7

Als nachstes mussen unter der 1 in der ersten Spalte Nullen erzeugt werden. Das ge-schieht dadurch, dass zu jeder der nachfolgenden Zeilen (Gleichungen) ein passendesVielfaches der ersten Zeile (Gleichung) addiert wird, so dass jeweils vorn die Null ent-steht. Was heißt das konkret?

Die zweite Zeile muss dazu mit dem −a21-fachen der ersten Zeile multipliziert werden,die dritte mit dem −a31-fachen, usw. Das fuhren wir nun an dem Beispiel durch.

Die zweite Zeile entsteht, indem die erste mit −4 multipliziert und elementweise zurzweiten hinzuaddiert wird. 1 −2

323

103

0 143−17

3−37

3

2 −3 2 7

Die dritte Zeile entsteht, indem die erste mit −2 multipliziert und elementweise zurdritten hinzuaddiert wird. 1 −2

323

103

0 143−17

3−37

3

0 −53

23

13

Damit ist der erste Schritt abgeschlossen. Man betrachtet nun die

”Restmatrix“, die sich

ergibt, wenn man die erste Zeile und die erste Spalte in Gedanken herausstreicht. Daserste Element dieser

”Restmatrix“ ist nun a22. Um dieses zu 1 zu machen und darunter

Nullen geht man genau so vor, wie bei der ersten Zeile beschrieben. Fur die dritte undggf. alle weiteren Zeilen geht man ebenso vor.

Wir wenden das jetzt wieder auf unser Beispiel an. Die zweite Zeile muss durch 143

divi-diert werden. Da man bekanntlich durch einen Bruch dividiert, indem man mit seinemKehrwert multipliziert, konnen wir die zweite Zeile auch mit 3

14multiplizieren. Die Null

in der ersten Spalte wird dadurch nicht beeinflusst. 1 −23

23

103

0 1 −1714−37

14

0 −53

23

13

50

Page 51: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Nun muss a32 = 0 gemacht werden. Dazu wird das 53-fache der zweiten Zeile zur dritten

hinzuaddiert. 1 −23

23

103

0 1 −1714−37

14

0 0 −5742−171

42

Zum Schluss wird noch die letzte Zeile durch −57

42geteilt, damit die letzte fehlende 1 in

die Diagonale kommt. 1 −23

23

103

0 1 −1714−37

14

0 0 1 3

Im Prinzip konnte man hier schon aufhoren, denn aus der dritten Zeile geht sofort derWert fur x3 = z hervor. In eine Gleichung

”ubersetzt“ steht da namlich 1 · x3 = 3. Das

Ergebnis konnte man in die vorletzte Zeile (Gleichung) einsetzen, um damit sofort dievorletzte Variable zu berechnen, usw. An dieser Stelle hat Wilhelm Jordan angesetztund das Verfahren erganzt. Man erhalt damit die Nullen oberhalb der aus Einsen beste-henden Diagonale, wie oben beschrieben.

Das Verfahren zur Erzeugung dieser Nullen lauft ahnlich dem Verfahren ab, das wir bishierher benutzt haben; man fangt nur nicht oben links, sondern unten rechts an. Genau-er: zur ersten Zeile wird das −a1n-fache der letzten (n-ten) Zeile hinzuaddiert. Dadurchentsteht senkrecht uber der untersten 1 in der ersten Zeile eine 0. Alle Elemente davorbleiben erhalten. Das fuhrt man Zeile fur Zeile bis zur (n−1)-ten (vorletzten) Zeile durch.

Anschließend denkt man sich die letzte Zeile weg und macht entsprechendes mit dendavor liegenden Zeilen, bis uberall die gewunschten Nulle stehen. Wir sehen uns das anunserem Beispiel an. 1 −2

323

103

0 1 −1714−37

14

0 0 1 3

Die letzte Zeile muss mit −2

3multipliziert und zur ersten Zeile addiert werden. Wir

erhalten diese Matrix: 1 −23

0 163

0 1 −1714−37

14

0 0 1 3

Jetzt muss das 17

14-fache der letzten Zeile zur zweiten addiert werden. 1 −2

30 16

3

0 1 0 10 0 1 3

Damit ist die hintere

”Nullenspalte“ fertig. Nebenbei bemerkt kann man jetzt auch schon

ablesen, dass x2 = y = 1 ist.

51

Page 52: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Nun kommt die zweite Spalte dran. Uber der mittleren 1 muss eine Null entstehen.Dazu wird zur ersten Zeile das 2

3-fache der zweiten Zeile addiert. Wir erhalten dann

dieses Ergebnis: 1 0 0 60 1 0 10 0 1 3

Damit haben wir es geschafft. Die Ergebnisse fur die gesuchten Variablen stehen in derletzten Spalte: x = 6, y = 1 und z = 3, oder als Losungsmenge: L = {(6|1|3)}

14.5.2 Das Gauß-Jordan-Verfahren in der Anwendung

Wir haben gesehen, dass das Verfahren sehr systematisch ablauft. Weiterhin haben wirgesehen, dass zwischendurch ungunstig handhabbare Zahlenwerte entstehen, auch wennes ganzzahlige Ergebnisse gibt. Aus diesen beiden Grunden eignet sich das Verfahrenweniger fur die Ausrechnung

”zu Fuß“, sondern eher, um damit ein Rechnenprogramm

fur den Computer zu schreiben. Dies soll hier ja auch gemacht werden.

Wir gehen davon aus, dass folgende Variablen als Integer-Variablen definiert sind:

n: Die Anzahl der Variablen und Gleichungen

k: Hilfsvariable fur Teilmatritzen

i: Hilfsvariable fur Zeilennummern

j: Hilfsvariable fur Spaltennummern

Weiterhin sei a als ein zweidimensionales Feld mit der Große n×n+1 (n Zeilen, n+1Spalten) bestehend aus Fließkommavariablen in dieser Form definiert:

a =

a11 a12 . . . a1n b1a21 a22 . . . a1n b2...

......

...an1 an2 . . . ann bn

Auch die b-Werte (die Werte auf der rechten Seite in den zugrunde liegenden Glei-chungen) werden damit als a-Werte – namlich als ai,n+1 – angesprochen. In einem Glei-chungssystem 3. Grades (n=3) beispielsweise ware dann b1=a14, b2=a24 und b3=a34.Das erleichtert die Berechnungen, die ja immer in einer kompletten Zeile stattfinden.

52

Page 53: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Die eigentliche Programmieranleitung Die Beschreibung des Algorithmus beginnt,nachdem alle Werte in die Matrix eingetragen sind und auch n die Zahl der Variablenenthalt. Der Algorithmus besteht in zwei aufeinanderfolgenden Teilen. Im ersten wirddie Diagonale mit Einsen und das Dreieck unten links mit Nullen gefullt, im zweiten Teilkommen die Nullen oben rechts dazu.

Schritt 1: Einserdiagonale und Nullen unten links.

• Fuhre nachfolgende Befehle fur k = 1 bis k = n aus:

– Ist akk = 0? Wenn ja, fuhre nachfolgende Befehle aus.

∗ Setze i=k+1

∗ Ist i > n? Wenn ja, brich ab mit der Fehlermeldung:”Das Gleichungssys-

tem ist unterbestimmt!“

∗ Ist aik = 0? Wenn ja, erhohe i um eins und prufe erneut. Wenn da-bei i > n wird, brich mit der oben genannten Fehlermeldung ab. DieseErhohungen werden so lange fortgesetzt, bis entweder aik 6= 0 ist, odermit der Fehlermeldung abgebrochen wurde.

∗ Tausche die Werte aus Zeile i mit den Werten aus Zeile k.

– Berechne von j = n + 1 ruckwarts bis j=k: akj =akj

akk

– Falls k < n ist, fuhre nachfolgenden Befehl fur i = k + 1 bis i = n aus.

∗ Berechne fur j = n + 1 ruckwarts bis j = k: aij = aij − akj · aik

Wenn wir hier angekommen sind, ist der erste Teil abgeschlossen; die Einserdiagonalemit den Nullen darunter ist erzeugt.

Schritt 2: Die Nullen oben rechts.

• Fuhre folgende Schritte fur k = n ruckwarts bis k = 2 durch.

– Fuhre folgende Schritte fur i = 1 bis i = k− 1 durch.

∗ Berechne fur j = n + 1 ruckwarts bis j = k: aij = aij − akj · aik

Danach stehen alle Losungen in der letzten Spalte der Matrix. Diese Werte mussen dannnur noch nacheinander ausgegeben werden.

53

Page 54: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

14.5.3 Umsetzung in C:

Beim Programmstart fragt das Programm zunachst nach dem Grad des Linearglei-chungssystems. Damit ist die Zahl der Variablen (und der Gleichungen) gemeint. DasProgramm soll einen Grad zwischen 2 und 20 zulassen.

Danach mussen die Parameter der Gleichungen eingegeben werden. Dazu ein Tipp: Inder Aufgabe 4.4 haben Sie solche Eingaberoutinen bereits erstellt, sie mussen nur nochleicht angepasst werden.

Die Ergebnisausgabe erfolgt zeilenweise, wobei der Variablenname jeweils mit einemGleichheitszeichen vor der Losung steht. Das sieht dann etwa so aus:

x1=6

x2=1

x3=3

Bei der Umsetzung in die Srache C sollte man beachten, dass die Nummerierung bei Fel-dern immer mit einer 0 beginnt. Die oben dargestellte allgemeine Beschreibung benenntdas erste Element dagegen mit einer 1. Die Nummerierung muss also angepasst werden.

54

Page 55: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

15 Rekursive Funktionen

Manchmal kann es sinnvoll sein, dass eine bestimmte Funktion sich selbst aufruft. Dannspricht man von einer Rekursion oder einem rekursiven Aufruf der Funktion. Damitdas funktioniert, mussen zwei Bedingungen erfullt sein:

1. In der Funktion muss sicher gestellt sein, dass die Funktion sich nicht unbeschranktimmer weiter selbst aufruft.

2. Es durfen innerhalb der Funktion nur lokale Variablen verwendet werden.

Ein Beispiel soll verdeutlichen, wie das ganze funktioniert und was das uberhaupt soll.

/* Berechnung der Summe aller Zahlen von 1 bis n */

#include <stdio.h>

int summe(int n) /* Rekursive Funktion */

{

int z=1; /* lokale Hilfsvariable */

if (n>1)

z=n+summe(n-1); /* Rekursiver Aufruf */

return z;

}

int main(void)

{

int n,k;

printf("Geben Sie eine naturliche Zahl n ein: ");

scanf("%d",&n);

k=summe(n);

printf("Die Summe aller Zahlen von 1 bis %d ist %d\n",n,k);

return 0;

}

Die Funktion summe() ist die rekursive Funktion. Sie wird einmal im Hauptprogrammaufgerufen. Sie soll die Summe aller Zahlen von 1 bis zu einer einzugebenden Zahl n be-rechnen. Das Problem hatten wir zwar schon einmal am Anfang unseres Kurses andersgelost, hier soll es aber ubungshalber rekursiv gemacht werden.

Schaut man sich die Funktion summe() genau an, dann wird man feststellen, dass sie sichin ihrer 3. Zeile selbst aufruft. An dieser Stelle wird vorausgesetzt, dass summe(n-1) dieSumme aller Zahlen von 1 bis (n-1) berechnet. Es muss dann nur noch n hinzuaddiertwerden und fertig ist die Summe aller Zahlen. Dieser Wert wird als Funktionsruckgabe-wert an die aufrufende Routine zuruckgeliefert. Durch die Rekursion wird die Funktionalso recht einfach.

55

Page 56: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Wir wollen uns an diesem Beispiel ansehen, wodurch und warum die angegebenen Be-dingungen erfult sind.

1. In der Funktion muss sicher gestellt sein, dass die Funktion sich nicht unbeschranktimmer weiter selbst aufruft.Irgendwann ist das Funktionsargument (n-1) nicht mehr großer als 1. Die if-Bedingung in der zweiten Zeile des Funktionskorpers ist dann nicht mehr erfulltund die Funktion ruft sich nicht mehr selbst auf. Sie liefert dann eine 1 zuruck,denn die Summe aller Zahlen von 1 bis 1 ist 1. Aufgerufen wurde sie aus derFunktionsebene, in der n = 2 war. Dort wird dann 2 hinzugezahlt und das Ergebnisan die nachste Ebene zuruckgeliefert und so weiter.

2. Es durfen innerhalb der Funktion nur lokale Variablen verwendet werden.Lokale Variable werden auf dem Stapel (Stack) angelegt. Ruft sich die Funktionselbst erneut auf, dann wird wieder ein neuer Bereich auf dem Stapel fur die neuenVariablen angelegt. Dadurch wird ausgeschlossen, dass beim rekursiven Aufruf dieFunktion Werte verandert, die sie vielleicht hinterher noch benotigt. In diesemBeispiel wird zwar kein Wert von z, der vor dem rekursiven Aufruf vorhandenwar, hinterher noch benotigt, aber das ist nicht in jeder rekursiven Funktion so.Daher wird in allgemeinen eine rekursive Funktion nicht ordnungsgemaßfunktionieren, wenn darin globale Variablen verwendet werden!

56

Page 57: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

16 Zeiger/Pointer

Wie wir schon in vorangehenden Kapiteln gesehen haben, spielen Zeiger in der C-Pro-grammierung eine wichtige Rolle. Was ist uberhaupt ein Zeiger?

Zeiger sind Variablen, in denen die Speicheradressen anderer Variablen ge-speichert werden konnen.

16.1 Einfache Zeiger

Den Speicher eines Rechners kann man sich vorstellen als ein langes Band von Speicher-stellen, die von Anfang bis Ende bei 0 beginnend durchnummeriert sind, ahnlich wie dieHausnummern der Hauser an einer langen Straße. Diese Nummern bezeichnet man alsdie Adresse einer Speicherstelle. Jedes Byte im Arbeitsspeicher eines Rechners hat alsoeine eindeutige Addresse. Fasst man mehrere Bytes zu einer großeren Einheit zusammen,etwa zu einer int-Variablen, einer float-Variablen oder zu einem Array, dann ist dieAddresse dieser Struktur die Adresse des ersten Bytes dieser Struktur.

Unter C gibt es den Operator &, der verwendet wird, wenn man die Addresse einerVariablen angibt. Ein Beispiel:

x = y;

Nach x wird der Inhalt von y geladen. Davon ist zu unterscheiden:

x = &y;

Nach x wird die Adresse von y geladen.

Das ganze funktioniert naturlich nur dann, wenn der Typ von x eine Adresse aufnehmenkann. Im Protected Mode, der in allen modernen Betriebssystemen wie Linux, Unix, OS/2oder Windows verwendet wird, benotigt die Adresse 4 Byte. Dem entspricht der dortdefinierte Typ int. Genaugenommen musste es heißen

”unsigned int“, da die Adres-

sen nur positiv sind, aber mit einfach”int“ geht es auch. Bei alteren Betriebssystemen,

die im Real Mode laufen, wie DOS oder der DOS-Modus unter Windows, besteht dieAdresse aus einem Segment-Anteil und einem Offset-Anteil. Hier wird nur der Offsetan-teil als Zeiger aufgefasst, das Segmentregiser DS dient dann als Basis. Da der Offset nur2 Byte belegt, passt er auch in die hier als Standardgroße definierte int-Variable mit2 Byte Lange. Sinnvoller ist es aber, direkt eine Zeiger-Variable anzulegen, wie weiterunten beschrieben wird.

Adressen von Variablen sind aber noch keine Zeiger. Wenn unter ASSEMBLER mit demBefehl mov [Variable],Wert einer Variablen ein Wert zugewiesen wird, dann steht imOpcode immer die Speicheradresse der Variablen. Das ist also normal. Wenn wir aber

57

Page 58: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

mit dem Befehl mov [ESI],Wert eine Zuweisung machen, dann arbeiten wir mit einemZeiger. Die Zieladresse steht dann namlich im Register ESI. Da dieser Registerinhaltjederzeit wahrend des Programmlaufes verandert werden kann, kann man also mit demgleichen Befehl – beispielsweise in einer Schleife – verschiedene Speicherstellen anspre-chen. Genauso ist es auch unter C.

Betrachten wir dazu folgende Sequenz:

int k=25;

int *z;

z = &k;

Der erste Befehl ist bekannt, es wird eine Integer-Variable mit dem Namen k definiert undmit der Zahl 25 initialisiert. Mit dem zweiten Befehl wird eine Zeigervariable definiert,die auf Integer-Variablen zeigen soll. Das Zeichen * macht z zum Zeiger, der Typ int

steht davor. Zu diesem Zeitpunkt zeigt der Zeiger irgendwo hin, genaues weiß man nicht.Mit dem dritten Befehl wird nun die Adresse von k nach z geladen. Der Zeiger ist nunsozusagen auf k eingestellt. Erst jetzt kann und darf man die Zeigervariable sinnvollnutzen. Wir haben jetzt die Moglichkeit, auf zwei verschiedene Arten auf die Variable k

zuzugreifen, beispielsweise so:

printf("Der Inhalt von k ist: %d\n",k);

printf("Der Inhalt von k ist: %d\n",*z);

Das *z in der letzten Zeile bewirkt folgendes: Das Programm schaut in der Variablen z

nach und findet dort einen Wert vor. Diesen Wert interpretiert es als Adresse. Anschlie-ßend schaut es an dieser Adresse im Speicher nach und holt von dort den eigentlichengesuchten Wert.

Jetzt kann man fragen:”Was soll denn der ganze Aufwand, wenn man auch direkt in der

Variablen nachsehen kann?“ Zugegeben, in diesem Beispiel ist das ziemlich unsinnig. Esgibt aber durchaus mehrere Grunde, wo das Arbeiten mit Zeigern sinnvoll oder sogarunumganglich ist.

• Wenn wir innerhalb einer Schleife nach und nach verschiedene Variablen mit demgleichen Befehl ansprechen wollen, geht es nicht ohne Zeiger.

• Es ist manchmal notwendig und auch moglich, wahrend des Programmlaufes mehrSpeicherplatz anzufordern. (Wie das geht, folgt spater.) Da die Adressen fur diesenBereich beim Programmstart noch nicht bekannt sind, ist es hier einzig mit Zeigernmoglich, diesen Bereich zu nutzen.

Der Umgang mit Zeigern erfordert besondere Aufmerksamkeit. Schnell ist einmal einStern vergessen oder einer zuviel gesetzt. Dann erfolgen vollkommen unkontrollierteSchreib- oder Lesezugriffe irgendwo im Speicher. Wenn man Gluck hat, bricht das Pro-gramm mit einem

”Speicherzugriffsfehler“ ab und man hat eine Chance, den Fehler zu

finden. Problematischer sind eher noch die Falle, wo man unvorhersehbare und zum Teilauch nicht reproduzierbare Ergebnisse bekommt. Betrachten wir dazu folgende Sequenz:

58

Page 59: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

int k=100;

int *z;

*z=k;

Was passiert?Zunachst wird die Integer-Variable k definiert und mit 100 initialisiert. Dann wird dieVariable z als Zeigervariable fur Integer-Variable definiert. So weit, so gut. Dann wirdder Inhalt der Variablen k – also die 100 – an die Stelle geschrieben, wo z hinzeigt. Da z

aber noch mit keinem Wert initialisiert worden ist, ist die Adresse dieses Schreibzugriffsnur vom Zufall bestimmt, es wird irgendwo hin geschrieben. Das fuhrt zu einer wichtigenProgrammierregel:Jedem Zeiger ist die Adresse eines definierten Speicherbereiches zuzuweisen,bevor der Verweisungsoperator auf diesen Zeiger angewendet werden kann!

Ein Beispiel soll die Verwendung von Zeigern verdeutlichen.

Das Beispiel-Programm soll im wesentlichen einen String mit dem Namen string1 ineinen anderen mit dem Namen string2 kopieren. Auch wenn es unter PASCAL einenvergleichbaren Befehl gibt, geht es hier nicht mit dem Befehl:

string2=string1;

Probieren Sie es ruhig aus, der Compiler wird meckern. Warum? Unter C sind StringsZeigergroßen, sie zeigen auf den Anfang des Vektors, an dem die Zeichenkette beginnt.Ihr eigentlicher Inhalt ist diese feste String-Adresse. Der Befehl wurde also von C wiefolgt gedeutet: Hole die Adresse von string1 und schreibe sie als Adresse von string2.Da string2 aber eine feste Adresse hat, kann der Compiler das nicht ubersetzen. DieFolge ware ja, dass unter dem Namen string2 nun auch string1 anzusprechen ware.Der tatsachliche Inhalt von string2 ware nicht mehr ansprechbar. Zudem ware naturlichauch keine Kopie von string1 entstanden.

Naturlich besteht die Moglichkeit, die Zeichen uber eine Indizierung byteweise hinuberzu kopieren. Der zugehorige Befehl wurde etwa so lauten:

string2[i]=string1[i];

wobei i in einer Schleife bei Null beginnend bis zum Stringende durchlaufen musste.Wir wollen das Problem hier aber mit Zeigern losen. Das Programm konnte dann soaussehen:

59

Page 60: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

#include<stdio.h>

int main(void)

{

char string1[] = "Hallo!\n";

char string2[10];

char *zeiger1;

char *zeiger2;

zeiger1 = string1;

zeiger2 = string2;

while((*zeiger2 = *zeiger1))

{

zeiger1++;

zeiger2++;

}

printf(string2);

return 0;

}

Am Programmanfang sind die beiden Strings string1 und string2 deklariert, wobeistring1 zugleich mit einem Text initialisiert wird. Danach werden zwei Zeiger vom Typchar deklariert und anschließend sofort auf die beiden Strings eingestellt. Da die Stringsja auch Zeigergroßen sind, entfallt hier der vorangestellte Adress-Operator & wie etwa&string1.

Ziemlich trickreich ist die nachfolgende Programmzeile:

while((*zeiger2 = *zeiger1))

Wer bis hier halbwegs aufmerksam gelesen hat und mitdenkt, dem durfte auffallen, dassder Befehl while ja eigentlich eine logische Bedingung (also eine Bedingung, die entwe-der wahr oder falsch ist) in seinen Klammern erwartet. Dafur musste aber das doppel-te Gleichheitszeichen verwendet werden. Außerdem fallen moglicherweise die doppeltenKlammern auf. Was hat das zu bedeuten?

In der Tat steht in den inneren Klammern eine Zuweisung! Das Zeichen, auf daszeiger1 zeigt, wird dahin kopiert, wo zeiger2 hin zeigt. (Anmerkung: An dieser Stel-le wird wohl auch klar, warum der Typ von Zeigergroßen deklariert werden muss. DerCompiler weiß sonst nicht, wieviele Byte zu einem Zeichen gehoren, das er kopieren soll.)Die inneren Klammern bedeuten fur den Compiler nun sinngemaß folgendes: Nimm dasErgebnis der Zuweisung und betrachte es als logische Bedingung. Dabei bedeutet:

• Ergebnis = 0 ⇒ logisch falsch

• Ergebnis 6= 0 ⇒ logisch wahr

60

Page 61: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Wenn also ein ASCII-Zeichen kopiert wurde (Wert 6= 0), dann ist die Bedingung erfullt,die while-Schleife wird ausgefuhrt. Wurde die Stringendemarke kopiert (Wert = 0),dann ist sie nicht erfullt und die Schleife beendet sich.

Die doppelte Klammerung hinter while wegen der Zuweisung, die als Bedingung”miss-

braucht“ wird, ist nicht zwingend erforderlich. Der Compiler versteht das auch so. EinigeCompiler geben allerdings eine Warnmeldung aus. Die ist vermutlich aber mehr dazugedacht, den Programmierer an ein doppeltes Gleichheitszeichen zu erinnern, das ermoglicherweise in einer als Bedingung gemeinten Anweisung vergessen hat. Daher meinTipp: Verwenden Sie immer den Parameter −Wall, um alle Warnmeldungeneinzuschalten, wenn Sie den GCC-Compiler verwenden! So kann man durchausHinweise bekommen, warum ein Programm moglicherweise nicht das macht, was es soll.

Der Rest des Programmes ist vermutlich leicht verstandlich. Im Schleifenkorper werdenbeide Zeiger weitergestellt. So werden die Strings zeichenweise kopiert, einschließlich derStringendemarke. Zum Schluss gibt das Programm noch den kopierten String aus. Dasdient aber mehr der Dokumentation, dass es geklappt hat. Testen Sie es aus!

Es geht ubrigens auch noch trickreicher! Die while-Schleife kann reduziert werden auf:

while((*zeiger2++ = *zeiger1++));

Der Schleifenkorper hat sich auf ein einziges Semikolon reduziert, weil die Erhohungs-anweisungen ++ schon gleich in die Bedingung/Zuweisung integriert wurde.

61

Page 62: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

17 Ubungsaufgaben Teil 5

17.1 Aufgabe 5.1: Programm FAKULTAET

Erstellen Sie ein Programm mit dem Namen FAKULTAET mit folgenden Bedingungen:

Zunachst gibt das Programm die Anweisung aus:

Bitte eine naturliche Zahl eingeben:

Dann liest das Programm von der Tastatur die Zahl und berechnet die Fakultat dieserZahl. Die Fakultat einer Zahl n – geschrieben als n! – ist das Produkt aller naturlichenZahlen von 1 bis n, also:

n! = 1 · 2 · 3 · 4 · . . . · n

Nach der Berechnung gibt das Programm das Ergebnis aus. Wurde beispielsweise fur neine 5 eingegeben, dann erscheint folgende Ausgabe:

5! = 120

Danach beendet sich das Programm. Das Bildschirmbild sieht dann etwa so aus:

Bitte eine naturliche Zahl eingeben: 5

5! = 120

Die Berechnung soll mit einer rekursiven Funktion erfolgen. Da fur die Fakultat einerZahl sehr schnell sehr große Werte entstehen, verwenden Sie bitte Fließkommazahlen furdie entsprechenden Variablen.

62

Page 63: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

17.2 Aufgabe 5.2: Programm DETERMINANTE

Erstellen Sie ein Programm mit dem Namen DETERMINANTE mit folgenden Bedingungen:

Das Programm soll eine beliebige Determinante berechnen. Die Menustruktur entsprichtim wesentlichen dem Programm DET3, das wir als Aufgabe 4.4 erstellt haben. Dort wares ausschließlich eine dreireihige Determinante, wahrend wir hier n-reihige Deter-minanten berechnen wollen, wobei n eine (nahezu) beliebige naturliche Zahl ist. DieseDimension n der Determinante wollen wir aus verschiedenen Grunden allerdings in un-serem Programm auf einen Maximalwert von 9 beschranken.

Nach dem Aufruf fragt unser Programm die Dimension n der Determinante ab. FalscheWerte, also Werte uber 9 oder unter 2 werden mit einer entsprechenden Fehlermeldungabgewiesen. Eine neue Aufforderung zur Eingabe erfolgt, bis ein gultiger Wert eingege-ben ist. Danach erscheint das Menu, das bereits in Aufgabe 4.4 beschrieben wurde. Alledazugehorigen Routinen konnen nach kleiner Anpassung auf die variable Dimension derDeterminante von dort ubernommen werden.

Neu ist die Berechnung der Determinante. Bekanntlich funktioniert der Satz von Sarrus,der im Programm DET3 verwendet wird, nur fur dreireihige Determinanten. Hier istdie Dimension moglicherweise großer als 3. Hier hilft nur der Entwicklungssatz weiter.Bekanntlich ist die n-reihige Determinante wir folgt rekursiv definiert. Fur n = 2 gilt:

a11 a12a21 a22

= a11 · a22 − a21 · a12

Ist n großer als 2, dann kann die Determinante beispielsweise nach der ersten Spalteentwickelt werden:

a11 a12 a13 . . . a1na21 a22 a23 . . . a2na31 a32 a33 . . . a3n...

......

. . ....

an1 an2 an3 . . . ann

= +a11 ·

a22 a23 . . . a2na32 a33 . . . a3n...

.... . .

...an2 an3 . . . ann

. . .

. . .− a21 ·

a12 a13 . . . a1na32 a33 . . . a3n...

.... . .

...an2 an3 . . . ann

+ . . .± an1 ·

a12 a13 . . . a1na22 a23 . . . a2n...

.... . .

...a(n−1)2 a(n−1)3 . . . a(n−1)n

Etwas anschaulicher kann man dieses”Entwickeln“ vielleicht mit Worten beschreiben.

Alle Elemente a11 bis an1 bekommen abwechselnd ein Plus- oder ein Minuszeichen zuge-ordnet, wobei bei a11 mit einem Pluszeichen begonnen wird. Außerdem wird jedes dieserElemente aus der ersten Spalte mit einer Unterdeterminante multipliziert. Diese Un-terdeterminante entsteht, indem man die Zeile und die Spalte aus der ursprunglichen

63

Page 64: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Determinanten ausloscht, in der das jeweilige Element steht. Aus einer n-reihigen Deter-minanten werden so n (n − 1)-reihige Determinanten. Jede dieser Unterdeterminantenkann rekursiv nach dem gleichen Verfahren bestimmt werden. Irgendwann stoßt mandann auf 2-reihige Determinanten, die man dann mit der Formel aus dem ersten Teilder Definition berechnet.

Da schon die Definition rekursiv ist, bietet es sich naturlich an, auch die Berechnungmit einer rekursiven Funktion durchzufuhren. Hierbei sind ein paar Dinge zu beachten.

• Beim Aufruf der Funktion muss der Funktion die Dimension der zu berechnendenDeterminanten sowie ein Zeiger auf die zu berechnende Determinante ubergebenwerden.

• Die Funktion selbst darf aus der ubergebenen Determinante nur Lesen. Schreib-zugriffe verbieten sich, dann ware keine Rekursion mehr moglich. Wenn also eineUnterdeterminante gebildet und zur Berechnung rekursiv an sich selbst ubergebenwerden soll, muss also diese neue Determinante als lokale Variable angelegt undmit den Daten der jeweils zu berechnenden Unterdeterminante gefullt werden. Da-mit diese angelegte Hilfsdeterminante groß genug ist, muss fur sie mindestens dieDimension (n − 1) vorgesehen werden. Wenn sie großer ist, ist das kein Problem,nur zu klein darf sie nicht sein. Allerdings ist zu beachten, dass der Zeigertypder gleiche bleibt, wie beim ersten Aufruf der Funktion von

”außen“, also mit der

ubergebenen Original-Determinanten. Konkret heißt das, dass die Spaltenzahlfur das Array der lokalen Hilfsdeterminanten die gleiche sein muss, wie die derHauptdeterminanten.

• Die Summanden werden abwechselnd mit einem positiven und einem negativenVorzeichen versehen. Ist die Zeilennummer ungerade, ist das Vorzeichen positiv,ist die Zeilennummer gerade, ist das Vorzeichen negativ. Daraus konnen Sie eineRoutine zur Berechnung des Vorzeichens machen, indem Sie die Zeilennummerdurch 2 teilen und den Divisionsrest auswerten. Diese Modulofunktion wird mitdem Operator % gebildet.

• Bekommt die rekursive Funktion eine Determinante mit der Dimension 2 zur Be-rechnung ubergeben, dann berechnet sie diese nach der Formel aus der Definitionfur zweireihige Determinanten. Dadurch wird die Rekursion endlich.

Nachdem die Determinante rekursiv berechnet wurde, muss das Ergebnis ausgegebenwerden. Zuvor wird noch die zu berechnende Determinante ausgegeben. Da diese beigroßem n recht groß sein kann, ist es zweckmaßig, das Ergebnis in einer neuen Zeileunter der Determinanten auszugeben.

64

Page 65: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

18 Tabellen

18.1 Steuerzeichen

Einige Steuerzeichen und ihre Bedeutung:

Steuerzeichen Bedeutung ASCII-Wert

\a Piepton 7\b Backspace = ein Zeichen zuruck 8\t Tabulator 9\n Zeilenvorschub 10\f Seitenvorschub 12\r Rucksprung zum Zeilenanfang 13\\ Ausgabe des Zeichens \ 92\" Ausgabe des Zeichens " 34\0 Null-Zeichen 0

18.2 Datentypen

Speicherlangen und Wertebereiche der Datentypen unter C:

Datentyp Speicherlange Wertebereich

char 1 Byte −128 - +127unsigned char 0 - 255short 2 Byte −32768 - +32767unsigned short 0 - 65535int 2 oder 4 Byte wie bei shortunsigned int bzw. longlong 4 Byte −214783648 - +214783647unsigned long 0 - +4294967295

float 4 Byte 3, 4 · 10−38 - 3, 4 · 1038

8 Bit Exponent23 Bit Mantisse

double 8 Byte 1, 7 · 10−308 - 1, 7 · 10308

11 Bit Exponent52 Bit Mantisse

long double 10 Byte 3, 4 · 10−4932 - 3, 4 · 104932

16 Bit Exponent63 Bit Mantisse

65

Page 66: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

18.3 Formatbeschreiber

Einige Formatbeschreiber und ihre Bedeutung, die bei den Funktionen printf und scanfVerwendung finden:

Beschreiber Bedeutung

%d Dezimale Ganzzahl Typ int

%o Oktale Ganzzahl%x Hexadezimale Ganzzahl%u Ganzzahl ohne Vorzeichen%f Gleitpunkt-Darstellung einer Gleitkommazahl Typ float

%e Exponential-Darstellung einer Gleitkommazahl Typ float

%g kurzeste Darstellung einer Gleitkommazahl Typ float

%c ein ASCII-Zeichen%s eine Zeichenkette%p Addresse einer Variablen

Zusatzlich kann zwischen dem % und dem Kennbuchstaben noch (in dieser Reihenfolge)angegeben werden:

• Ein Minuszeichen, damit das Argument linksbundig ausgegeben wird.

• Eine Zahl, die die minimale Feldbreite angibt, also wieviele Ziffern fur die Zahlmindestens reserviert werden sollen. Werden mehr benotigt, werden auch mehrverwendet. Beispiel %6d fur Ganzzahl Typ int

• Ein Punkt, der die Feldbreite von der Genauigkeit trennt.

• Eine Zahl, die angibt, wieviele Nachkommastellen eine Fließkommazahl haben soll.Beispiel %5Lg fur Gleitkommazahl Typ double

• Eine Zahl, die angibt, wieviele Zeichen von einer Zeichenkette ausgegeben werdensollen. Beispiel %25s

• Der Buchstabe h oder H, wenn das Argument vom Typ short ist. Beispiel %hd furGanzzahl Typ char

• Der Buchstabe l oder L, wenn das Argument vom Typ long ist. Beispiel %lg furGleitkommazahl Typ double

66

Page 67: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

18.4 Operatoren

Liste Der Operatoren unter C

Name Operator Erklarung

Inkrement, nach Zugriff x++ Erhoht x um 1Dekrement, nach Zugriff x-- Verringert x um 1Inkrement, vor Zugriff ++x Erhoht x um 1Dekrement, vor Zugriff --x Verringert x um 1Vorzeichenumkehr -x

Speicheradresse von x &x

Bitweises Komplement ~x z.B. 0x01101 → 0x10010Logische Negation !x Negation einer AussageWert der Speicherstelle mit Adresse x *x

Division x / y

Modulo x % y DivisionsrestMultiplikation x * y

Addition x + y

Subtraktion x - y

Bitweises Links-Shiften um y Stellen x << y z.B. 0x001101 << 2 → 0x110100Bitweises Rechts-Shiften um y Stellen x >> y z.B. 0x001101 >> 2 → 0x000011Bitweise UND-Verknupfung x & y z.B. 0x0101 & 0x1100 → 0x0100Bitweise Exclusiv-Oder x ^ y z.B. 0x0101 ^ 0x1100 → 0x1001Bitweise Oder-Verknupfung x | y z.B. 0x0101 | 0x1100 → 0x1001Logische UND-Verknupfung x && y AussagenverknupfungLogische ODER-Verknupfung x || y Aussagenverknupfung

18.5 Vergleichsoperatoren

Liste der Vergleichsoperatoren

Operator Bedeutung

== gleich!= ungleich< kleiner> großer<= kleiner oder gleich>= großer oder gleich

67

Page 68: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

19 Losungsbeispiele Teil 1

Die dargestellten Losungen sind nur Beispiele, es gibt naturlich auch noch viele andereLosungsmoglichkeiten.

19.1 Aufgabe 1: Programm SUMME2

/* Programm SUMME2 */

#include <stdio.h>

int main(void)

{

int i, j;

i=0;

j=1;

while (j<=15)

{

printf("%d",i);

i = i+j;

printf(" + %d = %d\n",j,i);

j = j+1;

}

printf("\nSumme von 1 bis 15 = %d\n", i);

return 0;

}

19.2 Aufgabe 1.1: Programm TASTE1

/* Ubungsprogramm TASTE1 */

#include <stdio.h>

int main(void)

{

int z;

printf("Bitte eine Taste drucken!\n");

z=getchar();

printf("Taste: %c Zeichencode: %x\n", z, z);

return 0;

}

68

Page 69: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

19.3 Aufgabe 1.2: Programm TASTE2

/* Ubungsprogramm TASTE2 */

#include <stdio.h>

int main(void)

{

int z, i, dummy;

printf("Bitte eine Taste drucken!\n");

for (i=0; i<10; i++)

{

z=getchar();

dummy=getchar(); /* Enter-Betatigung abfangen */

printf("Taste: %c Zeichencode: %x\n", z, z);

}

return 0;

}

19.4 Aufgabe 1.3: Programm TASTE3

/* Ubungsprogramm TASTE3 */

#include <stdio.h>

int main(void)

{

char z[10];

int i=0;

printf("Bitte eine Taste drucken, Ende mit q!\n");

while (z[0]!=’q’ && i<10)

{

scanf("%s",&*z);

printf("Taste: %c Zeichencode: %x\n", z[0], z[0]);

i++;

}

return 0;

}

69

Page 70: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

19.5 Aufgabe 1.4: Programm QUADRAT

/* Ubungsprogramm QUADRAT */

#include <stdio.h>

int main(void)

{

int x,q;

for (x=1; x<16; x++)

{

q=x*x;

printf("%d^2=%d\n", x, q);

}

return 0;

}

19.6 Aufgabe 1.5: Programm PRIMZAHL

/* Programm PRIMZAHL

Berechnung der ersten 15 Primzahlen */

#include <stdio.h>

int main(void)

{

int p=1; /* Das ist unsere potentielle Primzahl */

int n=0; /* Die Anzahl der bisher gefundenen Primzahlen */

int i; /* Die Testzahl */

while(n<15)

{

i=2; /* Startwert fur ersten Test */

if(i<=p){ while(p%i!=0){i++;} }

if(i>=p)

{

printf("%d\n",p);

n++;

}

p++;

}

return 0;

}

70

Page 71: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20 Losungsbeispiele Teil 2

Die dargestellten Losungen sind nur Beispiele, es gibt naturlich auch noch viele andereLosungsmoglichkeiten.

20.1 Aufgabe 2.1: Programm RECHNER1

#include <stdio.h>

int main (void)

{

int a, b; /* Die beiden Zahlen */

char z[5]; /* Platz fur einen kleinen String (Rechenzeichen) */

printf("Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:\n");

scanf("%d%s%d",&a, &*z, &b);

switch(z[0])

{

case ’+’: printf("%d + %d = %d\n",a, b, a+b); break;

case ’-’: printf("%d - %d = %d\n",a, b, a-b); break;

case ’*’: printf("%d * %d = %d\n",a, b, a*b); break;

case ’/’: printf("%d / %d = %d\n",a, b, a/b); break;

default : printf("Falsche Eingabe!\n ");

}

return 0;

}

71

Page 72: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20.2 Aufgabe 2.2: Programm RECHNER2

#include <stdio.h>

int main (void)

{

int a, b; /* Die beiden Zahlen */

char z[5]; /* Platz fur einen kleinen String (Rechenzeichen) */

printf("Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:\n");

scanf("%d%s%d",&a, &*z, &b);

switch(z[0])

{

case ’+’: printf("%d + %d = %d\n",a, b, a+b); break;

case ’-’: printf("%d - %d = %d\n",a, b, a-b); break;

case ’*’: printf("%d * %d = %d\n",a, b, a*b); break;

case ’:’: ;

case ’/’: printf("%d / %d = %d\n",a, b, a/b); break;

default : printf("Falsche Eingabe!\n ");

}

return 0;

}

72

Page 73: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20.3 Aufgabe 2.3: Programm RECHNER3

#include <stdio.h>

int main (void)

{

int a, b; /* Die beiden Zahlen */

char z[5]; /* Platz fur einen kleinen String (Rechenzeichen) */

do

{

printf("Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:\n");

scanf("%d%s%d",&a, &*z, &b);

switch(z[0])

{

case ’+’: printf("%d + %d = %d\n",a, b, a+b); break;

case ’-’: printf("%d - %d = %d\n",a, b, a-b); break;

case ’*’: printf("%d * %d = %d\n",a, b, a*b); break;

case ’:’: ;

case ’/’: printf("%d / %d = %d\n",a, b, a/b); break;

default : printf("Falsche Eingabe!\n ");

}

printf("Noch eine Rechnung? (j/n) ");

scanf("%s",&*z);

} while (z[0]!=’n’);

return 0;

}

73

Page 74: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20.4 Aufgabe 2.4: Programm RECHNER4

#include <stdio.h>

int main (void)

{

int a, b; /* Die beiden Zahlen */

char z[5]; /* Platz fur einen kleinen String (Rechenzeichen) */

do

{

printf("Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:\n");

scanf("%d%s%d",&a, &*z, &b);

switch(z[0])

{

case ’+’: printf("%d + %d = %d\n",a, b, a+b); break;

case ’-’: printf("%d - %d = %d\n",a, b, a-b); break;

case ’*’: printf("%d * %d = %d\n",a, b, a*b); break;

case ’:’: ;

case ’/’: printf("%d / %d = %d\n",a, b, a/b); break;

default : printf("Falsche Eingabe!\n ");

}

do

{

printf("Noch eine Rechnung? (j/n) ");

scanf("%s",&*z);

} while ((z[0]!=’n’) && (z[0]!=’N’) && (z[0]!=’j’) && (z[0]!=’J’));

} while (z[0]!=’n’ && z[0]!=’N’);

return 0;

}

74

Page 75: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20.5 Aufgabe 2.5: Programm RECHNER5

#include <stdio.h>

int main (void)

{

double a, b; /* Die beiden Zahlen */

char z[5]; /* Platz fur einen kleinen String (Rechenzeichen) */

do

{

printf("Bitte zwei Zahlen mit einem Rechenzeichen dazwischen eingeben:\n");

scanf("%lf%s%lf",&a, &*z, &b);

switch(z[0])

{

case ’+’: printf("%lg + %lg = %lg\n",a, b, a+b); break;

case ’-’: printf("%lg - %lg = %lg\n",a, b, a-b); break;

case ’*’: printf("%lg * %lg = %lg\n",a, b, a*b); break;

case ’:’: ;

case ’/’: printf("%lg / %lg = %lg\n",a, b, a/b); break;

default : printf("Falsche Eingabe!\n ");

}

do

{

printf("Noch eine Rechnung? (j/n) ");

scanf("%s",&*z);

} while ((z[0]!=’n’) && (z[0]!=’N’) && (z[0]!=’j’) && (z[0]!=’J’));

} while (z[0]!=’n’ && z[0]!=’N’);

return 0;

}

75

Page 76: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

20.6 Aufgabe 2.6: Programm FAKTOR

/* Programm FAKTOR

Eine einzugebende Zahl wird in Primfaktoren zerlegt */

#include <stdio.h>

int main (void)

{

int Zahl, Teiler;

printf("Bitte eine Zahl eingeben! ");

scanf("%d", &Zahl);

printf("Die Zahl wird in Primfaktoren zerlegt...\n%d = ", Zahl);

do

{

for(Teiler=2; Teiler<=Zahl; Teiler++)

if(Zahl % Teiler==0)

{

printf("%d ", Teiler);

Zahl = Zahl / Teiler;

Teiler = 1;

if (Zahl>1) printf("* ");

}

}

while(Zahl>1);

printf("\n");

return 0;

}

76

Page 77: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

21 Losungsbeispiele Teil 3

Die dargestellten Losungen sind nur Beispiele, es gibt naturlich auch noch viele andereLosungsmoglichkeiten.

21.1 Aufgabe 3.1: Programm GROSS1

#include <stdio.h>

int gross (int zeichen) /* Funktion wandelt in Großbuchstaben */

{

if ( zeichen >=’a’ && zeichen <=’z’ ) zeichen = zeichen-32;

return zeichen;

}

int main (void)

{

int c;

do

{

c=getchar(); /* Ein Zeichen holen */

c=gross(c); /* In Großbuchstaben wandeln */

putchar(c); /* und wieder ausgeben. */

}

while (c!=10);

return 0;

}

77

Page 78: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

21.2 Aufgabe 3.2: Programm GROSS2

Zu dieser Aufgabe habe ich zwei verschiedene Versionen. Hier zunachst die Version furLINUX-Systeme mit UTF8-Codierung:

#include <stdio.h>

int gross (int zeichen) /* Funktion wandelt in Großbuchstaben */

{

if ( zeichen >=’a’ && zeichen <=’z’ ) zeichen = zeichen-32;

switch (zeichen)

{

case 0xA4: zeichen=0x84; break; /* a in A wandlen */

case 0xB6: zeichen=0x96; break; /* o in O wandlen */

case 0xBC: zeichen=0x9C; break; /* u in U wandlen */

}

return zeichen;

}

int main (void)

{

int c;

do

{

c=getchar(); /* Ein Zeichen holen */

if (c==0xC3) /* UTF8-Umlaut? */

{

putchar(c); /* Einleitungszeichen ausgeben */

c=getchar(); /* Fortsetzungszeichen holen */

}

c=gross(c); /* In Großbuchstaben wandeln */

putchar(c); /* und wieder ausgeben. */

}

while (c!=10); /* Das Enter-Zeichen */

return 0;

}

78

Page 79: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

Fur herkommliche Windows-Systeme im DOS-Modus sieht das Programm beispielsweiseso aus:

#include <stdio.h>

int gross (int zeichen) /* Funktion wandelt in Großbuchstaben */

{

if ( zeichen >=’a’ && zeichen <=’z’ ) zeichen = zeichen-32;

switch (zeichen)

{

case 0x84: zeichen=0x8E; break; /* a in A wandlen */

case 0x94: zeichen=0x99; break; /* o in O wandlen */

case 0x81: zeichen=0x9A; break; /* u in U wandlen */

}

return zeichen;

}

int main (void)

{

int c;

do

{

c=getchar(); /* Ein Zeichen holen */

c=gross(c); /* In Großbuchstaben wandeln */

putchar(c); /* und wieder ausgeben. */

}

while (c!=10); /* Das Enter-Zeichen */

return 0;

}

79

Page 80: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

21.3 Aufgabe 3.3: Programm KOMPLEX

/* Programm KOMPLEX

Vier Grundrechenarten mit Komplexen Zahlen */

#include <stdio.h>

float produkt_Re (float rea, float ima, float reb, float imb)

{

float rec;

rec=rea*reb-ima*imb;

return rec;

}

float produkt_Im (float rea, float ima, float reb, float imb)

{

float imc;

imc=rea*imb+ima*reb;

return imc;

}

float quotient_Re (float rea, float ima, float reb, float imb)

{

float rec;

rec=(rea*reb+ima*imb)/(reb*reb+imb*imb);

return rec;

}

float quotient_Im (float rea, float ima, float reb, float imb)

{

float imc;

imc=(ima*reb-rea*imb)/(reb*reb+imb*imb);

return imc;

}

int main (void)

{

float Rea, Ima,

Reb, Imb,

Rec, Imc;

char z[5]; /* Platz fur einen kleinen String (Rechenzeichen) */

do

{

80

Page 81: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

printf("Bitte zwei komplexe Zahlen mit einem Rechenzeichen dazwischen eingeben!\n");

printf("Eingabeformat: \nRealteil1 Imaginarteil1 Rechenzeichen Realteil2 Imaginarteil2\n");

scanf("%f%f%s%f%f",&Rea, &Ima, &*z, &Reb, &Imb);

switch(z[0])

{

case ’+’: Rec=Rea+Reb;

Imc=Ima+Imb;

printf("(%g",Rea);

if (Ima>=0) putchar(’+’);

printf("j%g)+(%g",Ima,Reb);

if (Imb>=0) putchar(’+’);

printf("j%g) = %g",Imb,Rec);

if (Imc>=0) putchar(’+’);

printf("j%g\n",Imc); break;

case ’-’: Rec=Rea-Reb;

Imc=Ima-Imb;

printf("(%g",Rea);

if (Ima>=0) putchar(’+’);

printf("j%g)-(%g",Ima,Reb);

if (Imb>=0) putchar(’+’);

printf("j%g) = %g",Imb,Rec);

if (Imc>=0) putchar(’+’);

printf("j%g\n",Imc); break;

case ’*’: Rec=produkt_Re(Rea,Ima,Reb,Imb);

Imc=produkt_Im(Rea,Ima,Reb,Imb);

printf("(%g",Rea);

if (Ima>=0) putchar(’+’);

printf("j%g)*(%g",Ima,Reb);

if (Imb>=0) putchar(’+’);

printf("j%g) = %g",Imb,Rec);

if (Imc>=0) putchar(’+’);

printf("j%g\n",Imc); break;

case ’:’: ;

case ’/’: Rec=quotient_Re(Rea,Ima,Reb,Imb);

Imc=quotient_Im(Rea,Ima,Reb,Imb);

printf("(%g",Rea);

if (Ima>=0) putchar(’+’);

printf("j%g):(%g",Ima,Reb);

if (Imb>=0) putchar(’+’);

printf("j%g) = %g",Imb,Rec);

if (Imc>=0) putchar(’+’);

printf("j%g\n",Imc); break;

default : printf("Falsche Eingabe!\n ");

}

81

Page 82: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

do

{

printf("Noch eine Rechnung? (j/n) ");

scanf("%s",&*z);

} while ((z[0]!=’n’) && (z[0]!=’N’) && (z[0]!=’j’) && (z[0]!=’J’));

} while (z[0]!=’n’ && z[0]!=’N’);

return 0;

}

82

Page 83: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

22 Losungsbeispiele Teil 4

Die dargestellten Losungen sind nur Beispiele, es gibt naturlich auch noch viele andereLosungsmoglichkeiten.

22.1 Aufgabe 4.1: Programm GROSS3

In diesem Beispiel ist wichtig zu wissen, fur welches Betriebssystem bzw. fur welchenZeichensatz das Programm bestimmt ist. Hier ist die UTF8-Codierung zugrunde gelegtworden, wie sie zur Zeit in allen gangigen Linux-Systemen (und in Zukunft moglicher-weise auch auf Windows-Systemen) ublich ist. Um die Vielfalt der Umlaute abbilden zukonnen, bestehen sie unter UTF8 aus einem Doppel-Byte, wobei bei den deutschenUmlauten das erste Byte immer C3hex lautet.

#include <stdio.h>

xunsigned char gross (unsigned char zeichen)

{ /* Funktion wandelt in Großbuchstaben */

if ( zeichen >=’a’ && zeichen <=’z’ ) zeichen = zeichen-32;

switch (zeichen)

{

case 0xA4: zeichen=0x84; break; /* a in A */

case 0xB6: zeichen=0x96; break; /* o in O */

case 0xBC: zeichen=0x9C; break; /* u in U */

}

return zeichen;

}

int main (void)

{

unsigned char c[128];

int i=0;

scanf("%s",&*c);

while (c[i]!=0)

{

if (c[i]==0xC3) i++; /* Bei UTF8-Umlaut Zahler weiter */

c[i]=gross(c[i]); /* In Großbuchstaben wandeln */

i++;

}

c[i]=10; /* Zeilenumbruch anhangen */

c[i+1]=0; /* neue Stringendemarke! */

printf(c);

return 0;

}

83

Page 84: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

22.2 Aufgabe 4.2: Programm SKALAR

#include <stdio.h>

int main (void)

{

int a[10], b[10], i, n, s;

char z[5];

printf("Berechnung des Skalarproduktes\n\n");

do /* Hauptschleife */

{

do /* Schleife fur Dimensionseingabe */

{

printf("Bitte die Dimension eingeben: ");

scanf("%d", &n);

if (n<2 || n>10) printf("Unzulassiger Wert!\n");

} while (n<2 || n>10);

for(i=1;i<=n;i++) /* Eingabe Vektor a */

{

printf("a%d= ", i);

scanf("%d",&a[i-1]);

}

for(i=1;i<=n;i++) /* Eingabe Vektor b */

{

printf("b%d= ", i);

scanf("%d",&b[i-1]);

}

putchar(’(’);

for(i=0;i<n;i++)

{

printf("%d",a[i]);

if (i<n-1) putchar(’ ’);

}

printf(")o(");

for(i=0;i<n;i++)

{

printf("%d",b[i]);

if (i<n-1) putchar(’ ’);

}

s=0; /* Startwert fur Summe */

for(i=0;i<n;i++) s=s+a[i]*b[i]; /* eigentliche Berechnung */

printf(")= %d\n", s);

do /* Schleife fur Ja/Nein-Abfrage */

{

84

Page 85: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

printf("Noch eine Rechnung? (j/n) ");

scanf("%s",&*z);

} while((z[0]!=’n’)&&(z[0]!=’N’)&&(z[0]!=’j’)&&(z[0]!=’J’));

} while (z[0]!=’n’ && z[0]!=’N’);

return 0;

}

85

Page 86: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

22.3 Aufgabe 4.3: Programm KREUZ

/* Kreuzprodukt zweier Vektoren */

#include <stdio.h>

int main (void)

{

float a[3], b[3], c[3];

int i;

char z[5];

printf("Berechnung des Kreuzproduktes zweier Vektoren\n\n");

do /* Hauptschleife */

{

for(i=1;i<=3;i++) /* Eingabe Vektor a */

{

printf("a%d= ", i);

scanf("%f",&a[i-1]);

}

for(i=1;i<=3;i++) /* Eingabe Vektor b */

{

printf("b%d= ", i);

scanf("%f",&b[i-1]);

}

printf("(%g %g %g)x(%g %g %g) = ",a[0],a[1],a[2],b[0],b[1],b[2]);

c[0]=a[1]*b[2]-a[2]*b[1];

c[1]=a[2]*b[0]-a[0]*b[2];

c[2]=a[0]*b[1]-a[1]*b[0];

printf("(%g %g %g)\n", c[0], c[1], c[2]);

do /* Schleife fur Ja/Nein-Abfrage */

{

printf("Noch eine Rechnung? (j/n) ");

scanf("%s",&*z);

} while((z[0]!=’n’)&&(z[0]!=’N’)&&(z[0]!=’j’)&&(z[0]!=’J’));

} while (z[0]!=’n’ && z[0]!=’N’);

return 0;

}

86

Page 87: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

22.4 Aufgabe 4.4: Programm DET3

#include <stdio.h>

float det[3][3];

void zeilenweise(void)

{

int i, j;

float k;

for(i=1;i<4;i++)

{

for(j=1;j<4;j++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

}

void spaltenweise(void)

{

int i, j;

float k;

for(j=1;j<4;j++)

{

for(i=1;i<4;i++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

}

void zeile(void)

{

int i, j;

float k;

printf("Bitte Zeilennummer eingeben: ");

scanf("%d", &i);

for(j=1;j<4;j++)

{

87

Page 88: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

void spalte(void)

{

int i, j;

float k;

printf("Bitte Spaltennummer eingeben: ");

scanf("%d", &j);

for(i=1;i<4;i++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

void berechnung(void)

{

float s;

s=det[0][0]*det[1][1]*det[2][2]+det[0][1]*det[1][2]*det[2][0];

s=s+det[0][2]*det[1][0]*det[2][1]-det[2][0]*det[1][1]*det[0][2];

s=s-det[2][1]*det[1][2]*det[0][0]-det[2][2]*det[1][0]*det[0][1];

printf("\n| %5g %5g %5g |\n", det[0][0], det[0][1], det[0][2]);

printf("| %5g %5g %5g | = %5g\n", det[1][0], det[1][1], det[1][2],s);

printf("| %5g %5g %5g |\n\n", det[2][0], det[2][1], det[2][2]);

}

int main (void)

{

int a;

printf("Berechnung einer 3-reihigen Determinante\n\nAuswahl:\n");

do {

printf("1: Kompletteingabe zeilenweise\n2: Kompletteingabe spaltenweise\n");

printf("3: Eine Zeile eingeben\n4: Eine Spalte eingeben\n");

printf("5: Determinante berechnen\n6: Beenden\n\n");

scanf("%d", &a);

switch (a)

{

case 1: zeilenweise(); berechnung(); break;

case 2: spaltenweise(); berechnung(); break;

88

Page 89: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

case 3: zeile(); berechnung(); break;

case 4: spalte(); berechnung(); break;

case 5: berechnung(); break;

}

} while (a!=6);

return 0;

}

89

Page 90: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

22.5 Aufgabe 4.5: Programm LIN

#include <stdio.h>

#define max 20 /* maximal zulassige Anzahl der Variablen */

float a[max][max+1];

int n;

void zeilenweise(void) /* Zeilenweise Gleichungseingabe*/

{

int i, j;

float k;

for(i=1;i<n+1;i++){

for(j=1;j<n+2;j++){

if(j<=n) printf("a%d%d = ",i,j); else printf("b%d = ",i);

scanf("%f", &k);

a[i-1][j-1]=k;

}

}

}

char berechnung (void) /* Berechnung nach Gauß */

{

float puffer;

char flag=0;

int i,j,k;

for(k=0;k<n;k++){

if(a[k][k]==0){ // falls vorn eine 0 steht, muss getauscht werden

i=k+1;

if(i>=n) flag=1;

while(a[i][k]==0 && flag==0){

if(i>=n) flag=1;

i++;

}

if(flag==0){

for(j=0;j<=n;j++){ // Zeile i mit k tauschen

puffer=a[i][j];

a[i][j]=a[k][j];

a[k][j]=puffer;

}

}

}

if(flag==0){

90

Page 91: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

for(j=n;j>=k;j--){ // 1 in Diagonale erzeugen

a[k][j]=a[k][j]/a[k][k];

}

if(k<n){ // unten Nullen erzeugen

for(i=k+1;i<n;i++){

for(j=n;j>=k;j--){

a[i][j]=a[i][j]-(a[k][j]*a[i][k]);

}

}

}

}

}

if(flag==0){ // oben Nullen erzeugen

for(k=n-1;k>=0;k--){

for(i=0;i<k;i++){

for(j=n;j>=k;j--){

a[i][j]=a[i][j]-(a[k][j]*a[i][k]);

}

}

}

}

return(flag);

}

int main(void)

{

int i;

printf("Losung eines Lineargleichungssystems\n");

do{

printf("Bitte die Zahl der Variablen (2 bis %d) eingeben!\n",max);

scanf("%d",&n);

if(n<2) printf("Die Zahl ist zu klein!\n");

if(n>max) printf("Die Zahl ist zu groß!\n");

} while((n<2)||(n>max));

printf("Berechnet wird ein Gleichungssystem %d. Ordnung.\n",n);

zeilenweise(); // Eingabe der Gleichungen

printf("\nLosungen:\n");

if (berechnung()==1){

printf("Das Gleichungssystem ist unterbestimmt!\n");

} else {

for(i=1;i<=n;i++)printf("a%d = %g\n",i,a[i-1][n]);

}

return(0);

}

91

Page 92: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

23 Losungsbeispiele Teil 5

Die dargestellten Losungen sind nur Beispiele, es gibt naturlich auch noch viele andereLosungsmoglichkeiten.

23.1 Aufgabe 5.1: Programm FAKULTAET

#include <stdio.h>

double fakultaet(double n)

{

double z=1;

if (n>1)

z=n*fakultaet(n-1);

return z;

}

int main (void)

{

double n;

printf("Bitte eine naturliche Zahl eingeben: ");

scanf("%lf",&n);

printf("%g! = %g\n",n,fakultaet(n));

return 0;

}

92

Page 93: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

23.2 Aufgabe 5.2: Programm DETERMINANTE

#include <stdio.h>

#define max 10 /* Maximale Dimension als Konstante */

float det[max][max];

int n;

void zeilenweise(void) /* Determinanteneingabe zeilenweise */

{

int i, j;

float k;

for(i=1;i<n+1;i++)

{

for(j=1;j<n+1;j++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

}

void spaltenweise(void) /* Determinanteneingabe spaltenweise */

{

int i, j;

float k;

for(j=1;j<n+1;j++)

{

for(i=1;i<n+1;i++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

}

93

Page 94: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

void zeile(void) /* Eingabe einer einzelnen Zeile */

{

int i, j;

float k;

do

{

printf("Bitte Zeilennummer eingeben: ");

scanf("%d", &i);

if(i<1) printf("Die Zeilennummer muss mindestens 1 sein!\n");

if(i>n) printf("Die Zeilennummer darf hochstens %d sein!\n",n);

} while(i<1||i>n);

for(j=1;j<n+1;j++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

void spalte(void) /* Eingabe einer einzelnen Spalte */

{

int i, j;

float k;

do

{

printf("Bitte Spaltennummer eingeben: ");

scanf("%d", &j);

if(j<1) printf("Die Spaltennummer muss mindestens 1 sein!\n");

if(j>n) printf("Die Spaltennummer darf hochstens %d sein!\n",n);

} while(j<1||j>n);

for(i=1;i<n+1;i++)

{

printf("a%d%d= ",i,j);

scanf("%f", &k);

det[i-1][j-1]=k;

}

}

94

Page 95: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

float berechne(int m, float DET[][max]) /* Rekursive Berechnung */

{

float deter[max-1][max];

/* lokale Hilfs-Determinante - Die Zeilenzahl kann um 1 kleiner

sein, als die Originaldeterminante. Die Spaltenzahl muss

die gleiche bleiben, damit Rekursion (gleicher Zeigertyp!)

moglich ist. */

float ergebnis;

int i,j,k,v;

if(m==2) ergebnis=DET[0][0]*DET[1][1]-DET[1][0]*DET[0][1];

if(m>2)

{

ergebnis=0; /* Initialisieren */

for(k=0;k<m;k++) /* Nach 1. Spalte entwickeln */

{ /* Lokale Determinante fullen: */

if(k>0)

for(i=0;i<k;i++)

for(j=0;j<m;j++)

deter[i][j]=DET[i][j+1];

if(k<m-1)

for(i=k;i<m-1;i++)

for(j=0;j<m;j++)

deter[i][j]=DET[i+1][j+1];

if(k%2==0) v=1; else v=-1; /* korrektes Vorzeichen bestimmen */

ergebnis=v*DET[k][0]*berechne(m-1,deter)+ergebnis; /* Rekursion */

}

}

return ergebnis;

}

void berechnung(void) /* Berechnung und Ausgabe */

{

int i,j;

float z;

for(i=0;i<n;i++)

{

printf("\n|");

for(j=0;j<n;j++) printf("%5g ",det[i][j]);

printf("|");

}

z=berechne(n,det);

printf("\n = %g\n",z);

}

95

Page 96: C Programmierung - DK4EK · 2018. 10. 9. · C Programmierung W. Kippels 11. Februar 2011 Eine Anleitung mit Ubungsaufgaben 1. Inhaltsverzeichnis 1 Grundlegendes 5 2 Der Compiler

int main (void)

{

int a;

printf("Berechnung einer n-reihigen Determinante\n");

do

{

printf("Bitte die Dimension der Determinante eingeben: ");

scanf("%d",&n);

if(n>max) printf("n darf nicht großer als %d sein!\n",max);

if(n<2) printf("n muss mindestens 2 sein!\n");

}

while (n>max||n<2);

do {

printf("\nAuswahl:\n");

printf("1: Kompletteingabe zeilenweise\n");

printf("2: Kompletteingabe spaltenweise\n");

printf("3: Eine Zeile eingeben\n");

printf("4: Eine Spalte eingeben\n");

printf("5: Determinante berechnen\n");

printf("6: Beenden\n");

scanf("%d", &a);

switch (a)

{

case 1: zeilenweise(); berechnung(); break;

case 2: spaltenweise(); berechnung(); break;

case 3: zeile(); berechnung(); break;

case 4: spalte(); berechnung(); break;

case 5: berechnung(); break;

}

} while (a!=6);

return 0;

}

96