View
216
Download
1
Category
Preview:
Citation preview
1
C-Programmierung 2003/2004 1
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Grundlagen der Programmierung
2
C-Programmierung 2003/2004 2
Einleitung
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Was sind Programme? Warum programmieren?
Einfache und schnelle Lösung mathematischen Problemen
Erarbeitung eines Algorithmus
Übersetzen des Algorithmus in die Maschinensprache
Erstellung einer Abarbeitungsvorschrift (Programm) für den Computer in einer speziellen Sprache
Abarbeitung des Programms im Computer
Ergebnis
3
C-Programmierung 2003/2004 3
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Fortran
Cobol Algol 60
Basic
Visual Basic
Pascal
1950
1960
Algol 68
C
C++
Java
C#
Delphi
Ada
1970
1980
1990
2000
Prozedurale Sprachen Objektorientierte Sprachen
Klassifikation nach Sprachtypen
4
C-Programmierung 2003/2004 4
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Funktionale Sprachen: - Lisp (1960)
- das Programm besteht aus Funktionen, die sich
gegenseitig aufrufen
- Programme werden wie mathematische
Funktionen geschrieben
- Funktion hat einen Definitions- und Wertebereich
- Funktion erhält Eingebewert und berechnet den
Wert der Funktion
- Einsatz im Forschungsbereich für künstliche
Intelligenz und im Bereich der Mathematik
Logische Sprachen: - Prolog (1970)
- Sprachen sind auf die Lösung von bestimmten
Problemen abgestimmt (Datenbankabfragen)
- das Programm bestimmt eine logische Beziehung
zwischen den einzelnen Daten
5
C-Programmierung 2003/2004 5
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Klassifikation nach Sprachgenerationen
Erste Generation: Maschinensprache
- Programmierung auf Maschinenniveau (0110101010)
Zweite Generation: Assembler-Sprache
- Programmierung auf Prozessorniveau; Anwendung
von speziellen Befehlen (LD 3,4 ; ADD ww1,dd4)
Dritte Generation: Problemorientierte Sprachen
- PL/1; Pascal, Cobol, Ada, C/C++, Basic usw.
Vierte Generation: Deklarative Sprachen
- SQL, Open Access
Fünfte Generation: Künstliche Intelligenz
- Lisp, Prolog, Smalltalk
6
C-Programmierung 2003/2004 6
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Entwicklung und Ausführung eines Programms
Problem Lösung mittels eines Algorithmus
mehrere Module
Modul 1
Modul 2
Modul 3
Compiler
Compiliertes Modul 1
Compiliertes Modul 2
Compiliertes Modul 3
Linker
(Verbinder)
Fertiges Programm mit
relativen Adressen
(Lademodul)
LaderAusführbares
Programm mit absoluten
Adressen
InterpreterProgramm
7
C-Programmierung 2003/2004 7
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Entwicklungsumgebung
Compiler und Linker sind für unterschiedliche Betriebssystemplattformen verfügbar
Für viele Betriebssysteme gibt es mächtige Entwicklungswerkzeuge, sogenannte Entwicklungsumgebungen. In diesen Tools sind die:
• Projektverwaltung,
• Editoren,
•Grafiktools,
•Compiler,
•Debugger und
•Linker
unter einer gemeinsamen Oberfläche vereinigt. Der Entwickler kann damit von der Quellcoderfassung bis zum fertigen Tool alles mit einem Werkzeug realisieren. Damit ist eine sehr effektive Arbeit möglich
Weiterhin gehören zu jeder Programmiersprache noch entsprechende Standard-bibliotheken.
8
C-Programmierung 2003/2004 8
Friedrich-Schiller-Universität Jena
Universitätsrechenzentrum
Multimediazentrum
Microsoft Visual C++ 6.0
10
C-Programmierung 2003/2004 10
Inhaltsverzeichnis
1. Grundlagen2. Funktionen3. Variablentyp int4. Eingabe mit scanf5. Grundrechenarten6. Entscheidung if7. Gültigkeitsbereich von Variablen8. Funktionen mir Parameterübergabe8.1. Parameterübergabe8.2. Wertrückgabe8.3. Übergabe mehrerer Parameter8.4. Prototypen parametrisierter Funktionen8.5. spezielle Hinweise zu Funktionen mit Parameterübergabe9. Die for-Schleife10. Schleifen mit Ein- und Austrittsbedingungen10.1. Schleifen mit Eintrittsbedingung10.2. Schleifen mit Austrittsbedingung10.3. Continue-Anweisung
11
C-Programmierung 2003/2004 11
11. Logische Operatoren12. Variablen vom Typ float13. Fallunterscheidungen14. Der Variablentyp char15. Zeiger und Vektoren15.1. Adressen als Funktionsparameter15.2. Zeiger auf Funktionen15.3. Zeiger auf Zeiger16. Variablenfelder17. Zeichenketten - String18. Strukturen19. Arbeit mit Dateien20. Präprozessor-Befehle21. Programmier-Technologien21.1. Eigene Header Dateien21.2. Rekursion21.3. Listen21.4 Sortierverfahren21.5 Suchalgorithmen21.6 Datenkomprimierung22. Zusammenfassung
12
C-Programmierung 2003/2004 12
1. GrundlagenDas erste C-Programm:
void main(void) /*Ein C-Programm*/
{
}
- dieses Programm realisiert nichts
- jedes C-Programm beginnt immer mit main (Haupt; Hauptfunktion)
- vor dem Funktionsaufruf steht void, das bedeutet, dass die Funktion keinen Rückgabewert
liefert
- das void nach dem Funktionsaufruf bedeutet, dass dem Funktionsaufruf keine Werte
übergeben werden
- hinter dem Funktionsaufruf stehen geschweifte Klammern, welche die Anweisungen der
Funktion umschließen (dürfen nie fehlen !)
void=leer
13
C-Programmierung 2003/2004 13
- geschweifte Klammern fassen Anweisungen zu einem Block zusammen
- Zusammengehörige geschweifte Klammern sollten immer untereinander stehen
- Kommentare werden immer in /* Kommentar */ eingeschlossen
und dürfen nicht verschachtelt werden
Ausgabe mit printf
- eine Grundfunktion mit der Ausgaben aller Art unterstützt werden heißt printf( )
#include <stdio.h>
void main(void)
{
printf("Das ist eine Bildschirmausgabe");
}
- der Funktion printf wird eine Stringkonstante übergeben, die während der
Ausführungszeit nicht verändert wird
14
C-Programmierung 2003/2004 14
- Stringkonstanten stehen immer innerhalb von doppelten Anführungszeichen
-Anweisungen, denen kein Anweisungsblock folgt, werden mit einem Semikolon
abgeschlossen
- #include <stdio.h> Standardbibliothek stdio.h an das C-Progamm binden
- der #include-Befehl ist kein Bestandteil der Sprache C, sondern der Befehl eines Präprozesses
- Präprozesse werden nur vom Compiler benötigt und nehmen bestimmte Änderungen während
der Compilierung im Programm vor
- ohne #include kommt es zu Fehlermeldungen während der Compilierung, da der Compiler
die Funktion printf nicht kennt
- Präprozessorbefehle erkennt man am # in der ersten Spalte
- diese Befehle dürfen nicht nach rechts eingerückt werden !!!
15
C-Programmierung 2003/2004 15
Steuerzeichen für die Ausgabe
#include <stdio.h>
void main(void)
{
printf ("Ausgabetext-1");
printf ("Ausgabe-2");
}
Ausgabe am Bildschirm: Ausgabetext-1Ausgabe-2
Durch den Einsatz von Steuerzeichen kann die Bildschirmausgabe den Erfordernissen des Nutzers angepasst werden.
16
C-Programmierung 2003/2004 16
Esc-Sequenz Aktion
\t HAT (horizontal tab), der Cursor geht zur nächsten horizontalen Tabulatorposition
\v VT (vertical tab), der Cursor geht zur nächsten vertikalen Tabulatorposition
\" " wird ausgegeben
\' ' wird ausgegebeb
\? ? wird ausgegeben
\\ \ wird ausgegeben
Wenn C keine Steuerinformation erhält, dann wird auch bei der Aus- und Eingabe keine Aktivität ausgelöst!!!
#include <stdio.h>
void main(void)
{
printf ("Ausgabe-1\n");
printf ("Ausgabe-2");
}
Ausgabe am Bildschirm:
Ausgabe-1
Ausgabe-2
Programm01
17
C-Programmierung 2003/2004 17
#include <stdio.h>
vioid main(void)
{
printf ("Ausgabe-1\nAusgabe-2");
}
Alternativ (Ausgabe in einer printf-Anweisung)
Esc-Sequenz Aktion
\a BEL (bell) gibt akustisches Signal
\b BS (backspace), Curser geht eine Position nach links
\f FF (formfeed), Seitenvorschub wird ausgelöst
\n NL (new line), Curser geht zum Anfang der nächsten Zeile
\r CR (carriage return), der Cursor geht zum Anfang der aktuellen Zeile
18
C-Programmierung 2003/2004 18
2. Funktionen
Die Zerlegung eines Programms in verschiedene Funktionen dient der Verbesserung der Übersichtlichkeit und der effektiveren Realisierung des Programmablaufs.
Programme sollten immer in sinnvolle Blöcke gegliedert werden!!!
Diese Planung sollte bereits vor der Programmierung erfolgen, denn später lässt sich eine Gliederung in mehrere Blöcke (Funktionen) meist nicht mehr realisieren.
#include <stdio.h>void funktion1(void){printf ("Ausgabe-1\n");}void funktion2(void){printf ("Ausgabe-2\n");}
19
C-Programmierung 2003/2004 19
void main(void){funktion1( );funktion2( );}
Startmain
funktion1
funktion2
EndemainFunktionsaufruf
funktion1
funktion2
{printf ("Ausgabe-1\n");}
{printf ("Ausgabe-2\n");}
20
C-Programmierung 2003/2004 20
Funktionsnamen müssen mit Buchstaben oder Unterstrich beginnen und dürfen nur Buchstaben, Ziffern oder Unter- striche enthalten.
Bei Namen wird auf Groß- und Kleinbuchstaben geachtet.
Nur die ersten 31 Zeichen werden bei der Namensunterscheidung benutzt.
Diese Regeln gelten für alle Namen (Variablen, Funktionsnamen, Strukturnamen usw).
21
C-Programmierung 2003/2004 21
Funktionsdeklarationen und Prototypen
Prototyp
Funktionsdeklaration
#include <stdio.h>
void funktion1(void);void funktion2(void);
void main(void){funktion1();funktion2();
}void funktion1(void){
printf("Ausgabe-Text-Funktion1\n");}void funktion2(void){
printf("Ausgabe-Text-Funktion2\n");}
22
C-Programmierung 2003/2004 22
3. Variablentyp int
Variablen bestehen aus Buchstaben oder einem Wort (evtl. in Verbindung mit Ziffern) und repräsentieren einen Wert.
Variablentyp int (integer) = ganzzahlig
z.B. 2, 99, -23, 387 usw.
Typ Größe Zahlenbereich FZint 2 Byte -32768 bis +32767 i
unsignetd int 2 Byte 0 bis 65535 u
long 4 Byte - 2147483648 bis + 2147483647 li
unsigned long 4 Byte 0 bis 4294967295 lu
short 1 Byte - 128 bis + 127 hi
unsigned short 1 Byte 0 bis 255 hu
FZ = Formatzeichen
Varianten von Integer-Variablen
23
C-Programmierung 2003/2004 23
Die angegebenen Längen von Integer Variablen sind Mindestgrößen, die ein Compiler benutzen muss, es können aber auch mehr sein.
24
C-Programmierung 2003/2004 24
Formatzeichen für die Ausgabe
Um printf innerhalb eines Strings mitzuteilen welcher Variablentyp zu benutzen ist, muss das entsprechende Formatzeichen angegeben werden.
printf ("Ausgabe einer Int Zahl mit 2 Byte: %i", zahl1);
an %i kann man erkennen, daß Zahl1 eine Variable vom Typ int sein muss !!!
printf ("Ausgabe von Zahlen %i, %hu, %li", x1, x2, x3);
int unsigned int long int
25
C-Programmierung 2003/2004 25
#include <stdio.h>void main(void){
int zahl1;int zahl2;int zahl3;
zahl1=19;zahl2=-23;zahl3=299;
printf("Die Zahlen lauten %i, %i und %i\n",zahl1,zahl2, zahl3);}
Bildschirmausgabe:
Die Zahlen lauten 19, -23 und 299
26
C-Programmierung 2003/2004 26
1. Variablen werden definiert
2. Variablen wird ein Wert zugewiesen = initialisieren
Dies erfolgt in C durch den Zuweisungsoperator "="
3. Steht rechts vom Gleichheitszeichen ein Ausdruck, z.B.
a=b+c, wird zuerst berechnet und dann der Wert zugewiesen.
verkürzte Schreibweise
int zahl1; int zahl2; int zahlxyz; int a;
kann auch wie folgt realisiert werden:
int zahl1, zahl2, zahlxyz, a;
oder sofort mit Wertzuweisung:
int zahl1=222, zahl2=333, zahlxyz=-234, a=-99;
Vor dem Gleichheitszeichen dürfen keine konstanten Ausdrücke stehen
27
C-Programmierung 2003/2004 27
Variablen, welche nicht initialisiert sind, haben immer einen undefinierten Wert.
Variablen prinzipiell initialisieren
Erweiterte Formatierung bei der Ausgabe
printf ("Ausgabe des Wertes %+i", 99);
Der Wert bekommt immer ein Vorzeichen +99
printf ("Ausgabe des Wertes %5i und %5i\n", 99, 33333);
Beide Zahlen haben die gleiche Länge (hier 5). Fehlende Stellen werden mit Leerzeichen aufgefüllt. Ist die Zahl länger als der reservierte Platz, wird sie trotzdem komplett ausgegeben
28
C-Programmierung 2003/2004 28
printf ("Ausgabe des Wertes %-5i und %-5i\n", 99, 33333);
Werte linksbündig ausgeben
printf ("Ausgabe des Wertes %05i und %05i\n", 99, 33333);
Mit führenden Nullen auffüllen
29
C-Programmierung 2003/2004 29
4. Eingabe mit scanf
Eingabe erfolgt mit der Funktion scanf. Diese Funktion steht genau wie printf in der Headerdatei stdio.h.
#include <stdio.h>
void main(void){unsigned int zahl;
printf("Geben Sie bitte eine Zahl größer gleich Null und kle\iner 65536 ein:");
scanf("%u",&zahl);printf("Sie haben %u eingegeben.\n",zahl);
}
Trennsymbol "\"
Folgezeile nicht einrücken
30
C-Programmierung 2003/2004 30
scanf("%u",&zahl);
Adresse von Zahl (&=Addreßoperator
Formatzeichen
scanf("Bitte eine Zahl eingeben %u", &zahl);
Text wird ignoriert !!!!!
printf ("Bitte eine Zahl eingeben:");
scanf ("%i",&zahl);
Richtig !!!!!
31
C-Programmierung 2003/2004 31
Achtung:
Die Programmiersprache C prüft bei scanf nicht die Überschreitung des Wertebereiches der definierten Variablen !!!!!
Programmierer muss selbst die Richtigkeit der Eingaben prüfen. Einfügen von entsprechenden Prüfprogrammen (Funktionen).
32
C-Programmierung 2003/2004 32
5. Grundrechenarten
+ Addiert zwei Werte
- Subtrahiert den rechten Wert vom linken
* Multipliziert zwei Werte miteinander
/ Dividiert den linken Wert durch den rechten
Punktrechnungen (* und /) binden stärker als Strichrechnungen ( + und -).
Wird eine andere Reihenfolge der Berechnung benötigt, so müssen Klammern verwendet werden.
aa=5*3+zahl1;
aa=5*(3+zahl1);
int-Variablen nehmen nur ganzzahlige Werte auf. Bei "/" werden die entstehenden Nachkommastellen weggelassen (es erfolgt keine Rundung).
33
C-Programmierung 2003/2004 33
Der Modulo-Operator %
Der Modulo-Operator bestimmt den Rest einer Division von Ganzzahlen.
13%4 = 1 denn 13/4=3 und 3*4=12
13-12=1
23%5 = 3 denn 23/5=4 und 5*4=20
23-20=3
Anwendungsfall:
Schubladenprinzip: - es existieren 8 Schubladen 0 bis 7
- es werden Zahlen in die Schubladen einsortiert
- 0 in Schublade 0
- 7 in Schublade 7
- 8 in Schublade 0 usw.
schublade=zahl%8;
33 / 8 = 4
4 * 8 = 32 Rest 1
Schublade 1
34
C-Programmierung 2003/2004 34
Weitere Operatoren (Zuweisungsoperatoren)
+= zahl+=5; zahl=zahl+5;
-= zahl-=5; zahl=zahl-5;
*= zahl*=5; zahl=zahl*5;
/= zahl/=wert; zahl=zahl/wert;
%= zahl%=6; zahl=zahl%6;
Frage ?
zahl=wert1/wert2 + zahl;
zahl+=wert1/wert2;
Die beiden Ausdrücke sind nur deshalb äquivalent, da "/" eine stärkere Bindung hat als "+".
35
C-Programmierung 2003/2004 35
zahl=zahl*wert1+wert2 ;
zahl*=wert1+wert2;
Achtung: Es erfolgt immer erst die Berechnung rechts und dann die Zuweisung !!!!!
falsch
36
C-Programmierung 2003/2004 36
Ausgabe von Ausdrücken
An jeder Stelle im Programm, an der eine Variable stehen kann, ist auch ein berechenbarer Ausdruck möglich. Außer auf der linken Seite eines Ausdruckes.
z3=z1+z2;
printf ("%i plus %i gleich %i\n", z1,z2,z3);
oder
printf ("%i plus %i gleich %i\n", z1, z2, z1+z2);
oder
printf ("%i plus %i gleich %i\n", z1, z2, z3=z1+z2);
Steht an einer Stelle im Programm ein berechenbarer Ausdruck, kann er auch dort zugewiesen werden.
37
C-Programmierung 2003/2004 37
An jeder Stelle im Programm, an der eine Variable steht, kann auch eine Konstante stehen.
printf ("Die Zahl heißt %i\n" , 123);
oder
printf ("Die Zahl heißt 123");
38
C-Programmierung 2003/2004 38
Die Operatoren ++ und --
Eine Variable wird inkrementiert (++), wenn ich ihren Wert um eins erhöhe.
Eine Variable wird dekrementiert (--), wenn ich ihren Wert um eins erniedrige.
Verwendung: Bei der Benutzung von Zählern !!!
wert=3;
printf ("Die Zahl lautet %i", wert);
wert++;
printf ("Die Zahl lautet %i"; wert);
wert--;
printf ("Die Zahl lautet %i", wert);
Als Ausgabe erfolgt in diesem Beispiel: 3 4 3
Die Operatoren stehen hinter der Variablen, d.h. das de- bzw. inkrementieren wird nach der Benutzung der Variablen ausgeführt.
Dieser Vorgang wird als Postinkrement bzw. Postdekrement bezeichnet.
39
C-Programmierung 2003/2004 39
wert=3;
printf ("Die Zahl lautet %i", wert);
++wert;
printf ("Die Zahl lautet %i"; wert);
--wert;
printf ("Die Zahl lautet %i", wert);
Als Ausgabe erfolgt in diesem Fall 3 4 3
In diesem vorliegendem Beispiel erfolgt die Inkrementierung bzw. Dekrementierung vor der Benutzung der Variablen. Dieser Vorgang wird als Präinkrement bzw. Prädekrement bezeichnet.
Warum erfolgt die gleiche Ausgabe, obwohl im ersten Beispiel die Operatoren als Postinkrement/-dekrement und im zweiten Beispiel als Präinkrement/-dekrement angewendet werden ?????
40
C-Programmierung 2003/2004 40
Weil in beiden Programmen die Variablen während dem Inkrementieren / Dekrementieren nicht benutzt wurden. Der Vorgang wurde separat ausgeführt
41
C-Programmierung 2003/2004 41
wert=3;
printf ("Das ist Zahl %i",wert++);
printf ("Das ist Zahl %i",wert--);
printf ("Das ist Zahl %i", wert);
Das Ergebnis lautet: 3 4 3
wert=3;
printf ("Das ist Zahl %i",++wert);
printf ("Das ist Zahl %i",--wert);
printf ("Das ist Zahl %i", wert);
Das Ergebnis lautet: 4 3 3
42
C-Programmierung 2003/2004 42
Fragen:1.) Ist x+=2 gleich x++2 ???
2.) Worin liegt der Vorteil von ++ gegenüber von +=1 ???
Programm 02
Programm 02_2
43
C-Programmierung 2003/2004 43
6. Entscheidungen
Entscheidungen werden benutzt, um den sequentiellen Programmablauf zu verändern.
if (bedingung)
{
}
if zahl==0
{
printf (Achtung Wert nicht gueltig !!!!" \n);
}
erg=zahl01*zahl02;
Abfrage auf Gleichheit erfolgt mit: ==
44
C-Programmierung 2003/2004 44
Der Operator !
In C hat man die Möglichkeit die Aussage einer Bedingung zu negieren, wenn "!" vor die Aussage gesetzt wird.
if (! (wert==100))
{
printf ("Der Wert ist ungleich 100 !!!!!");
}
Besteht der Anweisungsblock hinter einer if Kontrollstruktur nur aus einer Anweisung, so können die geschweiften Klammern weggelassen werden.
45
C-Programmierung 2003/2004 45
Die else-Anweisung
Die else Anweisung ist ein Zusatz zu if und kann auch nur im Zusammenhang damit verwendet werden.
if (a>b)
{
printf ("Die Zahl a ist grösser als die Zahl b");
a=a-b;
}
else
{
print ("Die Zahl a ist nicht grösser als b");
a=b-a;
}
Der else Zweig wird immer dann ausgeführt, wenn die Bedingung nicht erfüllt ist. Ist die Bedingung erfüllt, so wird der gesamte else Zweig ignoriert und es werden nur die Anweisungen (Anweisungsblock) hinter der Bedingung abgearbeitet.
46
C-Programmierung 2003/2004 46
Vergleichsoperatoren
a<b Wahr, wenn a kleiner b
a<=b Wahr, wenn a kleiner gleich b
a>b Wahr, wenn a größer b
a>=b Wahr, wenn a größer gleich b
a==b Wahr, wenn a gleich b
a!=b Wahr, wenn a ungleich b
Achtung:
Unzulässig sind die Operatoren => und =<
47
C-Programmierung 2003/2004 47
Testfragen:
1.) Der if-Anweisungsblock wird nur dann ausgeführt, wenn die Bedingung erfüllt ist? Ja/Nein????
2.) Worin liegt der Unterschied von = und == ?
3.) Worin liegt der Unterschied in den beiden Vergleichen?
(a>b)
(!(a<=b))
48
C-Programmierung 2003/2004 48
#include <stdio.h>
void main(void){int zahl;
printf("Bitte geben Sie eine Zahl ein :");scanf("%i",&zahl);
if(zahl<100){printf("Die Zahl ist kleiner als Hundert.\n");
}if(zahl==100){printf("Hundert war die gesuchte Zahl.\n");}if(zahl>100)printf("Die Zahl ist größer als Hundert.\n");
}
Programm 3.cpp
49
C-Programmierung 2003/2004 49
Behandlung der Bedingung
C behandelt Bedingungen wie einen Wert. Eine Entscheidung kann nur zwei Zustände annehmen, wahr oder falsch. Um die Werte für eine Entscheidung zu erhalten, kann man das folgende Programm nutzen.
#include <stdio.h>
void main(void){int wahr,falsch;
wahr=(3==3);falsch=(2==4);
printf("Der Wert für wahr ist %i\n",wahr);printf("Der Wert für falsch ist %i\n",falsch);
}
Eine Bedingung ist falsch, wenn sie den Wert 0 hat und wahr, wenn sie einen Wert ungleich 0 hat.
Programm 04
50
C-Programmierung 2003/2004 50
Eine Bedingung darf auch in einem berechenbaren Ausdruck stehen. Dabei nimmt sie die Werte 0 und 1 an, 0 bei falsch und 1 bei wahr.
Eine Bedingung ist falsch, wenn sie den Wert 0 hat.
Abfrage auf ungleich Null kann wie folgt realisiert werden:
if (x)
{
}
Der Anweisungsblock hinter if wird dann ausgeführt, wenn x ungleich null ist. Das ergibt sich daraus, dass alle Werte ungleich Null für C "wahr" sind.
51
C-Programmierung 2003/2004 51
Die Abfrage auf gleich Null kann damit durch folgende
Anweisung realisiert werden.
Das man mit Bedingungen rechnen kann, das wurde im
Beispielprogramm bereits bewiesen.
if (!x)
{
}
Programm 6.cpp
52
C-Programmierung 2003/2004 52
7. Gültigkeitsbereiche von Variablen
Lokale Variablen
Eine Variable, die innerhalb eines Anweisungsblocks definiert ist, hat nur lokal in diesem Block ihre Gültigkeit.
#include <stdio.h>
void aendern(void){
x=10;}
void main(void){int x=4;
printf("x = %i\n",x);
aendern();
printf("x = %i\n",x);}
Fehler beim compilieren, Variable x ist nicht definiert
53
C-Programmierung 2003/2004 53
Wird ein Anweisungsblock verlassen, werden alle Variablen, die in ihm definiert wurden, gelöscht.
Gibt es mehrere Variablen mit gleichem Namen, so spricht man immer die lokalste Variable an.
Kann man Variablen auch noch lokaler als im Beispiel auf der
vorherigen Seite definieren? ?
54
C-Programmierung 2003/2004 54
#include <stdio.h>
void main(void){int wert;
printf("Bitte Zahl eingeben :");scanf("%i",&wert);if(wert<=20){int quadrat;
quadrat=wert*wert;printf("Das Qudrat von %i ist %i\n",wert,quadrat);}printf("Quadrat hat den Wert %i",quadrat);
}
Variable quadrat ist innerhalb des if-Blocks definiert und nur dort gültig
Fehler beim compilieren, da Variable quadrat nicht definiert ist !!!!
Lokale Variablendefinitionen müssen immer die ersten Anweisungen des Blockes sein, in dem sie stehen !!!
55
C-Programmierung 2003/2004 55
Globale Variablen
#include <stdio.h>
int x=4;
void aendern(void){
x=10;}
void main(void){
printf("x = %i\n",x);
aendern();
printf("x = %i\n",x);}
Die Variable x ist als globale Variable definiert
Variablen, die außerhalb einer Funktion definiert werden, sind global und können somit in jeder Funktion benutzt werden.
56
C-Programmierung 2003/2004 56
#include <stdio.h>
int a,b;
void aendern(void){int a;
a=0;if(a==0)
{ int a=20;printf("a=%i\n",a);
}printf("a=%i\n",a);
}void main(void){a=b=10;
printf("a=%i und b=%i\n",a,b);aendern();printf("a=%i und b=%i\n",a,b);
}
Globale und lokale Variablen können in einem Programm zusammen genutzt werden. Dabei sind gleiche Namen durchaus erlaubt.
Variable a und b global definiert
Variable a lokal definiert
57
C-Programmierung 2003/2004 57
Wenn eine lokale Variable definiert wurde, dann ist es nicht möglich auf globale Variablen gleichen Namens zuzugreifen. Dies ist erst in C++ möglich.
void main(void)
{
int a;
int a;
a=10;
}
Es dürfen nicht zwei Variablen mit gleichem Namen und dem gleichen Gültigkeitsbereich definiert werden
Achtung
Bei der Definition von Variablen gilt folgender Grundsatz
So lokal wie möglich, so global wie nötig.
Globale Variablen erleichtern das Programmieren ungemein, da man in jeder Funktion auf alle Variablen ungehindert zugreifen kann. Für eine modulare Programmierung sollten globale Variablen jedoch vermieden werden. Sie sollten nur dann verwendet werden, wenn es keine andere Möglichkeit in der Programm-realisierung gibt.
58
C-Programmierung 2003/2004 58
Statische Variablen
Statische Variablen sind eine Mischung aus globalen und lokalen Variablen. Sie werden beim Verlassen ihres Gültigkeitsbereiches nicht gelöscht, sondern behalten ihren Wert.
#include <stdio.h>void test(void){int a=1;
printf("a=%i\n",a); a++;}void main(void){
test();test();test();
}
Was wird in diesem Programm ausgegeben ? ?1 1 1
59
C-Programmierung 2003/2004 59
#include <stdio.h>void test(void){static int a=1;
printf("a=%i\n",a);a++;
}void main(void){
test();test();test();
}
Definition von a als statische Variable
Was wird im Testprogramm ausgegeben? ?1 2 3
Statische Variablen müssen bei ihrer Definition immer initialisiert werden.
Wenn eine Variable als statisch definiert wurde, ist sie immer noch lokal, d.h. im Testprogramm kann in der main-Funktion nicht auf a zugegriffen werden. Nach Verlassen des Gültigkeitsbereiches bleibt jedoch der Wert der Variablen a erhalten.
60
C-Programmierung 2003/2004 60
#include <stdio.h>void test(void){static int a;
a=1;printf("a=%i\n",a);
a++;}void main(void){
test();test();test();
}
Was wird im Programm ausgegeben? ?1 1 1
Im Programmbeispiel wurde die statische Variable bei ihrer Definition nicht initialisiert. Aus diesem Grund wird bei jedem Aufruf von test immer a=1 zugewiesen. Die Variable hat damit in jedem printf den Wert 1.
Programm 05
61
C-Programmierung 2003/2004 61
8. Funktionen mit Parameterübergabe
Funktionen können Werte übergeben werden. Das void vor der Klammer des Funktionsnamens bedeutet, dass die Funktion keinen Wert zurückliefert. Das void in der Klammer nach dem Funktionsaufruf bedeutet, das der Funktion kein Wert übergeben wird.
Funktionsparameter sind lokale Variablen der Funktion, die mit der Übergabe initialisiert werden.
8.1 Parameterübergabe
62
C-Programmierung 2003/2004 62
Parameterübergabe an quadrat
#include <stdio.h> /*Programm 07 */
void quadrat (int x){int ergebnis;
ergebnis=x*x;printf("Das Quadrat von %i",x);printf (" ist %i\n",ergebnis);
}
void main(void){int wert;
printf("bitte geben Sie eine Zahl ein: ");scanf("%i",&wert);
quadrat(wert);}
Wert wird an die Funktion übergeben
63
C-Programmierung 2003/2004 63
Im Beispiel hat int x den Platz von void eingenommen, d.h. die Funktion quadrat bekommt einen int Wert übergeben. Die Variable x bekommt diesen Wert zugewiesen und kann wie jeden andere Variable in der Funktion genutzt werden.
Achtung! Mit der Übergabe des Wertes an die Funktion ist die Variable x initialisiert.
In der Hauptfunktion main wird die Funktion quadrat aufgerufen. Im Funktionsaufruf wird wert an die Funktion übergeben und damit die Variable x in der Funktion quadratinitialisiert.
Funktionsparameter verhalten sich wie lokale Variablen, d.h. Innerhalb der Funktion kann diese Variable geändert werden, ohne das sich die Variable in der übergeordneten Funktion ändert (Gültigkeitsbereich lokaler Variablen).
64
C-Programmierung 2003/2004 64
8.2 Wertrückgabe
#include <stdio.h> /* Programm 8 */
int quadrat (int x){int ergebnis;
ergebnis=x*x;return(ergebnis);
}void main(void){int wert,qwert;
printf("bitte geben Sie eine Zahl ein: ");scanf("%i",&wert);printf ("\n\n\n");qwert=quadrat(wert);
printf("Das Quadrat von %i ist %i\n\n\n",wert,qwert);}
Funktion quadrat
Das int vor dem Funktionsname bedeutet, daßein int Wert zurückgegeben wird
Rückgabewert
Funktionsaufruf
Funktionen, die einen Wert zurückliefern, repräsentieren diesen Wert mit dem Aufruf.
65
C-Programmierung 2003/2004 65
Soll eine Funktion einen Wert zurückgeben, dann erfolgt dies mit "return".
Funktionen werden mit "return beendet, wenn ein Wert in die übergeordnete Funktion übergeben werden soll. Die Klammern hinter return sind nicht zwingend, erhöhen aber die Übersichtlichkeit in Programm.
An den Stellen, wo im C-Programm eine Variable steht, kann auch ein berechenbarer Ausdruck stehen.
#include <stdio.h>int quadrat (int x){
return(x*x);}void main(void){int wert,qwert;printf("bitte geben Sie eine Zahl ein:");scanf("%i",&wert);qwert=quadrat(wert);printf("Das Quadrat von %i ist %i\n",wert,qwert);}
Die Berechnung erfolgt direkt in return, die Variable quadratwird nicht benötigt
66
C-Programmierung 2003/2004 66
Der Funktionsaufruf repräsentiert direkt den Wert, den die Funktion liefert. Damit kann man das Testprogramm weiter vereinfachen.
#include <stdio.h>int quadrat (int x){
return(x*x);}void main(void){int wert,qwert;printf("bitte geben Sie eine Zahl ein:");scanf("%i",&wert);qwert=quadrat(wert);printf("Das Quadrat von %i ist %i\n",wert,quadrat(wert));}
Funktionsaufruf ist direkt in die printf-Anweisung integriert
Wird der Rückgabewert einer Funktion nicht angegeben, geht der Compiler davon aus, dass ein int-Wert zurückgegeben wird.
Kann entfallen
67
C-Programmierung 2003/2004 67
Wie würde das Programm aussehen, wenn die eben besprochene Tatsache zur Anwendung kommt???
Test#include <stdio.h> /*Programm 9 */quadrat (int x){
return(x*x);}void main(void){int wert;printf("bitte geben Sie eine Zahl ein:");scanf("%i",&wert);printf("Das Quadrat von %i ist %i\n",wert,quadrat(wert));}
Das int vor der Funktion kann weggelassen werden
68
C-Programmierung 2003/2004 68
8.3 Übergabe mehrerer Parameter
Eine Funktion kann nur einen Wert zurückgeben (auf diese Art und Weise). Es können aber beliebig viele Werte an die Funktion übergeben werden.
#include <stdio.h>int max(int a, int b){int maxwert;
if(a>b){maxwert=a;}
else{maxwert=b;}
return(maxwert);}void main(void){int zahl1,zahl2;
printf("Bitte geben Sie Zahl 1 ein:");scanf("%i",&zahl1);printf("Bitte geben Sie Zahl 2 ein:");scanf("%i",&zahl2);printf("Die größere Zahl ist %i\n", max(zahl1,zahl2));
}
Was realisiert dieses Programm?????
69
C-Programmierung 2003/2004 69
8.4 Prototypen parametrisierter Funktionen
Wann ist ein Prototyp für eine Funktion erforderlich? ?Ein Prototyp für eine Funktion ist dann erforderlich, wenn die Funktion hinter die main-Funktion platziert wird!
Wird ein Prototyp einer Funktion benutzt, so müssen nur die Variablentypen der Funktionsparameter angegeben werden, nicht die Variablennamen.
int funktion(int x, int y)
{
x=((x+9)*12)/y
}
int funktion (int, int); Funktion als Prototyp
!
70
C-Programmierung 2003/2004 70
8.5 sonstiges bei Funktionen mit Parameterübergabe
Funktionen, die einen Wert zurückgeben, müssen immer mit return beendet werden. !
Ist das folgendem Programmausschnitt richtig?
int testfkt (int x)
{ if (x==20)
return (x+12);
}
Der Compiler wird einen Fehler melden, da die Funktion einen Rückgabewert hat und return aber nur ausgeführt ´wird, wenn x=20 ist. Ist x ungleich 20, so wird die Funktion beendet und es wird kein Rückgabewert geliefert.
Wie muss die Funktion richtig lauten ????
71
C-Programmierung 2003/2004 71
int testfkt (int x)
{ if (x==20)
return (x+12); else { return (x*x) };
}
72
C-Programmierung 2003/2004 72
9. Die for-Schleife
Aufgabenstellung:
Ausgabe der Zahlen von 1 bis 100 am Bildschirm.
1. Möglichkeit 100 printf-Anweisungen
2. Möglichkeit mit einer Schleife und einer printf-Anweisung
Syntax der for-Schleife
for (anweisung1 ; bedingung ; anweisung2)
{ anweisungsblock
}
73
C-Programmierung 2003/2004 73
for (anweisung1 ; bedingung ; anweisung2)
{ anweisungsblock}
Anweisung1
Bedingung wahr? Anweisungs-block
Anweisung2nein
ja
74
C-Programmierung 2003/2004 74
Reihenfolge der Abarbeitung der for-Scheife
1. Anweisung1 ausführen
2. Bedingung prüfen, wenn wahr, dann weiter mit Pkt.3,
sonst bei Pkt.6
3. Anweisungsblock hinter for ausführen
4. Anweisung2 ausführen
5. Weiter bei Pkt.2
6. Zur ersten Anweisung hinter den Anweisungsblock der
for-Anweisung springen
75
C-Programmierung 2003/2004 75
#include <stdio.h>
void main(void){int x;
for(x=1; x<=3; x++){printf("Aktueller Wert :%i\n",x);}
}
Anweisung1 bedingung anweisung2
anweisungsblock
Programm 10
76
C-Programmierung 2003/2004 76
An jeder Stelle der for Anweisung, an der eine Variable steht, kann auch ein berechenbarer Ausdruck stehen.
Innerhalb einer for Anweisung können auch mehrere Anweisungen stehen. Diese sind dann durch Komma zu trennen.
#include <stdio.h>
void main(void){int x,y,zahl1,zahl2;
printf("Bitte Zahl x eingeben :");scanf("%i",&zahl1);printf("Bitte Zahl y eingeben :");scanf("%i",&zahl2);
for(x=1,y=zahl2; x<=zahl1; x++,y--)printf("Aktuelle Werte :%i und %i\n",x,y);
}
Was realisiert das Programm ??? ?
Programm 11
77
C-Programmierung 2003/2004 77
Initialisierungen weglassen
In for Schleifen kann man auf Initialisierung von Variablen teilweise verzichten. Es ist jedoch aus Gründen der Übersichtlichkeit und Lesbarkeit des Programms nicht immer zu empfehlen.
#include <stdio.h> Programm 11_04
void main(void){int x;
printf("Bitte Zahl eingeben :");scanf("%i",&x);
for(; x ; x--)printf("Aktueller Wert :%i\n",x);
}
An der Stelle der Bedingung steht x, das heißt, solange der wert von x ungleich Null ist, gilt die Bedingung als wahr.
78
C-Programmierung 2003/2004 78
10. Schleifen mit Ein-/Austrittsbedingungen
10.1Schleifen mit Eintrittsbedingung
Die Schleife in C mit Eintrittsbedingung ist die while-Schleife. Syntax:
while (bedingung)
{anweisungsblock
}
Bedingung wahr? anweisungsblockja
nein
79
C-Programmierung 2003/2004 79
Ist die Bedingung wahr, dann wird der Anweisungsblock hinter while ausgeführt. Anschließend wird die Bedingung erneut geprüft. Der Anweisungsblock wird solange ausgeführt, bis die Bedingung falsch ist. Dann wird die while Schleife verlassen und das Programm fortgesetzt.
#include <stdio.h> Programm 11-01
void main(void){int zahl;
zahl=0;
while(zahl!=200){printf("Bitte geben Sie 200 ein:");scanf("%i",&zahl);}
}
Was realisiert dieses Programm??
80
C-Programmierung 2003/2004 80
Auch bei der while Anweisung gilt, daß die Klammern entfallen, wenn es sich nur um eine Anweisung im Anweisungsblock handelt
Eine while-Schleife ist als eine vereinfachte Form von for zu betrachten. Aus diesen Gründen kann auch eine for-Schleife mit while simulieren.
for (x=5;x<=25;x++)
printf ("Der Wert betraegt %i\n",x);
x=5;
while (x<=25)
{ printf ("Der Wert betraegt %i\n",x);
x++;
}
81
C-Programmierung 2003/2004 81
Wenn man das obige Beispiel betrachtet, so kann man feststellen, dass die Lösung mit for viel einfacher erscheint. Warum also while benutzen?
Die while Schleife wird für spezielle Probleme genutzt, z.B. wenn auf ein bestimmtes Ereignis gewartet wird (Syntaxprüfung bei der Eingabe von Daten/Wertebereich).
In diesem Fall eignet sich die while Schleife auf Grund ihrer einfachen Konstruktion sehr gut.
In einigen Anwendungsfällen kann man sogar auf den Anweisungsblock verzichten.
#include <stdio.h> // Programm 11-02int getzahl(void){ int zahl;
printf("Bitte geben Sie eine Zahl ein:");scanf("%i",&zahl);return(zahl);
}void main(void){
while(getzahl()!=200);}
82
C-Programmierung 2003/2004 82
10.2 Schleifen mit Austrittsbedingung: do while
Bei while wird erst der Vergleich durchgeführt, d.h. der Anweisungsblock wird nach dem Vergleich abgearbeitet oder bei falscher Bedingung nicht abgearbeitet.
Bei Benutzung von do while wird erst der Anweisungs-block abgearbeitet und danach die Bedingung geprüft.
Problem wird bei der Eingabe mit Syntaxprüfung benutzt. Um zu prüfen, ob eine eingegebene Zahl eine gewisse Bedingung erfüllt, muß ich sie zuerst einlesen und danach prüfen. Das bedeutet, der Anweisungsblock muß erst abgearbeitet werden und danach wird erst die Bedingung geprüft.
Syntax:
do
{ anweisungsblock
}
while (Bedingung);
83
C-Programmierung 2003/2004 83
Die do while Sckleife wird wie folgt abgearbeitet:
(1) Abarbeitung des Anweisungsblockes zuwischen do und while
(2) prüfen der Bedingung
(3) bei wahr wird zu do gesprungen und der Anweisungsblock
erneut abgearbeitet (1)
(4) ist die Bedingung nicht erfüllt (falsch), so fährt das Pro-
gramm hinter while fort
nein
jaBedingung wahr?
Anweisungs-Block
84
C-Programmierung 2003/2004 84
Die while Abfrage in der do while Konstruktion wird immer mit einem Semikolon abgeschlossen.
Das Programm von Seite 79 könnte mit einer do while Konstruktion wie folgt aussehen:
#include <stdio.h>void main(void){int zahl;
do{printf("Bitte geben Sie 200 ein:");scanf("%i",&zahl);}
while(zahl!=200);}
In C gibt es eine spezielle Anweisung, welche nur innerhalb von Schleifen benutzt werden kann. Das heißt nur innerhalb von for, while oder do while. Das ist die continue Anweisung.
Keine Anfangsinitialisierung
von „zahl“ notwendig
Programm 11_03
„Eingabeprüfung“
85
C-Programmierung 2003/2004 85
10.3 Continue-Anweisung
x=0;
while (x<20)
{
x++
if (x==10)
continue;
printf ("x=%i\n",x);
}
Continue springt immer an den Anfang der innersten Schleife!!
Programm 991
86
C-Programmierung 2003/2004 86
Beginn
x=0
solangeX<20
x=x+1
x==10
nein
ja
In diesem Fall tritt die continue
Anweisung in Aktion
1
1
Ausgabe von x
Schleifenende
Ende
87
C-Programmierung 2003/2004 87
Welche Auswirkung hat while (1) auf den Programmablauf? ?Die Bedingung while ist immer wahr, d.h. es ist eine Endlosschleife
88
C-Programmierung 2003/2004 88
11. Logische Operatoren
Der logische Operator &&
Der logische Operator && wir als UND oder AND-Operator bezeichnet. Er verknüpft zwei Bedingungen auf folgende Weise.
Bedingung1 Bedingung2 Bedingung1 && Bedingung2
falsch falsch falsch
falsch wahr falsch
wahr falsch falsch
wahr wahr wahr
89
C-Programmierung 2003/2004 89
if ((x>=20) && (x<=40))
{ anweisungsblock
}
Der Anweisungsblock hinter if wird nur abgearbeitet, wenn
X größer gleich 20 und kleiner gleich 40 ist ?Achtung!!Der && Operator ist kommutativ, das heißt
x && y ist gleichbedeutend mit y && x
90
C-Programmierung 2003/2004 90
Bedingung1 Bedingung2 Bedingung1 || Bedingung2
falsch falsch falsch
falsch wahr wahr
wahr falsch wahr
wahr wahr wahr
Der logische Operator ||
Der logische Operator || wird auch als ODER bzw. OR Operator bezeichnet. Er realisiert folgende Verknüpfungen.
Achtung!!!Der || Operator entspricht nicht dem gebräuchlichem ODER, er bedeutet,
dies oder jenes oder beides !Der || Operator ist ebenfalls kummutativ. Daraus folgt, dass
a || b gleichbedeutend mit b|| a ist
91
C-Programmierung 2003/2004 91
Der && Operator und der || Operator können auch gemeinsam innerhalb eines Ausdruckes auftreten.
do
{
printf ("Bitte eine Zahl im Bereich von 20 bis\ 40 eingeben oder eine 0 für\Ende der Eingabe");
scanf ("%i", &wert);
}
while (((wert<20) || (wert>40)) && (wert !=0));
Die Schleife wird beendet, wenn der Wert zwischen 20 und 40 liegt oder wenn eine 0 eingegeben wird.
Das heißt, wenn der Wert kleiner als 20 oder größer als 40 ist und ungleich Null ist, dann wird wieder zu do gesprungen.Alle Werte zwischen 20 und 40 du die Null sind gültig!!!!
Programm 12
92
C-Programmierung 2003/2004 92
10 wahr || falsch = wahr wahr && wahr = wahr
in Schleife verbleiben!!!
30 falsch || falsch= falsch falsch && wahr = falsch
Schleife verlassen
0 wahr || falsch = wahr wahr && falsch = falsch
Schleife wird verlassen
93
C-Programmierung 2003/2004 93
12. Variablen vom Typ float
Float-Point Variablen stehen in 3 verschiedenen Varianten zur Verfügung.
Typ Größe Mindestgenauigkeit Formatzeichen
float 4 6 f
double 8 10 f
long double 10 10 lf
Die Größe gibt die Byte an, die von einer Variablen belegt werden. Die Mindestgenauigkeit ist die Anzahl der Stellen hinter dem Komma. Alle Variablen decken einen Wertebereich von mindestens 1038 bis 10-38 ab. Es gibt in C keine vorzeichenlosen Gleitkommazahlen.
Diese Genauigkeit der Gleitkommazahlen ist ausreichend für die meisten Operationen, auch im mathematischen Bereich. Man sollte sich jedoch immer genau den Einsatz von Gleitkommazahlen überlegen, da diese Operationen rechenintensiver und speicher-intensiver als int Variablen sind
94
C-Programmierung 2003/2004 94
#include <stdio.h>void main(void){unsigned long n=3,max;//unsigned long 4 Byte 0 bis 4.294.967.295
float pi=1.0;printf("Bis zu welchem n soll gerechnet werden:");scanf("%li",&max);while(n<max)
{pi=pi-(1.0/n)+(1.0/(n+2));n+=4;printf("n=%lu :%f\n",n,pi*4.0);
}}Dieses Programm realisiert die Berechnung der Zahl pi nach dem Verfahren von Leibnitz.
pi=(1-1/3+1/5-1/7+1/9-1/11+1/13-1/15+1/17-1/19+1/21-.......)*4
Gleitkommazahlen verhalten sich in Operationen genau wie Ganze Zahlen. Es muss nur eine andere Deklaration und ein anderes Formatzeichen benutzt werden.
Programm 13
95
C-Programmierung 2003/2004 95
Werden zwei Variablen unterschiedlichen Typs durch einen Operator verknüpft, so bekommt das Ergebnis den genaueren Typ der beiden Variablen.
1/n ist immer 0, wenn n>1 und eine int Variable.
1.0/n bekommt als Ergebnis den Wert einer Gleitkommzahl, da 1.0 als Gleitkommazahl interpretiert wird.
Typumwandlung mit dem cast-Operator
Mit dem cast Operator kann der Programmierer den Typ des Ergebnisses selbst bestimmen. Mit cast wird eine Typumwandlung realisiert.
Syntax des cast Operators:
(typ) (variable)
96
C-Programmierung 2003/2004 96
int a=3, b=2; /* Beispiel-1
float c;
c=a/b;
Als Ergebnis hat c den Wert 1, da erst die Division mit int-Variablen durchgeführt wird. Erst danach erfolgt die Anpassung an das float Format.
int a=3, b=2; / /Beispiel-2
float c;
c=(float) (a) / (float) (b);
Im zweiten Beispiel wird der cast Operator verwendet. Damit erfolgt erst die Anpassung an das float Format und danach die Division. Damit lautet das Ergebnis 1,5.
int a=3, b=2; /* Beispiel-3
float c;
c=(float) a / (float) b;
97
C-Programmierung 2003/2004 97
Auch wenn die Klammern nicht geschrieben sind, erfolgt erst die Typumwandlung und danach die Division. Die Ursache liegt darin, dass der cast Operator eine stärkere Bindung hat als die Division. Deshalb erfolgt erst die Umwandlung und dann die Division
98
C-Programmierung 2003/2004 98
Die Funktionen von math.h
In der Bibliothek math.h sind die wesentlichsten mathematischen Funktionen enthalten. Werden diese be-nötigt, so ist diese Bibliothek am anfang des Programms anzuhänhen.
#include <math.h>
acos Umkehrfunktion des Kosinus
asin Umkehrfunktion des Sinus
atan Umkehrfunktion des Tangens
ceil grundsätzliches aufrunden
cos Kosinus
cosh Kosinus Hyperolicus
exp Exponentialfunktion (e hoch a)
fabs Absolutwert von |a|
floor grundsätzliches abrunden
99
C-Programmierung 2003/2004 99
fmod Modulowert (a%b)
frexp Aufspalten von a in a=f*2i
ldexp Umkehrung zu frexp
log nathürlicher Logarithmus (Basis e)
log10 dekadischer Logarithmus (Basis 10)
modf Aufspaltung von a in a=f+i
pow Potenz a hoch b
sin Sinus
sinh Sinus Hyperbolicus
sqrt Quadratwurzel
tan Tangens
tanh Tangens Hyperbolicus
100
C-Programmierung 2003/2004 100
Beschreibung ausgewählter Funktionen
sqrt
double sqrt (double a);
Berechnet die Quadratwurzel von a
#include "stdio.h"#include "math.h"void main (void){double zahl=4.3456, ergebnis;printf ("Eingabe einer Zahl: ");//scanf ("%lf",&zahl); Probleme bei %f und double zahlergebnis=sqrt(zahl);
printf ("Ergebnis von Quadratwurzel aus %f ist: %f \n",zahl,ergebnis);}
101
C-Programmierung 2003/2004 101
tandouble tan (double a);Berechnet den Tangens von a im Bogenmaß.
sindouble sin (double a);Berechnet den Sinus von a im Bogenmaß.
ceil
double ceil (double a)
Liefert die nächst höhere Ganzzahl von a.
z.B aus 6.4 wird 7, aus -3.1 wird -3
102
C-Programmierung 2003/2004 102
acos
double acos (double a);
Berechnung Arcus Kosinus (Umkehrfunktion von Kosinus) im Wertebereich -1 bis 1
fabs
double fabs (double a)
Liefert den Betrag oder Absolutwert von a ( |a| )
floor
double floor (double a)
Liefert die nächstniedrige Ganzzahl
103
C-Programmierung 2003/2004 103
FZ Typ Zahlensystem Besonderheit
f double Dezimal *.*****
Lf long double Dezimal *.*****
e double Dezimal *.***E**
Le long double Dezimal *.***E**
E double Dezimal *.***E**
LE long double Dezimal *.***E*
g double Dezimal mit oder ohne Exponent
Lg long double Dezimal mit oder ohne Exponent
G double Dezimal mit oder ohne Exponent
LG long double Dezimal mit oder ohne Exponent
Formatzeichen Gleitkommazahlen
104
C-Programmierung 2003/2004 104
Erweiterte Formatierung der Ausgabe
printf ("%.2f\n",1234.3456) .2
Legt fest, daß zwei Stellen nach dem Komma ausgegeben werden.
printf ("%15.2f\n",1223.34345); 15.2
Diese Anweisung setzt 8 Leerzeichen vor die Zahl. Die Zahl selbst ist 17 Stellen lang (geplanter Wert) die auszugebende Zahl ist im Original 9 Stellen. 17 - 9 =8 ---> 8 Leerstellen.
105
C-Programmierung 2003/2004 105
printf ("%-15.2f\n",1223.34345); -15.2
Zahl wird linksbündig ausgegeben.
printf ("%+15.2f\n",1223.34345); +15.2
Zahl wird immer als positive Zahl ausgegeben.
Programm 14
Programm 14_01
106
C-Programmierung 2003/2004 106
13. Fallunterscheidungen
Gibt es zu einem Entscheidung mehrere Möhlichkeiten der Entscheidung, so müssen verschachtelte if Anweisungen oder die case-Anweisung genutzt werden.
Syntax:
switch (variable)
{
case 1:
case 12:
case -9:
}
Die Variable dient in dieser Anweisung als Schalter. Hat die Variable den entsprechenden Wert, so wird die zugehörige case Anweisung angesprungen. Hinter der Sprungmarke case muß immer eine ganzzahlige Konstante stehen.Wird eine case Marke angesprungen, so werden alle danach folgenden case Anweisungen mit abgearbeitet. Wird keine Übereinstimmung mit den Konstanten erzielt, so passiert nicht. Das Programm wird fortgesetzt.
107
C-Programmierung 2003/2004 107
Sollen nach dem Ansprung einer case Marke die anderen nachfolgenden CaseAnweisungen nicht abgearbeitet werden, so muß break verwendet werden.
Break springt immer hinter die innerste for, switch oder while Anweisung.
Beginn
case 1 ?
case 2 ?
case 3 ?
ja
ja
ja
Ausgabe 1
Ausgabe 2
Ausgabe 3
nein
nein
nein
Ende
Switch/case ohne break
108
C-Programmierung 2003/2004 108
Beginn
case 1 ?
case 2 ?
case 3 ?
ja
ja
ja
Ausgabe 1
Ausgabe 2
Ausgabe 3
nein
nein
nein
Ende
Switch/case mit break
109
C-Programmierung 2003/2004 109
#include <stdio.h> /*Programm 15 */
void main(void){int x;
printf("Geben Sie bitte 1,2 oder 3 an:");scanf("%i",&x);switch(x)
{case 1: printf("Das war Zahl-1-\n");
break;
case 2: printf("Das war Zahl -2-\n");break;
case 3: printf("Das war Zahl -3-\n");break;
}}
110
C-Programmierung 2003/2004 110
Beginn
case 1 ?
case 2 ?
case 3 ?
ja
ja
ja
Ausgabe 2
Ausgabe 3
nein
nein
nein
Ende
Mehrere case Anweisungen mit gleichem Sprungziel
Es können beliebig viele case-Anweisungen das gleiche Sprungziel haben.
111
C-Programmierung 2003/2004 111
switch(x){case 1:case 2: printf("Das war Zahl 2 oder 1 \n");
break;case 3: printf("Das war Zahl 3 \n");
break;}
Die default-Anweisung
Wenn für einen Wert keine Sprungmarke existiert, dann kann default verwendet werden. Wird also keine Übereinstimmung erzielt, dann wird immer defaultangesprungen. Damit kann der Sachverhalt, dass eine begrenzte Anzahl case-Anweisungen für bestimmte Bedingungen und ein Standard für "sonstiges", abgedeckt werden.
Keine Sprungmarke für einen Wert default (wenn vorhanden)
112
C-Programmierung 2003/2004 112
#include <stdio.h> /*Programm 15-01 */
void main(void){int x;
printf("Geben Sie bitte 1,2 oder 3 an:");scanf("%i",&x);switch(x)
{case 1: printf("Das war Zahl 1 \n");
break;
case 2: printf("Das war Zahl 2 \n");break;
case 3: printf("Das war Zahl 3 \n");break;
default: printf("ungültige Eingabe \n");break;
}}
113
C-Programmierung 2003/2004 113
14. Der Variablentyp charDer Variablentyp char gestattet es, mit einzelnen Zeichen zu arbeiten.
char x;
printf ("Bitte ein Zeichen eingeben");
scanf ("%c",&x);
printf ("Das eingegebene Zeichen lautet >%c< \n",x);
Das Formatzeichen ist %c
Wertebereich von 0-255 (ASCII)
Eine Wertzuweisung (Initialisierung) einer char-Variablen erfolgt mit:
char x ; x='F'; Achtung: Wertzuweisung immer in einfachen Anführungszeichen!!!!!
114
C-Programmierung 2003/2004 114
Der Variablentyp char ist fast identisch mit unsigned short.
Man kann char somit auch wie ganzzahlige Variablen behandeln.
x='F';
printf ("Der Wert von %c ist %i",x,x);
int x;
for (x=0;x<256;x++)
printf ("Das Zeichen ist \"%c\", der Wert ist %i \n",x,x); ?int x; x=24+'B';
switch (x)
{
case 'a': printf (" Ein kleines a\n");
break;
case 'b': printf ("Ein kleines b\n");
break;
}
Programm 15_02
ASCII Tabelle Teil-1
ASCII Tabelle Teil-2
115
C-Programmierung 2003/2004 115
Die Funktionen von ctype.h
isalnum wahr für einen Buchstaben oder eine Zahl
isalpha wahr für einen Buchstaben
iscntrl wahr für ein bestimmtes Steuerzeichen
isdigit wahr für eine dezimale Ziffer
isgraph wahr für darstellbare Zeichen außer Leerzeichen
islower wahr für Kleinbuchstaben
isprint wahr für darstellbare Zeichen incl. Leerzeichen
isupper wahr für Großbuchstaben
isxdigit wahr für eine Hexadezimalzahl
116
C-Programmierung 2003/2004 116
#include <stdio.h> /*Programm 15-03 */#include <ctype.h>void main(void){char x; printf("Bitte Zeichen eingeben:");
scanf("%c",&x);if(isdigit(x)){printf("Es war eine dezimale Ziffer!\n");}else{printf("Das Zeichen war keine Ziffer\n");}
}
117
C-Programmierung 2003/2004 117
Die Headerdatei ctype.h stellt außerdem noch zwei Umwandlungsfunktionen zur Verfügung.
tolower Umwandlung in Kleinbuchstaben
toupper Umwandlung in Großbuchstaben
Bei Eingaben sind diese Funktionen sehr gut zu benutzen. Soll z.B. der Buchstabe c eingegeben werden, dann sollte es egal sein, ob der Nutzer ein kleines c oder ein großes C eingibt.
Die Funktionen wandeln nur, wenn es etwas zum um-wandeln gibt, sonst wird das gleiche Zeichen zurückgegeben.
x=tolower(x);
Die Variable x wird nur verändert, wenn der Wert von x ein Großbuchstabe ist. Dann wandelt tolower ihn in den entsprechenden Kleinbuchstaben um. Ist es bereits ein Kleinbuchstabe, dann hat tolower keine Bedeutung.
118
C-Programmierung 2003/2004 118
isalnum
int isalnum (int a);
Liefert einen wahren Wert, wenn a ein Zeichen aus folgendem Wertevorrat ist: a-z, A-Z, 0-9
Erläuterungen der einzelnen Funktionen
isalpha
int isalpha (int a);
Liefert einen wahren Wert, wenn a ein Zeichen aus den folgenden wertevorrat ist: a-z, A-Z oder landesspezifische Zeichen (in Deutschland äöüÄÖÜß)
iscntrl
int iscntrl (int a);
Liefert einen wahren Wert, wenn a eins der folgenden Steuerzeichen ist: FF, NL, CR, HAT, VT, BEL oder BS
119
C-Programmierung 2003/2004 119
isdigit
int isdigit (int a);
Liefert einen wahren Wert, wenn a eine Ziffer von 0-9 ist.
isgraph
int isgraph (int a);
Liefert einen wahren Wert, wenn a ein darstellbares Zeichen ist, aber kein Leerzeichen.
islower
int islower (int a);
Liefert einen wahren Wert, wenn a ein Zeichen von a-z oder ein umgebungsspezifisches Zeichen ist (Kleinbuchstabe).
isprint
int isprint (int a);
Liefert einen wahren Wert, wenn a ein darstellbares Zeichen ist oder ein Leerzeichen.
120
C-Programmierung 2003/2004 120
ispunct
int ispunct (int a);
Liefert einen wahren Wert, wenn isgraph (a) wahr und isalnum (a) falsch ist.
isspace
int isspace (int a);
Liefert einen wahren Wert, wenn a ein Leerzeichen oder FF, NL, CR, HAT oder VT ist.
isupper
int isupper (int a);
Liefert einen weahren Wert, wenn a ein Zeichen von A-Z ist oder ein umgebungsspezifischer Großbuchstabe.
isxdigit
int isxdigit (int a);
Liefert einen wahren Wert, wenn a ein Zeichen von 0-9, a-f oder A-F ist (hexadezimaler Wertebereich).
121
C-Programmierung 2003/2004 121
tolower
int tolower (int a);
Liefert den Kleinbuchstaben von a, falls a bereits ein Kleinbuchstabe ist, wird dieser unverändert zurückgegeben.
toupper
int toupper (int a);
Liefert den Großbuchstaben von a, falls a bereits ein Großbuchstabe ist, wird dieser unverändert zurückgegeben.
122
C-Programmierung 2003/2004 122
15. Vektoren und Zeiger
Vektoren und Zeiger verhalten sich wie Konstanten und Variable zueinander.
Bei Vektoren handelt es sich um konstante Adressen und bei Zeigern um variable Adressen.
000000002323432A X
412
Wert VariablennameSpeicher-adresse
Eine Variable ist durch folgende 4 Angaben eindeutig identifiziert:
• Adresse (Position)
• Name (Variablenname)
• Inhalt (Wert)
• Größe (belegter Speicherplatz)
123
C-Programmierung 2003/2004 123
Der Adreßoperator &&x liefert nicht den Inhalt der Variablen x, sondern die Adresse der Variablen x.
#include <stdio.h> /* Programm 16 */
void main(void){int x;
x=100;printf("Adresse von x mit dem Wert %i ist %p\n", x, &x);
x=800;printf("Adresse von x mit dem Wert %i ist %p\n", x, &x);
}
Adreßoperator &Formatzeichen für Adressen
Was liefert das Programm für Ausgaben ? ?
124
C-Programmierung 2003/2004 124
Die Adresse einer Variablen bleibt während der Programmabarbeitung immer gleich, auch wenn sich der Inhalt ändert.
Bei jedem Neustart verändert sich die Adresse, da das Programm an einer anderen Stelle im Hauptspeicher steht.
Der Wert, den der Adreßoperator & liefert ist ein Vektor.
Vektoren sind konstante Adressen!
Der Dereferenzierungsoperator *
Eine Variable, welche eine Adresse als Wert beinhaltet, nennt man einen Zeiger.
Syntax für Zeigerdefinitionen:
typ *variablenname
125
C-Programmierung 2003/2004 125
int x, *b;
x=99;
b=&x;
Zeiger auf einen int-Wert
Dem Zeiger wird ein Vektor zugewiesen.
126
C-Programmierung 2003/2004 126
Zeiger speichern Adresse, Variable speichern Werte. !
000BAC32D2FF2A b
000000002323432A
000000002323432A X
412
int x, *b;
x=99;
b=&x;
b ist der Zeiger auf die Variable x
Zeiger auf eine Variable
Dies macht aber Zeiger noch nicht interessant, wesentlich ist, wenn man die Adresse von x in b gespeichert hat, kann man darüber auf x zugreifen.
127
C-Programmierung 2003/2004 127
#include <stdio.h> /* Programm 18 und 18-1 */void main(void){int x,*z;
x=10;printf("x = %i\n", x);z=&x;*z+=10;printf("x = %i\n", x);x+=10;printf("x = %i, dereferenziertes z = %i\n", x, *z);
}
int x, *b; /* Programm 17*/
x=99;
b=&x;
printf ("Adresse von x ist %p, der Wert von b ist %p", &x,b);
Was wird in diesem Beispiel ausgegeben??? ?
128
C-Programmierung 2003/2004 128
Definition der int Variablen x und eines Zeigers z.
Der Variablen x wird der Wert 10 zugewiesen und dieser wird in der folgenden printf-Anweisung ausgegeben.
Danach wird die Adresse von x dem Zeiger z zugwiesen.
Jetzt wird durch eine Dereferenzierung von z (*z) nicht die in z gespeicherte Adresse von x angesprochen, sondern der Wert der an dieser Adresse steht (das ist der Wert von x). Das bedeutet, daß der Wert von x um 10 erhöht wird. In der folgenden printf-Anweisung wird der Wert von x ausgegeben. Dieser ist in diesem Fall 20.
Dann wird x erneut um den Wert von 10erhöht und in der folgenden printf-Anweisung wird x ausgegeben (30) und der dereferenzierte Wert von z, also nochmals 30.
Zeiger können auch direkt bei ihrer Deklaration initialisiert werden.
int x=24;
int *z=&x;
oder
int x=24 , *z=&x;
129
C-Programmierung 2003/2004 129
000000002323432A X
412
000000002323432A X
412
000BAC32D2FF2A b
000000002323432A
000BAC32D2FF2A b
000000002323432A
b
000000002323432A
*b
412
130
C-Programmierung 2003/2004 130
000000002323432A X
412
000BAC32D2FF2A b
000000002323432A
&b
000BAC32D2FF2A
131
C-Programmierung 2003/2004 131
Warum wird bei scanf immer der Adressoperator benutzt? ?scanf ("%i",&a);
Beim Aufruf von scanf wird die Adresse übergeben, wo der einzulesende Wert abgespeichert wird. Innerhalb der Funktion scanf wird dann über eine Dereferenzierungauf die Position (Adresse) zugegriffen wo der einzulesende Wert abgespeichert wird. Würde nicht die Adresse übergeben, dann könnte man nicht auf diese variable Adresse zugreifen, da die Variable innerhalb der Funktion nicht bekannt ist.
132
C-Programmierung 2003/2004 132
15.1 Adressen als Funktionsparameter
In der dargestellten Form werden Zeiger nur selten verwendet, denn es ist einfacher direkt auf die Variablen zuzugreifen als über Zeiger.
Im Zusammenhang mit Funktionen sind aber Zeiger sehr bedeutsam. Hauptsächlich werden Zeiger benutzt, um Adressen an Funktionen zu übergeben. Über diesen Umweg können dann direkt Variablen verändert werden.
#include <stdio.h> /* Programm 19 */void quadrat(int *wert){
*wert=(*wert)*(*wert);}void main(void){int x;
printf("Bitte eine Zahl eingeben:");scanf("%i",&x);quadrat(&x);printf("Das Quadrat ist %i\n",x);
}
Zeiger auf eine Variable wird übergeben
Adresse von x wird übergeben
Programm 19_01
133
C-Programmierung 2003/2004 133
15.2 Zeiger auf Funktionen
Zeiger beinhalten Adressen von Variablen. Es können aber in Zeigern auch Adressen von Funktionen gespeichert sein.
Anwendung: - bei Parameterabhängiger Auswahl von Funktionen
- in der objektorientierten Programmierung
rtype (*fkt) (para1,para2,….)
Syntax: Der Zeiger mit dem Namen fkt zeigt auf die Startadresse einer Funktion, die einen wert vom Typ rtyp zurückgibt und die Parameter para1, para2,… besitzt
Der Funktionszeiger kann nur Adressen von Funktionen aufnehmen, die die gleichen Eingabe-und Ausgabeparameter haben
134
C-Programmierung 2003/2004 134
#include <stdio.h> /* Programm 990 */void ausgabe(void) //Funktion ausgabe{
printf("Bitte geben Sie eine Zahl ein:");}int summe(int a, int b) // Funktion summe{
return(a+b);}
void main(void){int x,y;void (*fkt1)(void);int (*fkt2)(int, int);
fkt1=ausgabe;fkt2=summe;
fkt1();scanf("%i",&x);
(fkt1)();scanf("%i",&y);
printf("Die Summe ist %i\n",fkt2(x,y));}
Der Name einer Funktion ohne Klammern repräsentiert ihre Adresse
Programm 990_1
(Ohne Funktionsadressen)
135
C-Programmierung 2003/2004 135
15.3 Zeiger auf Zeiger
typ **name
Syntax
#include <stdio.h> /* Programm 992 */void main(void){int x,y,*xptr,**ptrptr;
x=10;y=10;printf("x = %i\n",x);
xptr=&x;*xptr=20;printf("x = %i, *xptr = %i\n",x,*xptr);
ptrptr=&xptr;**ptrptr=30;printf("x = %i, *xptr = %i, *ptrptr = %i\n",x,*xptr,**ptrptr);*ptrptr=&y;**ptrptr=40;
printf(„y = %i, x= %i *xptr = %i, *ptrptr = %i\n",y,x,*xptr,**ptrptr);}
136
C-Programmierung 2003/2004 136
Übung !!!Arbeiten mit Adressen;
Übergabe von Adressen an Funktionen;
Übergabe mehrerer Adressen an Funktionen
137
C-Programmierung 2003/2004 137
16. Variablenfelder
Anstelle n Variablen zu definieren (z.B. für eventuelle Sortierungen) kann man ein Feld (array) anlegen, in welchem dann alle Werte gespeichert sind.
Syntax eines Feldes:
typ name[anzahl]
int testfeld[20];
testfeld[3]=12;
testfeld[17]=99;
Felddefinition mit 20 int Werten
Wert 3 des Feldes wird mit 12 initialisiert und Wert 17 mit 99
Der Feldindex beginnt immer mit 0 und reicht bis n-1, bei einem Feld mit n Elementen. !
138
C-Programmierung 2003/2004 138
Ein Feld kann auch gleich bei seiner Definition initialisiert werden.
int testfeld[5]={12,4,5,33,-88};
#include <stdio.h> /*Programm 20 */
void main(void){
int x[10],y;
for(y=0;y<10;y++){printf("Bitte Zahl %i eingeben:",y+1);scanf("%i",&x[y]);}
for(y=0;y<10;y++)printf("%i multipliziert mit 2 ist %i\n",x[y],x[y]*2);
}
139
C-Programmierung 2003/2004 139
Felder als Funktionsparameter
Der Name eines Feldes ohne [...] ist identisch mit der Startadresse des Feldes. Der Feldname ist ein Vektor.
Der Zeiger auf eine Variable ist identisch mit dem Zeiger auf ein Feld.
Bei Zeigern auf Felder darf bei der Benutzung des Index kein Dereferenzierungsoperatorangewendet werden.
140
C-Programmierung 2003/2004 140
#include <stdio.h> /*Programm 21 */void input(int *a){int y;
for(y=0;y<10;y++){printf("bitte Zahl %i angeben:",y+1);scanf("%i",&a[y]);}
}void calc(int *a){int y; for(y=0;y<10;y++)
a[y]*=2;}void output(int *a){int y;
for(y=0;y<10;y++)printf("Das Ergebnis der %i. Multiplikation ist%i\n", y+1,a[y]);
}void main(void){ int x[10];
input(x);calc(x);output(x);
}
141
C-Programmierung 2003/2004 141
Mehrdimensionale Felder
Die bisherigen Felder waren eindimensional. In C ist es aber auch möglich, daßmehrdimensionale Felder aufgebaut werden.
int tabelle[4][10];
Mit dieser Definition wird ein zweidimensionales Feld angelegt, welches 4 Spalten und 10 Zeilen hat. Es kann dann ebenfalls jedes einzelnen Element in der Tabelle initialisiert werden. Soll z.B. in der 2. Spalte und der 8. Zeile eine 5 stehen, dann wird folgende Zuweisung notwendig:
int tabelle[1][7]=5 ?Achtung!!!
Das erste Feldelement beginnt immer mit der Position 0, das heißt, die Feldposition ist immer die reale Position -1.
142
C-Programmierung 2003/2004 142
In C können auch noch mehr Dimensionen benutzt werden.
int dreidimfeld[80][80][80];
Dieses Feld beinhaltet 80x80x80 int-Werte zu je 2 Byte. Es gilt unbedingt zu beachten, dass dieses Feld dann fast 1 MByte Speicher belegt.
Auch mehrdimensionale Felder können sofort bei ihrer Deklaration initialisiert werden. Dabei erfolgt die Initialisierung immer von der letzten Dimension aus.
int tabelle[2][4]={{4,5,6,7},{5,4,3,2}};
2 Spalten 4 Zeilen
1 2
1 4 5
2 5 4
3 6 3
4 7 2
SpalteZeile
143
C-Programmierung 2003/2004 143
Initialisierung eines dreidimensionalen Feldes:
int drei[2][3][4]={{{1,2,3,4},{5,6,7,8},{-2,4,-6,2}},{{12,4,5,33},
{22,33,44,55},{1,2,3,4}}};
Übung !!!Arbeiten mit Feldern;
Übergabe von Feldern an Funktionen;
Felder als Rückgabewert von Funktionen
Verbesserung von Praktikum 1 durch Nutzung von Feldern
144
C-Programmierung 2003/2004 144
Mit beliebigen Variablentypen kann man Felder erzeugen. Das geht auch mit char.
char[51] definiert ein Feld mit 50 Charakter-Werten.
Ein String besteht aus einer Folge von Zeichen und hat eine Endekennung. In C hat die Endekennung immer den Wert 0.
"erg"
Stringkonstante der Länge 4 (3 Zeichen und Endekennung 0)
17. Zeichenketten - String
Ein- und Ausgabe von Strings
Da Strings den Status eines Feldes haben, können sie auch so behandelt werden. Sie werden besonders für E/A-Operationen genutzt.
Das Formatzeichen für Strings ist %s.
145
C-Programmierung 2003/2004 145
#include <stdio.h> /* Programm 22 */void main(void){char a[7];
a[0]='S'; a[1]='t';a[2]='r'; a[3]='i';a[4]='n'; a[5]='g';a[6]=0;printf("Der erzeugte String ist :%s\n",a);
}
#include <stdio.h> /* Programm 23 */
void main(void){int x;char a[7];
a[0]='S'; a[1]='t'; a[2]='r'; a[3]='i';a[4]='n'; a[5]='g'; a[6]=0;
for (x=0;a[x]!=0;x++)printf("%c \n",a[x]);
}
146
C-Programmierung 2003/2004 146
Das Formatzeichen %s für Strings kann auch bei scanf genutzt werden, um ganze Zeichenketten einzulesen.
#include <stdio.h> //Programm 24void main(void){char a[81];printf("Bitte einen max. 80 Zeichen langen text eingeben:");scanf("%s",a);printf("Sie gaben \"%s\" ein.\n",a);}
?
Ein Character-Feld hat eine besondere Stellung. Scanf betrachtet das gesamte Feld als einen Variablentyp, als String.
Vor dem a in scanf fehlt der Adreßoperator &. Das ist richtig, denn ein Feld ohne eckige Klammern repräsentiert bereits die Adresse. Damit muss in der scanf-Anweisung nicht explizit der Adreßoperator angegeben sein, denn a ist bereits die Adresse. Alternativ könnte man auch folgendes schreiben:
scanf ("%s", &a[0]);
Debugger
147
C-Programmierung 2003/2004 147
Die Funktion scanf hat die Eigenschaft, dass mehrere Worte eingelesen werden können, die durch Leerzeichen getrennt sind. Die durch Leerzeichen getrennten Worte werden als mehrere Strings aufgefasst. Um einen String einzulesen, welcher Leerzeichen enthält, kann scanf nicht verwendet werden.
Die Eingabefunktion gets ist speziell für die Arbeit mit strings gedacht.
#include <stdio.h> //Programm25void main(void){char a[81];printf("Bitte einen max. 80 Zeichen langen text eingeben:");
gets(a);
printf("Sie gaben \"%s\" ein.\n",a);}
Die Funktion gets ist als Prototyp ebenfalls in der Headerdatei stdio.h enthalten. Für deren Benutzung ist also ebenfalls ein #include stdio.h notwendig.
Der Funktion gets wird die Adresse des Strings übergeben, damit diese den String überschreiben kann.
148
C-Programmierung 2003/2004 148
Analog zur Funktion gets gibt es auch eine Ausgabefunktion puts, welche einen String ausgibt. Auch diese Funktion steht als Prototyp in der Headerdatei stdio.h.
puts ("Das ist ein Text mit puts ausgegeben.\n");
Ein String darf mit Endekennung nur gleich oder kleiner als das definierte Feld sein, niemals größer!
149
C-Programmierung 2003/2004 149
Die Funktionen von string.h
memchr Zeichen im Speicherblock suchen
memcmp Speicherblöcke vergleichen
memcpy Speicherblöcke kopieren
memmove Sicheres kopieren von Speicherblöcken
memset Speicherblöcke initialisieren
strcat String an einen anderen hängen
strchr Zeichen im String suchen
strcmp Zwei Strings vergleichen
strcoll Zwei Strings umgebungsunabhängig ver-
gleichen
strcpy String kopieren
strerror Umwandlung eines Feldes in verbale Form
strlen Länge eines String ermitteln
150
C-Programmierung 2003/2004 150
strncat Teil eines String an einen anderen hängen
strncmp Teile von zwei Strings vergleichen
strncpy Teile eines String kopieren
strrchr Zeichen von Stringende aus suchen
strstr prüfen, ob String Teil eines anderen ist
Erläuterungen zu den Funktionen aus string.h
strcpy
char *strcpy (char ziel, const char *quelle);
Die Funktion strcpy kopiert den String Quelle komplett mit Endekennung in den String Ziel. Es wird der String Ziel zurückgegeben
151
C-Programmierung 2003/2004 151
Arbeiten mit Strings
Einem String kann bei der Initialisierung sofort ein Name zugewiesen werden.
char test[10]="Beispiel";
Der String Test wird mit "Beispiel" initialisiert und hat die Länge 9 (8 Zeichen und Endekennung).
Um dem String einen neuen Inhalt zu geben, muss eine Funktion aus der Headerdateigenutzt werden. Folgende Anweisung ist nicht zulässig:
test="Kunde";
Eine Stringkonstante steht immer für ihre Adresse. !strcpy (ziel,quelle);
strcpy (test,"Kunde")
Nutzung der Funktion strcpy (kopieren von Strings)
152
C-Programmierung 2003/2004 152
Der Name eines String steht immer für seine Adresse und eine Stringkonstante steht ebenfalls für ihre Adresse. Damit ist dieser Aufruf korrekt.
Stringzuweisungen außerhalb der Deklaration bedürfen immer der Nutzung von strcpy.
#include <stdio.h> //Programm26#include <string.h>void fkt(char *a){ printf("Inhalt in der Funktion :%s\n",a);
strcpy(a,"Anton");printf("Nach strcpy in der Funktion :%s\n",a);
}
void main(void){char x[15]="Willibald";
printf("Inhalt vor der Funktion :%s\n",x);fkt(x);printf("Inhalt nach der Funktion :%s\n",x);
}
153
C-Programmierung 2003/2004 153
Der String wird in der Funktion verändert. Das hat auch Auswirkungen auf den String außerhalb der Funktion, da die Adresse des Strings übergeben wurde.
Soll der String außerhalb der Funktion nicht verändert werden, so muss innerhalb der Funktion eine Kopie angefertigt werden.
154
C-Programmierung 2003/2004 154
#include <stdio.h> //Programm27#include <string.h>
void fkt(char *a){ printf("In der Funktion :%s\n",a);
strcpy(a,"Anton");printf("Nach strcpy :%s\n",a);
}void main(void){char x[15]="Willibald";
printf("Vor der Funktion :%s\n",x);fkt(x);printf("Nach der Funktion :%s\n",x);
}
ersetzen
void fkt (char *a){char b[15];strcpy(b,a);printf ("In der Funktion: %s\n",b);strcpy (b,"Anton");printf ("Nach strcpy : %s\n",b); }
Das Original von a bleibt erhalten!!!!!
155
C-Programmierung 2003/2004 155
Ein String kann auch zeichenweise ausgegeben werden.
a=0;
while (x[a])
printf ("%c", x[a++]);
Ein String wird immer mit 0 als Endekennung abgeschlossen, damit bricht die while-Schleife bei erreichen der Endekennung ab.
Steht jedoch nicht der wirkliche String zur Verfügung, sondern nur der Zeiger auf den String (ist bei Funktionsparametern üblich), muss die Zeichenweise Ausgabe wie folgt realisiert werden.char *z;z=x;while (*z);
printf ("%c",*(z++));
Zeiger auf char wird definiert. Dieser Zeiger bekommt die Adresse von x (Variablennameeines String verkörpert die Adresse). Durch Dereferenzierung wird auf das Zeichen an der Adresse zugegriffen, die der Zeiger gespeichert hat.
Programm27_1
156
C-Programmierung 2003/2004 156
String-Felder
Mehrere Strings können zu einem Stringfeld zusammengefasst werden.
char test[5][10]; 5 String zu je 10 Zeichen
char test[5][10]={"Otto1","Otto2","Kurt1","Kurt2","Willi"};
Auf diese einzelnen String kann problemlos zugegriffen werden:
for (a=0;a<5;a++)
printf ("%s\n",test[a]);
Achtung!!Der Name eines Stringfeldes mit einem Index weniger als in der Definition, repräsentiert die Adresse eines speziellen String.
Programm 28
ein Index
157
C-Programmierung 2003/2004 157
18. StrukturenVariablen unterschiedlichen Typs können zu einer Gruppe zusammengefasst werden. Diese Gruppe von unterschiedlichen Variablen werden als Strukturen bezeichnet.
char name[40]; char vorname[40];
int gehalt; int alter;
Soll das Programm eine definierte Menge dieser Personen verarbeiten, z.B. 500, so müßte für jede Variable ein Feld definiert werden.
char name[500][40];
char vorname[500][40];
int gehalt[500];
int alter[500];
Dies ist eine Realisierungsmöglichkeit, jedoch lässt sich das Problem mit Strukturenbedeutend eleganter lösen.
158
C-Programmierung 2003/2004 158
struct personaldaten
{char name[40];
char vorname[40];
int gehalt;
int alter;};
Struktur Personaldaten
Abschluß immer mit Semikolon
Die einzelnen Elemente der Struktur werden auch als Member (Mitglieder der Struktur) bezeichnet.
Eine Variable dieses Strukturtypes wird wie folgt definiert:
struct personaldaten arbeiter1;
Es wurde eine Variable arbeiter1 erzeugt, die vom Typ struct personaldaten ist.
Auf die einzelnen Elemente dieser Struktur kann jetzt zugegriffen werden. Die einzelnen Variablen innerhalb der Struktur können wie normale Variablen behandelt und verarbeitet werden. Es muss nur der Variablenname der Struktur vorangestellt werden.
159
C-Programmierung 2003/2004 159
arbeiter1.alter=34;
arbeiter1.gehalt=6700;
strcpy(arbeiter1.vorname="Otto");
strcpy(arbeiter1.name="Mueller");
Wird in der gleichen Funktion auch eine Variable mit dem Namen alter deklariert, so führt das zu keinen Konflikten, da diese Variable außerhalb der Struktur steht und damit unabhängig von der Variablen arbeiter1.alter ist.
int alter=99; unabhängig von arbeiter1.alter
Variablen innerhalb einer Struktur besitzen lokalen Charakter
Strukturen können mit Hilfe des Zuweisungsoperators kopiert werden wie elementare Datentypen.
Strukturen können in ihrer Komplexität trotzdem fast wie normale elementare Datentypen behandelt werden.
160
C-Programmierung 2003/2004 160
#include <stdio.h> //Programm 29#include <string.h>struct Personendaten
{char Vorname[40];char Nachname[40];int Bruttogehalt;int Alter; };
void main(void){ struct Personendaten person, person2;
person.Alter=34;person.Bruttogehalt=6700;strcpy(person.Vorname,"Joseph");strcpy(person.Nachname,"Müller");
printf("%s,%s. Alter:%i Bruttogehalt:%i\n",person.Nachname, person.Vorname, person.Alter,person.Bruttogehalt);
person2=person;printf("%s,%s. Alter:%i Bruttogehalt:%i\n", person2.Nachname, person2.Vorname,person2.Alter,person2.Bruttogehalt);
}
161
C-Programmierung 2003/2004 161
Strukturen können auch direkt bei ihrer Definition initialisiert werden.
struct personaldaten arbeiter1={"Otto","Mueller",6700,34};
162
C-Programmierung 2003/2004 162
#include "stdafx.h"struct feld{int wert[10];};
int main(int argc, char* argv[]){
struct feld vfeld_1={1,2,3,4,5,6,7,8,9,0};struct feld vfeld_2;
vfeld_2=vfeld_1;
printf ("%i %i %i \n",vfeld_2.wert[0],vfeld_2.wert[1],vfeld_2.wert[3]);
return 0;}
Direktes Kopieren von Feldern mittels Strukturen, da feld_1=feld_2 nicht zulässeig ist
// int feld_1[10]={1,2,3,4,5,6,7,8,9,0};// int feld_2[10];
// feld_2=feld_1;
Programm Test_1
163
C-Programmierung 2003/2004 163
Zeiger auf Strukturen
Auch auf Strukturen können Zeiger definiert werden.
struct personaldaten arbeiter1;
struct personaldaten *arbeiter1zgr;
Zeiger auf struct arbeiter1
Die Zuweisung erfolgt dann analog wie bei anderen Variablentypen.
arbeiter1zgr=&arbeiter1;
164
C-Programmierung 2003/2004 164
Normaler Zugriff auf Elemente von Strukturvariablen
arbeiter1.alter=99;
Zugriff über Zeiger auf ein Element einer Strukturvariablen
arbeiter1zgr->alter=99;
Es wird nur die Variable alter aus der Struktur arbeiter1 geändert, da arbeiter1zgr auf die Struktur arbeiter1 zeigt.
struct personaldaten maurer,*x;
x=&maurer; maurer.alter=44;
x->gehalt=3000;
aus der Strukturvariablen Maurer wird das Element alter direkt geändert und die Variable Gehalt durch einen Zugriff über Zeiger.
Programm 30
"zeigt auf"
165
C-Programmierung 2003/2004 165
Felder von Strukturen
Felder bieten in der Massendatenverarbeitung oft die Möglichkeit bestehende Probleme auf elegante Art zu lösen.
int x; Definition einer int Variablen
int x[100]; Definition eines int Feldes mit 100
Einträgen
Diese Möglichkeit bietet sich auch bei Strukturen, wenn man ein Feld von Strukturen bildet.
struct personaldaten arbeiter1;
struct ersonaldaten arbeiter1[500];
Auf die Elemente dieses Strukturfeldes kann jetzt ebenfalls einzeln durch Indizierung zugegriffen werden.
arbeiter1[12].alter=99;
arbeiter1[455].gehalt=3900;
166
C-Programmierung 2003/2004 166
Es soll das Alter der 320. Person auf 32 gesetzt werden:
arbeiter1[319].alter=32;
Achtung !!! Felder beginnen immer mit dem Index 0
Das Gehalt der 10. Person soll auf 4000 gesetzt werden. Der Zugriff ist mit Zeiger zu realisieren.
struct personaldaten *arbeiter1zgr[500];
arbeiter1zgr=&arbeiter1;
arbeiter1zgr[9]->gehalt=4000;
167
C-Programmierung 2003/2004 167
Weiterhin könnte man ein Feld von Zeigern auf die Strktur personaldaten definieren.
struct personaldaten arbeiter1zgr[100];
Änderung des Gehaltes der 30.Person:
arbeiter1zgr[29] ->gehalt=7600;
168
C-Programmierung 2003/2004 168
Verschachtelte Strukturen
Strukturen können ineinander verschachtelt werden
Deklaration der inneren Struktur:
struct p-adressen
{ char strasse[100];
unsigned long plz;
char ort[80] };
Einsetzen dieser Struktur in eine andere:
struct personaldaten
{ struct p-adressen adresse;
char vorname[40];
char nachname[40];
int bruttogehalt;
int alter; };
169
C-Programmierung 2003/2004 169
Variable vom Typ personaldaten deklarieren:
struct personaldaten person1, person2,person3;
Zugriffe auf die Elemente
person1.adresse.plz=07551;
Beim kopieren von verschachtelten Strukturen wird sowohl die innere als auch die äußere Struktur zusammen kopiert. Damit kann ein Kopiervorgang von verschachtelten Strukturen wie folgt realisiert werden:
person2=person1;
person3=person1;
personaldaten
personaldaten
personaldaten
p-adressen
p-adressen
p-adressen
Kopie
170
C-Programmierung 2003/2004 170
Änderungen einer Variablen in der Struktur person1 vom Typ Personaldatenhat damit keine Auswirkungen auf andere Strukturen des gleichen Typs.
Man kann die Daten der inneren Struktur aus dem vorherigem Beispiel auch außerhalb verwalten.
struct personaldaten
{
struct p-adressen *adressen;
char vorname[50];
char nachname[50];
int bruttogehalt;
int alter; };
personaldaten adressenZeiger
171
C-Programmierung 2003/2004 171
struct p-adressen homedaten;
struct personaldaten daten;
daten.adressen=&homedaten;
Zugriff auf die Werte:
daten.adressen->plz=07551;
Kopieren von verschachtelten Strukturen (flache Kopie)
personaldaten adressen
ZeigerPersonaldaten_1
Zeiger
Kopie
Zeiger
172
C-Programmierung 2003/2004 172
Kopieren von verschachtelten Strukturen (tiefe Kopie)
personaldaten adressen
personaldaten_1
Zeiger
Kopie
Zeiger
adressen_1
Kopie
173
C-Programmierung 2003/2004 173
UnionsWenn in einer Struktur mehrere Variable unterschiedlichen Typs gespeichert werden sollen, aber auf Grund eines Auswahlverfahrens nur ein Typ real gespeichert wird, dann ist der Speicherplatz für die anderen Variablen verschenkt.
struct werte
{int intzahl;
float floatzahl;
char charwerte[20];
}
Speicherplatzverschwendung,wenn nur ein Typ abgelegt wird
union werte
{int intzahl;
float floatzahl;
charwerte[20];
}
Es kann nur ein Typ gespeichert werden,
entweder intzahl oder floatzahl oder charwerte
174
C-Programmierung 2003/2004 174
#include <stdio.h> //Programm 31#include <string.h>union block {
char string[20];double dbl;int intzahl;
};void main(void){ union block sammlung;
sammlung.intzahl=20;printf("int = %i\n",sammlung.intzahl);strcpy(sammlung.string, "Johann");printf("string = %s\n", sammlung.string);printf("int = %i\n",sammlung.integer);sammlung.dbl=3.1415926535;printf("double = %f\n",sammlung.dbl);printf("string = %s\n", sammlung.string);printf("int = %i\n",sammlung.integer);
}
Bei einer union benutzen alle
Elemente den gleichen Speicherplatz.
175
C-Programmierung 2003/2004 175
Aufzählungstyp enum
Der Aufzählungstyp enum ist ein Ganzzahltyp, dessen Zahlenmenge eingeschränkt ist.
enum woche {MO,DI,MI,DO,FR,SA,SO};
C weist den 7 Konstanten jetzt Werte zu:
MO=0 DI=1 ....SO=6
Variable definieren:
Enum woche tag;
tag=MI; oder tag=(woche)(2); Typumwandlung mit cast-Operator
tag=XO Fehler nicht im Wertebereich
tag=(woche)(20) Fehler, wird aber nicht bemerkt
Schleifenbildung:
int z=0;
for (tag=MO;tag<=SO; tag=(woche)(++x))
176
C-Programmierung 2003/2004 176
Zuweisungen an andere Ganzzahlvariablen sind möglich:
int x,y;
x=DO;
printf („%i“,x);
Welchen Wert hat x ???????
Es muss bei bestimmten Ausdrücken auch eine Typumwandlung erzwungen werden (siehe Beispiele), dann ist aber der Programmierer dafür verantwortlich, dass der Wertebereich nicht überschritten wird.
tag=(woche) (x);
Ist der Wert einer Konstanten nicht explizit angegeben, ist er um 1 höher als der der Vorgängerin. Ist der Wert der ersten Konstanten nicht angegeben, dann ist er immer 0. !
177
C-Programmierung 2003/2004 177
#include "stdafx.h"enum wochentage{MO,DI,MI,DO,FR,SA,SO};
int main(int argc, char* argv[]){enum wochentage tag,*tagzgr;
tagzgr=&tag;tag=MO; printf ("%i\n\n",tag);tag=SO; printf ("%i\n\n",tag);
int x;x=2;
tag=(wochentage)(x); printf ("%i\n\n",tag);if (tag==MO)
{printf ("Montag \n\n");}else {printf ("Nicht Montag -- anderer
Wochentag\n\n");}tag=(wochentage)(0);
x=0;while (tag<=SO)
{printf ("%i\n", tag);x++;tag=(wochentage)(x);}printf ("\n\n");
for (tag=(wochentage)(0),x=0;tag<=SO; tag=(wochentage)(++x))printf ("%i\n", tag);
return 0;}
Programm 31_1Programm 31_1 .NET
178
C-Programmierung 2003/2004 178
Eigene Typen mit typedef
Es gibt die Möglichkeit, eigene Variablentypen zu deklarieren, so dass der eigentliche Variablentyp im Programm nicht vorkommt.
typdef int INTzahl;
typdef unsigned int uint;
typdef char Name[40];
Eine Definition einer Variablen vom Typ Name als char mit 40 Zeichen könnte dann so erfolgen:
Name vorname;
Eine Variable vom Typ INTzahl könnte wie folgt angelegt werden:
INTzahl zahl1, zahl2, zahl3, zahl4;
179
C-Programmierung 2003/2004 179
Für Strukturen gilt dies analog:
typdef struct Adresse
{
int privatnr;
int dienstnr;
char ort[20];
}SAdressen;
SAdressen adr;
180
C-Programmierung 2003/2004 180
19. Arbeiten mit Dateien
Um eine Datei zu öffnen wird die Funktion fopen benutzt. Eine Datei wird mit fclosegeschlossen. Beide Funktionen stehen in der Headerdatei stdio.h.
Fopen und fclose haben folgenden Aufbau:
fileptr=fopen(dateiname, modus);
.......
.......
fclose(fileptr);
fileptr ist ein Zeiger auf eine FILE-Struktur und wird wie folgt definiert:
FILE *fileptr
Datei
Text-Datei Binär-Datei
181
C-Programmierung 2003/2004 181
fileptr=fopen(dateiname, modus);
Dateiname verkörpert den Namen der zu öffnenden Datei und wird in einer Stringkonstanten gespeichert. Der Aufbau des Dateinamens ist abhängig vom Computersystem.
Modus ist ebenfalls eine Stringkonstante und gibt den Modus der zu öffnenden Datei an. Der Modus entscheidet über das Format der zu öffnenden Datei (Textdatei, Binärdatei) und darüber, ob in der Datei nur gelesen oder auch geschrieben werden soll.
Die File-Struktur enthält nach dem öffnen der Datei deren charakteristische Merkmale. Da dort ein eindeutiger Bezug zur Datei besteht, können auch mehrere Dateien geöffnet werden. Wenn filrptr nach dem Aufruf von fopen 0 ist, dann konnte die Datei nicht geöffnet werden.
Die Deklaration von FILE steht ebenfalls in stdio.h.
182
C-Programmierung 2003/2004 182
Text-Dateien
Modus Beschreibung
"r" öffnet eine Textdatei zum lesen
"w" erstellt eine Textdatei zum Schreiben. Der Inhalt einerunter diesem Namen bereits existierenden Datei wirdgelöscht.
"a" Erstellt oder öffnet eine bereits existierenden Datei zum Schreiben. Der Dateipositionszeiger steht am der Datei, dadurch werden neue Daten hinten angehängt.
"w+" Erstellt eine Textdatei zum Lesen oder Schreiben. Der Inhalt einer bereits unter diesem Namen existierenden Datei wird gelöscht.
"a+" Erstellt oder öffnet eine bereits existierenden Datei zum Schreiben oder Lesen. Der Dateipositionszeigersteht am der Datei, dadurch werden neue Datenhinten angehängt.
183
C-Programmierung 2003/2004 183
Öffnen einer Datei "test.txt" zum Schreiben:
fileptr=fopen(test.txt,"w");
Die Datei wird in das aktuelle Verzeichnis geschrieben. Dieses hängt vom Computersystem und vom eingestellten Pfad auf dem Rechner ab.
184
C-Programmierung 2003/2004 184
Die Funktionen fputs, fgets und feof
Die Funktionen sind mit den normalem puts und gets identisch, nur dass noch zusätzlich ein Zeiger auf die zu bearbeitende Filestruktur existiert und bei fgets noch die Anzahl der maximal einzulesenden Zeichen angegeben wird.
Weiterhin wird die Funktion feof benutzt. Diese Funktion wird benötigt, um zu prüfen, ob das Dateiende erreicht ist.
Dateiende erreicht: Wert von feof ist wahr
Dateiende noch nicht erreicht: Wert von feof ist falsch
Die Funktion feof wird folgendermaßen aufgerufen:
wert=feof(fileptr);
fgets (name,länge,fileptr);
fputs (name,fileptr);
185
C-Programmierung 2003/2004 185
#include <stdio.h> //Programm 32#include <string.h>#define DATNAME "test.txt"
void schreiben(void){FILE *fhd;char s[160];
fhd=fopen(DATNAME,"w");if(!fhd) {
printf("Datei konnte nicht erzeugt werden!\n\n");}
else {printf("Bitte maximal 160 Zeichen pro Zeile eingeben.\n");printf("Eingabe wird mit . beendet.\n\n");getchar();do { printf(">>>");
gets(s);if(strcmp(s,".")) //Vergleichen von Strings{fputs(s,fhd);
fputs("\n",fhd);}
} while(strcmp(s,"."));fclose(fhd);printf("\nEingabe beendet!\n");
}}
Problem Tastaturpuffer
186
C-Programmierung 2003/2004 186
void lesen(void){FILE *fhd;char s[160];int x=1;
fhd=fopen(DATNAME,"r");if(!fhd)
{printf("Datei konnte nicht geoeffnet werden!\n\n");}
else{printf("Die Datei hat folgenden Inhalt:\n");
fgets(s,160,fhd);do
{printf("%i:%s",x++,s);fgets(s,160,fhd);
} while(!feof(fhd));
fclose(fhd);printf("\nEnde der Datei!\n");
}}
187
C-Programmierung 2003/2004 187
void main(void){int input;
printf("Soll die Datei 1=gelesen oder 2=beschrieben werden?");scanf("%i",&input);if(input==1)
{lesen();
}else
{if(input==2)
{schreiben();
}else
{printf("\nFalsche Eingabe!\n\n");
}}
}
188
C-Programmierung 2003/2004 188
Feof liefert erst dann einen wahren Wert, wenn versucht wird, Daten zu lesen, obwohl das Dateiende erreicht ist.
Es muss bemerkt werden, dass die do-Schleife im folgenden Beispiel nur dann fehlerfrei funktioniert, wenn die Datei mindestens einen Datensatz enthält. Soll auch der Fall einge-schlossen sein, dass die Datei vollständig leer sein kann, dann muß die do-Schleife noch in eine if-Schleife eigebettet werden.
fgets (s,MAXZEILENLAENGE,fhd);
if (!feof(fhd)
{ do {
printf("%i: %s",x++,s);
fgets(s,MAXZEILENLAENGE,fhd);
} while (!feof(fhd));
} fclose(fhd);
Eine Funktion, die in einer Datei liest, positioniert den Dateipositionszeiger immer hinter das zuletzt gelesene Zeichen. Eine Funktion, die in eine Datei schreibt, positioniert den Datei-positionszeiger immer hinter das zuletzt geschriebene Zeichen.
Zuerst lesen, wenn EOF, dann wird Schleife nicht abgearbeitet.
189
C-Programmierung 2003/2004 189
Die Funktionen fprintf und fscan
Weitere Funktionen zur Bearbeitung von Textdateien sind fprintf und fscan. Die Funktionen sind identisch mit printf und scanf.
printf ("Das Wort heißt %s und hat %i Buchstaben", wort,strlen(wort));
fprintf (fhd, "Das Wort heißt %s und hat %i Buchstaben", wort,strlen(wort));
Den Text, welchen printf auf den Bildschirm schreibt, bringt fprintf in eine Datei,die der File-Struktur fhd zugeordnet ist.
Analog dazu holt sich fscan eine Eingabe von einer Datei, während scanf vom Bildschirm liest.
fscan (fhd, "%i %s", x, s); Programm32_1
190
C-Programmierung 2003/2004 190
Die Funktionen fgetc und fputc
Die Funktionen fgets und fputs lesen und schreiben Strings. Es gibt aber auch Funktionen, die ein einzelnes Zeichen aus einer Datei lesen oder schreiben, das sind fgetc und fputc.
fputc (zeichen, fhd);
speichert das in der Variablen zeichen gespeicherte Zeichen in die Datei, die der File-Struktur fhd zugeordnet ist.
fputc liefert den wert von zeichen zurück, wenn die Übertragung erfolgreich war, bei Fehlern wird der Wert EOF zurückgegeben.
wert=fputc(zeichen,fhd);
if (wert==EOF)
printf("Fehler beim Schreiben!!!\n");
zeichen=fgetc(fhd);
Die Funktion fgetc liest ein Zeichen aus der Datei, welche der File-Struktur fhdzugeordnet ist. Danach enthält die Variable zeichen das eingelesene Zeichen.
191
C-Programmierung 2003/2004 191
Binärdateien
In den bisherigen Varianten wurden die Daten als Textdateien gespeichert. Damit sind sie mit jedem beliebigen Editor lesbar. Oft ist es aber günstigen (z.B. aus Speicherplatzgründen) die Daten direkt als Binär-Daten zu speichern.
Ein Umwandeln von Textdaten in Zahlenvariablen kann bei der Speicherung als Binärdaten ebenfalls entfallen.
192
C-Programmierung 2003/2004 192
Modus Beschreibung
"rb" öffnet eine Binärdatei zum Lesen
"wb" erstellt eine Binärdatei zum Schreiben. Der Inhalt einer bereitsbestehenden Datei wird gelöscht.
"ab" erstellt oder öffnet eine bereits bestehende Binärdatei zum Schreiben. Der Dateipositionsanzeiger steht am Ende der Datei,d.h. Die Daten werden angehängt.
"rb+" öffnet eine Binärdatei zum Lesen oder Schreiben
"wb+" erstellt oder öffnet eine Binärdatei zum Lesen oder Schreiben. DerInhalt einer bereits bestehenden Datei wird gelöscht.
"ab+" erstellt oder öffnet eine Binärdatei zum Lesen oder Schreiben. Der Dateipositionsanzeiger steht am Ende der Datei,d.h. Die Daten werden angehängt.
193
C-Programmierung 2003/2004 193
Die Funktionen fwrite und fread
Syntax von fwrite:
anz=fwrite (adresse, groesse, anzahl, fhd);
adresse ist die Adresse, an der die zu speichernde Variable oder das zu speichernde Feld steht.
groesse ist die Größe der Variablen oder die eines Feldelements in Byte.
anzahl ist bei einer Variablen 1, bei einem Feld die Anzahl der Elemente.
fhd ist der Zeiger auf die FILE-Struktur, mit der die zu beschreibende Datei verknüpft ist.
fwrite gibt die Anzahl der komplett geschriebenen Elemente zurück.
194
C-Programmierung 2003/2004 194
Syntax von fread:
anz=fread (adresse, groesse, anzahl, fhd);
adresse ist die Adresse an der die aus der Datei gelesenen Daten gespeichert werden.Alle anderen Parameter sind analog fwrite.
195
C-Programmierung 2003/2004 195
Die Funktion sizeof
Die besprochenen Funktionen bergen zur Zeit noch einige Probleme in sich, denn die Größe der Variablen ist in den meisten Fällen unbekannt. Selbst bei int-Werten ist es von System zu System verschieden, wie viel Byte zur Speicherung benutzt werden. Um das Problem zu beseitigen, wurde die Funktion sizeof geschaffen. Sie bestimmt die Größe einer jeden Variablen und liefert damit den benötigten Wert für die Lese- und Schreibfunktionen für Binärdateien.
char s[80]; //Programm 37
strcpy (s,"Otto");
printf ("Die Größe von s ist %i \n",sizeof (s));
printf ("Der Variablentyp int ist %i Bytes gross. \n",sizeof (int));
Im ersten Fall wird 80 ausgegeben, da sich sizeof mit der Definition von s befasst und nicht mit der Zuweisung des Inhaltes. Im zweiten Fall wird die Größe des int Variablentypesermittelt und mit printf ausgegeben.
196
C-Programmierung 2003/2004 196
#include <stdio.h> //Programm 33#include <string.h>#define DATNAME "test.txt"#define MAXVORNAME 25#define MAXNACHNAME 20void schreiben(void){FILE *fhd;char vname[MAXVORNAME],nname[MAXNACHNAME];unsigned int alter,groesse;
fhd=fopen(DATNAME,"wb");if(!fhd) { printf("Datei konnte nicht erzeugt werden!\n\n"); }else {
printf("Vorname (Max. %i Zeichen) :",MAXVORNAME-1);scanf("%s",vname);
printf("Nachname (Max. %i Zeichen) :",MAXNACHNAME-1);scanf("%s",nname);
printf("Alter in Jahren :"); scanf("%u",&alter);printf("Groesse in Zentimetern :"); scanf("%u",&groesse);fwrite(vname,sizeof(vname),1,fhd);
fwrite(nname,sizeof(char),MAXNACHNAME,fhd);fwrite(&alter,sizeof(alter),1,fhd);fwrite(&groesse,sizeof(unsigned int),1,fhd);fclose(fhd); printf("\nEingabe beendet!\n");
}}
197
C-Programmierung 2003/2004 197
void lesen(void){FILE *fhd;char vname[MAXVORNAME],nname[MAXNACHNAME];unsigned int alter,groesse;
fhd=fopen(DATNAME,"rb");if(!fhd)
{ printf("Datei konnte nicht erzeugt werden!\n\n"); }else
{fread(vname,sizeof(vname),1,fhd);fread(nname,sizeof(nname),1,fhd);fread(&alter,sizeof(alter),1,fhd);fread(&groesse,sizeof(groesse),1,fhd);
fclose(fhd);
printf("Vorname : %s\n",vname);printf("Nachname : %s\n",nname);printf("Alter in Jahren : %u\n",alter);printf("Groesse in cm : %u\n",groesse);}
}
198
C-Programmierung 2003/2004 198
void main(void){int input;
printf("Soll die Datei 1=gelesen oder 2=beschrieben werden?");scanf("%i",&input);
if(input==1){
lesen();}
else{
if(input==2){
schreiben();}
else{
printf("\nFalsche Eingabe!\n\n");}
}}
199
C-Programmierung 2003/2004 199
Dateipositionsanzeiger
Für Binärdateien gibt es die Möglichkeit ein spezielles Element aus der Datei zu be-arbeiten. Das setzt natürlich die Veränderung des Dateipositionszeigers voraus. Nur dadurch kann eine spezielle Stelle innerhalb einer Datei erreicht werden.
Der Dateipositionszeiger wird mit der Funktion fsetpos verändert.
Syntax von fsetpos:
fpos_t position;
a=fsetpos(fhd,&position);
Die Variable a enthält den Wert 0, wenn das Setzen des Dateipositionszeigers erfolgreich war.
Die Adresse der Variablen Position vom Typ fpos_t wird an die Funktion fsetposübergeben (fpos_t ist ein selbst deklarierter Variablentyp).
Fsetpos löscht auch das Dateiendeflag.
200
C-Programmierung 2003/2004 200
void lesen2(void){FILE *fhd;char vname[MAXVORNAME],nname[MAXNACHNAME];unsigned int alter,groesse;fpos_t position;
fhd=fopen(DATNAME,"rb");if(!fhd)
{printf("Datei konnte nicht erzeugt werden!\n\n");
}else
{position=sizeof(vname)+sizeof(nname)+sizeof(alter);fsetpos(fhd,&position);
fread(&groesse,sizeof(groesse),1,fhd);fclose(fhd);
printf("Groesse in cm : %u\n",groesse);}
}
Programm 33_1
201
C-Programmierung 2003/2004 201
Es wird eine Variable mit dem Namen position definiert. In ihr wird die Summe der Längen der zu überspringenden Daten gespeichert. Nach dem Öffnen der Datei wird mit fsetpos der Dateipositionszeiger an die Stelle vor den gespeicherten Daten der Größe gesetzt. Alle anderen Anweisungen sind dann analog dem Beispiel 33.
Die Variablen vname, nname, alter wurden definiert, aber nur zur Überspringung der Daten benutzt. Der Compiler kann hier eine Warnung ausgeben, da die Variablen nicht benutzt wurden. Diese Warnung kann ignoriert werden.
202
C-Programmierung 2003/2004 202
Das Gegenstück zu fsetpos ist fgetpos. Diese Funktion speichert den aktuellen Wert des Dateipositionszeigers in einer Variablen.
Syntax:
fpos_t position;
a=fgetpos(fhd, &position);
Jetzt wird der aktuelle Inhalt des Dateipositionszeigers in die Variable positiongeschrieben. Ist die Funktion erfolgreich ausgeführt, dann gib die Funktion den Wert 0 zurück, welcher dann in der Variablen a gespeichert ist
203
C-Programmierung 2003/2004 203
Eine weitere Funktion zur Veränderung des Dateipositionszeigers ist fseek. Diese Funktion kann in verschiedenen Modi aufgerufen werden.
Syntax von fseek:
a=fseek(fhd, distanz, modus);
SEEK_SET Der Dateipositionszeiger wird auf Dateianfang gesetzt und
bekommt den Wert von distanz hinzuaddiert. Damit
sind nur positive Werte sinnvoll. Der Aufruf ist analog fsetpos(fhd,
&position), wenn position und distanz gleich sind.
SEEK_END Der Dateipositionszeiger wird auf Dateiende gesetzt und bekommt
den Wert von distanz hinzuaddiert. Es sind nur negative
Werte für distanz sinnvoll.
SEEK_CUR Zum Dateipositionszeiger wird der Wert von distanz addiert. Damit
sind positive und negative Werte sinnvoll.
204
C-Programmierung 2003/2004 204
fgetpos (fhd, &position);
position+=distanz;
fsetpos (fhd, &position);
Dateipositionsteiger um 2 Byte nach vorn bewegen:
fseek (fhd,2,SEEL_CUR);
Die Modi für fseek sind Makros, die in der Datei stdio.h definiert sind. Die Funktion fseek liefert den Wert 0 zurück, wenn der Dateipositionszeider fehlerfrei verändert wurde.
Fseek löscht ebenfalls das Dateiendeflag.
Die Funktion rewind setzt den Dateipositionszeiger auf den Anfang der Datei und löscht das Fehlerflag.
Der Aufruf erfolgt mit: rewind (fhd);
Die Funktionen fsetpos, fgetpos und fseek spezifizieren einen eventuell aufgetretenen Fehler im Makro errno.
205
C-Programmierung 2003/2004 205
Weitere Funktionen zur Arbeit mit Dateien
rename
#include <stdio.h> /* Programm 38 */
void main(void){
printf("Datei wird umbenannt");rename("test.txt","mueller.txt"); /* Datei wird von */
/* test.txt *//* nach mueller.txt umbenannt */
}
206
C-Programmierung 2003/2004 206
remove
remove löscht eine Datei namens name und gibt bei Erfolg den Wert 0 zurück.
Name ist die Adresse eines String.
a=remove (name);remove ("test.txt")
löscht die Datei test.txt
207
C-Programmierung 2003/2004 207
Oft werden im Programmen Dateien zur Zwischenspeicherung benötigt, die nach Programmende gelöscht werden können. Dabei ist besonders wichtig, dass ein Dateiname gewählt wird, der einzigartig ist, um das Überschreiben bzw. Zerstören anderer Dateien zu vermeiden.
Dies kann mit der Funktion tmpname erfolgen, diese Funktion erzeugt einen Filenamen, der einzigartig ist.
Syntax:char a[80];
tmpnam (a);
Die Datei kann dann mit fopen geöffnet werden.
char a[80];
tmpnam (a);
fhd=fopen(a,"wb+");
208
C-Programmierung 2003/2004 208
Für die Aufgabe der Erzeugung einer temporären Datei kann auch die Funktion tmpfilegenutzt werden. Diese Funktion öffnet eine binäre Datei zur Ein- und Ausgabe und liefert die Adresse der File-Struktur zurück, über die die Datei verwaltet wird.
fhd=tmpfile();
Wenn Fehler innerhalb der Dateiarbeit auftreten, dann kann die Funktion ferror genutzt werden.
a=ferror(fhd);
Bei aufgetretenen Fehlern ist a dann ungleich Null. Diese Funktion kann genutzt werden, um Fehler auszutesten und entsprechende Meldungen zu erzeugen.
209
C-Programmierung 2003/2004 209
#include <stdio.h> /* Programm 39 */#include <conio.h>#include <stdlib.h>void main(void){int zahl; zahl=0;
while(zahl!=200){
printf("Bitte geben Sie 200 ein:");scanf("%i",&zahl);//clrscr ();
system("cls");printf("Bitte geben Sie 900 ein:");scanf("%i",&zahl);//clrscr();
}}
Anwendung der Funktion system zum löschen des Konsolenfensters.
210
C-Programmierung 2003/2004 210
20. Präprozessor-Befehle
Ein Präprozessor-Befehl, #include, wurde bereits in vielen Programmen genutzt. Der Präprozessor kann jedoch noch bedeutend mehr Unterstützung für den Programmierer bieten.
#define ohne ParameterDie define Anweisung erlaubt es, dass einem bestimmten Wert ein Name zugewiesen wird.
#define MAXWERT 80
Dem symbolischen Name MAXWERT wird der Wert 80 zugeordnet. An jeder Stelle im Programm, an der MAXWERT auftaucht wird dies durch den Präprozessor mit 80 ersetzt.
void main (void)
{char feld[MAXWERT]; ....... ; }
Der String wird in diesem speziellen Fall 80 Zeichen groß. Die define Anweisung arbeitet auf Textebene, aus diesem Grund ist auch folgendes Programm richtig:
#define START main
void START (void)
211
C-Programmierung 2003/2004 211
Bevor der Compiler den Quelltext bearbeitet, ersetzt er START durch main. Damit ist das C-Programm in Ordnung und es wird zu keinen Fehlern während der Compilierung kommen.
Weitere Anwendungen von #define sind:
#define STRING "Tabelle"
void main (void)
{char Feld[80]=STRING;}
#define WERTE 80+80void main (void){int x;x=WERTE*2; ...........;}
#define WERTE (80+80)void main (void){int x;x=WERTE*2;...........;}
212
C-Programmierung 2003/2004 212
#define mit ParameterEs können auch Makros mit Parameter definiert werden.
#define QUADRAT(x) (x*x)
Wenn der Präprozessorjetzt auf QUADRAT(ausdruck) stoßt, dann ersetzt er dies durch (ausdruck)*(ausdruck).
#define QUADRAT(x) (x*x) //Programm 36
void main (void)
{int zahl;
printf ("Bitte einen Wert eingeben:");
scanf ("%i", &zahl);
printf ("Das Quadrat von %i ist %i \n",zahl, QUADRAT(zahl));}
printf ("Das Quadrat von %i ist %i \n",zahl, QUADRAT(zahl++)); ?Was berechnet das Programm, wenn die Zahl 4 eingegeben wird und wie groß ist der Wert von zahl am Programmende?
Der Präprozessor ersetzt zahl++ * zahl++. Damit lautet das Ergebnis 16 (4*4) und zahl ist am Programmende 6.
213
C-Programmierung 2003/2004 213
#undefMit der Anweisung #undef kann eine bestehende #define-Anweisung aufgehoben werden. Das kann z.B. notwendig sein, wenn ein definiertes Makro nur in einem bestimmten Bereich gültig sein soll, oder wenn Makros aus bestehenden Header-Files nicht genutzt werden sollen, oder durch eigene Definitionen ersetzt werden müssen.
#define STRING "Tabelle"
............
#undef STRING
#define STRING "MUSTER"
#includeDie #include-Anweisung wird schon seit längeren in Programmen genutzt.
#include <stdio.h>
Die spitzen Klammern bedeuten, dass die Header-Datei im include Pfad des Compilers zu suchen ist. Der Nutzer kann aber auch eigene Header-Dateien schreiben, in welchen die ganzen Deklarationen stehen. Die eigenen Header-Dateien speichert man im gleichen Verzeichnis wie das Programm.
Möchte man eine Header-Datei einbinden, die im gleichen Verzeichnis wie das Programm steht, benutzt man doppelte Anführungszeichen (#include "header1").
214
C-Programmierung 2003/2004 214
#define STD <stdio.h>
#define EIG "eigen.h"
#include STD
#include EIG
Die #include-Anweisung kann natürlich auch in Verbindung mit #define benutzt werden.
215
C-Programmierung 2003/2004 215
#if und #endifDie #if Anweisung entspricht der C-if-Anweisung, nur dass es sich auf eine Definition des Präprozessors bezieht. Diese Anweisung ist hauptsächlich zum bedingten Compilieren notwendig.
Es werden bestimmte Anweisungen nur dann kompiliert, wenn die entsprechenden Randbedingungen erfüllt sind.
#if TEST == 1
print ("Das ist ein Test - Makro Test ist 1");
x++;
#endif
Die Anweisungen im Beispiel zuwischen #if unf #endif werden nur dann kompiliert, wenn das Makro den Wert 1 hat.
Die #endif Direktive ist unbedingt notwendig und schließt jede #if Direktive ab.
Mit diesen Anweisungen ist es z.B. möglich, dass ein Programm geschrieben wird und vor dem kompilieren wird entschieden in welcher Sprache das Programm übersetzt wird.
216
C-Programmierung 2003/2004 216
#include <stdio.h> // Programm 34
#define DEUTSCH 1#define ENGLISCH 2
#define WERT DEUTSCH
void main(void){int zahl;
#if WERT == DEUTSCHprintf("Bitte Wert eingeben:");
#endif
#if WERT == ENGLISCHprintf("Please enter a value:");
#endif
scanf("%i",&zahl);}
217
C-Programmierung 2003/2004 217
__DATE__
Makro steht für eine Stringkonstante mmm tt jjjj
Startdatum der Kompilierung
__TIME__
Makto steht für das Datum hh:mm:ss
Startzeit der Kompilierung
__FILE__
Stringkonstante mit dem aktuellen Namen der Quellcodedatei
__LINE__
Aktuelle Zeilennummer Ganzzahl
__STDC__
Liefert Ganzzahl 1, wenn Compiler ein ANSI C Compiler ist
(geht nicht bei allen Compilern)
Vordefinierte Makros
Programm 43
219
C-Programmierung 2003/2004 219
Headerdatei-1.h Headerdatei-2.h Headerdatei-3.h Headerdatei-4.h
xx-1.cpp xx-2.cpp xx-3.cpp xx-4.cpp
Compiler
xx-1. obj xx-2. obj xx-3. obj xx-4. obj
Linker
Programm xx.exe
220
C-Programmierung 2003/2004 220
21.1 Eigene Header-Dateien
- Programme modular aufbauen
- Möglichkeit der eigenen Header-Dateien nutzen
- Auslagerung in Header-Dateien:
- alle #define Anweisungen
- Struktur- und Uniondeklarationen
- Prototypen
Bei doppelten Anführungszeichen stehen die Headerdateien im aktuellen Verzeichnis
#include <stdio.h>
#include <string.h>
#include "eigene-header-datei.h"
Programm 40
221
C-Programmierung 2003/2004 221
Bei Headerdateien sollte unbedingt verhindert werden, dass sie mehrfach kompiliert werden. Dies kann in komplexen Projekten zu Fehlern führen.
Um das zu vermeiden, wird die Präprozessoranweisung #ifndef benutzt.
#ifndef __HEADERDATEI001_H
#define __HEADERDATEI001_H
#include …….
.
.
#endif
Namenskonventionen von C
siehe auch Programm 40
222
C-Programmierung 2003/2004 222
Programm 41
Statische Variablen und Funktionen
static int rekfakul (int x, int y)
{if (x==1) return (y);
return (rekfakul (x-1,y*(x-1)));
}
int fakul (int x)
{if x<0) return (0);
if (x==0) return(1);
return (rekfakul (x,x));
Programm 42
Statische Variablen
223
C-Programmierung 2003/2004 223
Hinweise zur modularen Programmierung:
- Funktionen zu sinnvollen Modulen zusammenstellen
- Themenbezogene Strukturierung
- Schnittstellen zu den Funktionen transparent darstellen und dokumentieren
- wenn möglich auf globale Variablen verzichten
- Informationen zu den Funktionen hinzufügen (Kommentarzeilen), in denen die Funktion
erklärt wird
- Module genau beschreiben, Zusammenhänge eindeutig erläutern
- Aufbau von eigenen Header-Dateien für Definitionen
- Angabe von Änderungsständen und Versionsnummern
- Nutzung der Readme-Files der Entwicklungsumgebung
224
C-Programmierung 2003/2004 224
21.2. Rekursion
Von Rekursionen spricht man, wenn sich Funktionen selbst aufrufen.
// Rekursion01.cpp//#include <stdio.h>
void rekfunk (void){int x=99;static int z=1;printf ("Ausgabe innerhalb der Funktion rekfunk beim %i. Aufruf mit Wert %i\n",z,x);z++;rekfunk();}void main(void){
rekfunk();}
Absturz des Programms durch Stack-Übrlauf
• immer neue Rücksprungadresse von rekfunk
• immer neue Lokale Variable x
225
C-Programmierung 2003/2004 225
Sinnvolle Anwendung von rekursiven Funktionsaufrufen.
Beispiel: Berechnung der Fakultät einer Zahl
3!= 1*2*3=6 4!=1*2*3*4=24 4!=1*2*3*4*5=120
#include <stdio.h> // Programm: Fakultaet01.cppvoid main(void){int x;
do{ int i,erg=1,z;
printf ("Bitte die Zahl eingeben, von der die Fakultät berechnet werden soll: ");scanf ("%i",&i);
if (!(i==0)){ for (z=1;z<i+1;z++)
erg=erg*z;}printf ("Die Fakultaet von %i ist %i\n\n",i,erg);printf ("Soll eine weitere Berechnung durchgefuehrt werden? j=1/n=2: ");scanf ("%i",&x);
} while (x==1);}
Berechnung ohne rekursiven Funktionsaufruf
226
C-Programmierung 2003/2004 226
Berechnung auch wie folgt möglich: x!=x*(x-1)! ; mit 0!=1
#include <stdio.h> // Programm: Fakultaet02.cpp
int fakultaet (int x){ if (x<0) return (0);
if (x==0) return (1);return (x*fakultaet (x-1));
}
void main(void){int wert,x,erg;do{ printf ("Bitte die Zahl eingeben, von der die Fakultät berechnet werden soll: ");
scanf ("%i",&wert);
erg=fakultaet (wert);printf ("Die Fakultaet von %i ist %i\n\n",wert,erg);printf ("Soll eine weitere Berechnung durchgefuehrt werden? j=1/n=2: ");scanf ("%i",&x);
} while (!(x==2));
}
227
C-Programmierung 2003/2004 227
Programm am Beispiel von Fakultät 4:
Aufruf von fakultaet (4): x>0 Rückgabe von 4*fakultaet (3);
Aufruf von fakultaet (3): x>0 Rückgabe von 3*fakultaet (2);
Aufruf von fakultaet (2): x>0 Rückgabe von 2*fakultaet (1);
Aufruf von fakultaet (1): x>0 Rückgabe von 1*fakultaet (0);
Aufruf von fakultaet (0): x==0 Rückgabe von 1;
Rücksprung in fakultaet (1): Rückgabewert von 1*1=1
Rücksprung in fakultaet (2): Rückgabewert von 2*1=2
Rücksprung in fakultaet (3): Rückgabewert von 3*2=6
Rücksprung in fakultaet (4): Rückgabewert von 4*6=24
Ausgabe Ergebnis: 24
228
C-Programmierung 2003/2004 228
0 1
2 3
4 5
6 7
A B C A B C
A B C A B C
A B C A B C
A B C A B C
Türme von Hanoi
229
C-Programmierung 2003/2004 229
21.3. Listen
Abstrakter Datentyp: Ein abstrakter Datentyp ist ein Datentyp, dem zusätzlich Funktionen zur Verfügung gestellt werden, die auf ihm operieren.
Sortierung von Warteschlangen: jedes Mitglied der Warteschlange merkt sich seinen Vorgänger Länge der Schlange ist nicht relevant
• ideal für dynamische Speicherverwaltung, denn der für die Speicherung notwendigefreie zusammenhängende Platz ist nicht größer als die Größe eines einzelnen Elementes
230
C-Programmierung 2003/2004 230
Einfach verkettete Listen
struct Telefon
{ char name[80];
char vorname[80];
char telefon[25];
char mail[50];
}
Es ist effektiv, die Daten immer in einer Struktur zu kapseln
Trennung zwischen Nutzdaten und Kontrolldaten
Ein Listenelement benötigt zuerst die Nutzdaten, d.h. die Struktur telefon und
die Information auf das vorherige Element, d.h. einen Zeiger auf den Nachfolger
struct Knot
{struct Telefon *telefon; //Zeiger auf ein Element vom gleichen Typ
struct Knot *next; // Zeiger auf nächstes Element
};
234
C-Programmierung 2003/2004 234
Listenkopf: struct Knot *listenkopf=0;
Wird mit 0 initialisiert, da am Anfang noch kein Element existiert
1. Funktion der Liste –anhängen eines Knotens an die Liste
-Parameterübergabe - Nutzdaten und Listenkopf
-Funktion erzeugt einen Knoten und hängt ihn an die Liste an
- gibt Wert zurück (Funktion ausgeführt oder Error)
Funktionen malloc und free
Anfordern von Speicher: void *malloc (size_t groesse);
- der Typ der Speicherplatzanforderung ist size_t
- sizeof liefert einen Wert vom Typ size_t zurück Nutzung bei malloc
Freigeben von Speicher: void free (void *ptr);
235
C-Programmierung 2003/2004 235
Nutzung von malloc und free
#include <stdio.h> //Speicher01.cpp#include <stdlib.h>
void main(void){
void *nullptr;int *ptr;
nullptr=malloc( sizeof(int) );ptr=(int*)(nullptr);if(ptr)
{*ptr=30;printf("Der dynamische Speicherblock hat den Wert %i
gespeichert\n",*ptr);free(ptr);
}}
236
C-Programmierung 2003/2004 236
- Funktion malloc gibt einen Zeiger auf void zurück, d.h. auf einen typenlosen Zeiger
- ein typenloser Zeiger kann auf alles zeigen
- für die weitere Nutzung muss aber dieser void Zeiger durch Typumwandlung mit
dem cast Operator in einen typisierten Zeiger gewandelt werden
- der von malloc gelieferte Zeiger ist die Adresse des reservierten Speicherblocks oder der
Nullzeiger
Nullzeiger: - beinhaltet die Adresse 0; ist per Definition ein leerer Zeiger, d.h. er
zeigt auf kein Element
- wird bei Funktionen dazu benutzt, um zu zeigen, dass kein Element
vorhanden ist oder erzeugt wurde (nullptr)
237
C-Programmierung 2003/2004 237
int ListAppend (struct Knot *hd, struct Telefon *tel)
{void *ptr;
ptr=malloc(sizeeof(struct Knot));
struct Knot *cur,*ap;
ap=(struct Knot *)(ptr)
if (ap)
{ ap->telefon=tel; ap->next=0;
if (!hd)
{hd=ap; return (1);}
else
{cur=hd;
while (cur->next) cur=cur->next;
cur->next=ap; return (1);}
}
return (0);
}
238
C-Programmierung 2003/2004 238
1. Definition von 2 Zeigern, *ap bekommt dann einen Speicherbereich in der Größe vonstruct Knot zugewiesen
2. prüfen, ob hd wirklich Speicherplatz zugewiesen wurde, wenn ja Verweis auf Nutzdaten hergestellt und Verweis auf das nächste Element wird 0 (letztes Element-> hat keinen Nachfolger
3. prüfen, ob hd 0 ist, wenn ja es existiert noch kein Knoten, dieser wird der erste
4. ist hd nicht 0 es existiert mindestens ein Knoten letzten Knoten finden, um neues Element anhängen zu können
5. cur bekommt die in hd gespeicherte Adresse und zeigt damit auch auf den ersten Knoten
6. Über while Schleife wird geprüft, ob der next-Zeiger des Knotens, auf den cur zeigt gleich 0 ist bei ja ist dies der letzte Knoten, bei nein gibt es weitere Knoten
7. Ist cur 0 wird while abgebrochen, bei ungleich 0 wird weiter gesucht
8. Ist die while Schleife abgebrochen cur zeigt auf das letzte Listenelement
9. Dann wird dessen next auf den neuen Knoten gesetzt Liste ist um ein Element länger
Nachteil: Um das letzte Element zu finden, muss die gesamte Liste durchsucht werden.
239
C-Programmierung 2003/2004 239
Effektiver: direkter Zugriff auf Anfang und Ende der Liste Einführung einer Listenkopfstruktur
struct ListHead {struct Knot *head;
struct Knot tail;}
Zeiger auf den Listenkopf: struct ListHead *liste;
struct ListHead *ListCreate(void) // Funktion zum Anlegen und initialisieren des {void *ptr3; // Listenkopfes
ptr3=malloc(sizeof(struct ListHead));struct ListHead *head;head=(struct ListHead *)(ptr3);
if(head){
head->head=head->tail=0;return(head);
}return(0);
}
240
C-Programmierung 2003/2004 240
Anpassen der ListAppend Funktion unter Nutzung des Listenkopfes:
int ListAppend(struct ListHead *hd, struct Telefon *tel) // ListAppend *********{void *ptr1;ptr1=malloc(sizeof(struct Knot));struct Knot *ap;ap=(struct Knot *)(ptr1);
if(ap) {ap->telefon=tel;ap->next=0;
if(!(hd->head)){
hd->head=hd->tail=ap;return(1);
}else {
hd->tail->next=ap;hd->tail=ap;return(1);
}}
return(0);}
241
C-Programmierung 2003/2004 241
Funktion zum Löschen der Liste und freigeben des Speichers
void ListDelAll(struct ListHead *hd) //ListDelAll ***************{struct Knot *cur=hd->head, *nex;
while(cur){
nex=cur->next;free(cur->telefon);free(cur);cur=nex;
}free(hd);
}
Die Funktion geht die gesamte Liste durch.
Bevor ein Knoten gelöscht wird prüft die Funktion, ob dieser einen Nachfolger hat; wenn
ja, dann wird dessen Adresse in einer Variablen gespeichert. Beim Löschen wird ja der
Verweis auf den Nachfolger ebenfalls gelöscht.
Zuerst wird die Nutzdatenstruktur, dann die Knoten und zuletzt der Listenkopf gelöscht.
242
C-Programmierung 2003/2004 242
Die Funktion zu Dateneingabe:
int ListInput(struct ListHead *hd) //ListInput *****************{void *ptr2;ptr2=malloc(sizeof(struct Telefon));struct Telefon *dat;dat=(struct Telefon *)(ptr2);
if(dat) { printf("Vorname :");gets(dat->vorname);printf("Nachname :");gets(dat->nachname);printf("Telefon :");gets(dat->telefon);if(ListAppend(hd,dat)){return(1); }else {free(dat); return(0);}
}else
{return(0);
}}
243
C-Programmierung 2003/2004 243
Die Funktion zum Anzeigen der Liste:
void ListShow(struct ListHead *hd) //ListShow ******************{struct Knot *cur=hd->head;
if(!cur){
printf("Die Liste ist leer!\n");return;
}
while(cur){
printf("Name: %s, %s. Tel.:%s\n",cur->telefon->nachname,cur->telefon->vorname,cur->telefon->telefon);
cur=cur->next;}
}
244
C-Programmierung 2003/2004 244
void main(void){struct ListHead *liste;int eingabe;
liste=ListCreate();if(liste)
{ do { printf("\n1 = Liste zeigen\n");printf("2 = Knoten anfuegen\n");printf("\n0 = Ende\n\n");printf("Eingabe:");scanf("%i",&eingabe);getchar();printf("\n\n");
switch(eingabe){case 1: ListShow(liste); break;case 2: ListInput(liste);break;} } while(eingabe);
ListDelAll(liste);}}
Die main-Funktion
245
C-Programmierung 2003/2004 245
21.4. Sortierverfahren
Elementare Sortierverfahren: - Selection Sort
- Insertion Sort
- Bubble Sort
- Shell Sort
- Distribution Counting
- Quick Sort
Digitales Sortieren: - Radix Exchange Sort
- Straight Radix Sort
Proiritätswarteschlangen: - Heapsort
Mergesort : - Mergesort von Listen
- Bottom-Up Mergesort
246
C-Programmierung 2003/2004 246
Bubble Sort
- Einfaches Sortierverfahren
- Sortieren durch direktes Austauschen
99 84 23 11 Austauschen, wenn a>b
84 99 23 11 Austauschen, wenn a>b
84 23 99 11 Austauschen, wenn a>b
84 23 11 99 Ergebnis des 1. Durchlaufes – größte Zahl ist ermittelt
84 23 11 99 Austauschen, wenn a>b
23 84 11 99 Austauschen, wenn a>b
23 11 84 99 Austauschen, wenn a>b
23 11 84 99 Ergebnis des 2. Durchlaufes – zweitgrößte Zahl ermittelt
23 11 84 99 Austauschen, wenn a>b
11 23 84 99 Austauschen, wenn a>b
11 23 84 99 Austauschen, wenn a>b
11 23 84 99 Sortierung fertig
247
C-Programmierung 2003/2004 247
99 84 23 11 Austauschen, wenn a>b
84 99 23 11 Austauschen, wenn a>b
84 23 99 11 Austauschen, wenn a>b
84 23 11 99 Ergebnis des 1. Durchlaufes – größte Zahl ist ermittelt
84 23 11 99 Austauschen, wenn a>b
23 84 11 99 Austauschen, wenn a>b
23 11 84 99 Austauschen, wenn a>b kann enffallen !!!
23 11 84 99 Ergebnis des 2. Durchlaufes – zweitgrößte Zahl ermittelt
23 11 84 99 Austauschen, wenn a>b
11 23 84 99 Austauschen, wenn a>b kann entfallen !!!
11 23 84 99 Austauschen, wenn a>b kann entfallen !!!
11 23 84 99 Sortierung fertig
- Bei N Elementen braucht man für die Sortierung N-1 Durchläufe in der äußeren
Schleife und in jeder inneren Schleife immer einen Durchlauf weniger
248
C-Programmierung 2003/2004 248
// Bubble_Sort.cpp : Definiert den Einsprungpunkt für die Konsolenanwendung.#include "stdafx.h"/*void bubble(int *a,int n){int i,j,hv, z1=n,z=n;
for (i=1;i<=n;i++,z1--){ for (j=0,z=z1;z>=1;j++,z--)
{ if(a[j] > a[j+1]) {hv=a[j]; a[j]=a[j+1];a[j+1]=hv;};
}}}*/void bubble(int *a,int n){int i,j,hv;
for (i=n;i>=1;i--)for (j=1;j<i;j++)
if(a[j-1] > a[j]) {hv=a[j-1]; a[j-1]=a[j];a[j]=hv;};
}int main(int argc, char* argv[]){ int feld[4]={99,23,84,11};int n=4;
printf("%i %i %i %i \n", feld[0],feld[1],feld[2],feld[3]);bubble (feld,n);printf("%i %i %i %i \n", feld[0],feld[1],feld[2],feld[3]);return 0;
}
249
C-Programmierung 2003/2004 249
21.5. Suchalgorithmen
Elementare Suchmethoden: - Sequentielle Suche
- Binäre Suche
Ausgeglichene Bäume: - Top-Down 2-3-4 Bäume
- Rot-Schwarz Bäume
Hashing - Hash-Funktionen
- getrennte Verkettung
- lineares Austesten
- doppeltes Hashing
Digitale Suche
Externe Suche - indexsequentieller Zugriff
- B-Bäume
250
C-Programmierung 2003/2004 250
21.6. Datenkomprimierung
- Lauflängencodierung
- Kodierung mit variabler Länge
- Huffmann Codierung
-
252
C-Programmierung 2003/2004 252
Steuerzeichen
\a BEL (bell), gibt ein akustisches Signal
\b BS (backspace), der Cursor geht eine Position nach links
\f FF (formfeed), Seitenvorschub wird ausgelöst
\n NL (new line), der Cursor geht zum Anfang der nächsten Zeile
\r CR (carriage return), der Cursor geht zum Anfang der aktuellen Zeile
\t HAT (horizontal tab), der Cursor geht zur nächsten horizontalen
Tabulator position
\v VT (vertical tab), der Cursor geht zur nächsten vertikalen
Tabulatorposition
\" " es wird " ausgegeben
\' ' es wird ' ausgegeben
\? ? Es wird ein ? ausgegeben
\\ \ Es wird ein \ ausgegeben
253
C-Programmierung 2003/2004 253
Bindungsstärke der Operatoren
Operator Bedeutung Priorität
a++ Postinkrement 1
a-- Postdekrement 1
a[b] Index 1
a(b) Funktionsaufruf 1
a.b Zugriff auf Element 1
b->b zeigt auf Element 1
254
C-Programmierung 2003/2004 254
Operator Bedeutung Priorität
sizeeof a Größe 2
++a Präinkrement 2
--a Prädekrement 2
&a Adresse 2
*a Dereferenzierung 2
+a Plus 2
-a Minus 2
~a NOT Bitweise 2
!a NOT Logisch 2
(Deklaration)(a) Cast-Operator 2
255
C-Programmierung 2003/2004 255
Operator Bedeutung Priorität
a*b Multiplikation 3
a/b Division 3
a%b Modulo (Rest) 3
a+b Addition 4
a-b Subtraktion 4
a<<b Linksverschiebung 5
a>>b Rechtsverschiebung 5
a<b kleiner 6
a>b größer 6
a<=b kleiner gleich 6
a<=b größer gleich 6
256
C-Programmierung 2003/2004 256
Operator Bedeutung Priorität
a==b gleich 7
a!=b ungleich 7
a&b UND Bitweise 8
a^b exclusiv ODER Bitweise 9
a|b ODER Bitweise 10
a&&b UND Logisch 11
a||b ODER Logisch 12
257
C-Programmierung 2003/2004 257
Operator Bedeutung Priorität
a?b:c Bedingung 13
a=b Zuweisung 14
a*=b Multiplikation Zuweisung 14
a/=b Division Zuweisung 14
a%=b Modulo Zuweisung 14
a+=b Addition Zuweisung 14
a-=b Subtraktion Zuweisung 14
a<<=b Linksverschiebung Zuweisung 14
a>>=b Rechtsverschiebung Zuweisung14
a&=b UND Bitweise Zuweisung 14
a^b exclusiv ODER Bitzuweisung 14
a|=b ODER Bitzuweisung 14
a,b Komma 15
258
C-Programmierung 2003/2004 258
Formatzeichen Gleitkommazahlen
FZ Typ Zahlensystem Besonderheit
f double Dezimal *.*****
Lf long double Dezimal *.*****
e double Dezimal *.***E**
Le long double Dezimal *.***E**
E double Dezimal *.***E**
LE long double Dezimal *.***E*
g double Dezimal mit oder ohne E.
Lg long double Dezimal mit oder ohne E.
G double Dezimal mit oder ohne E.
LG long double Dezimal mit oder ohne E.
259
C-Programmierung 2003/2004 259
Formatzeichen Strings
FZ Typ Besonderheit
c char einzelnes Zeichen
s char[ ] String mit abschließender 0
% gibt % selbst aus
Formatzeichen Zeiger
FZ Typ Besonderheit
n int *
hn short *
ln long *
P void *
260
C-Programmierung 2003/2004 260
FZ Typ Zahlensystem
i int Dezimal
d int Dezimal
hi short Dezimal
hd short Dezimal
li long Dezimal
ld long Dezimal
u unsigned int Dezimal
hu unsigned short Dezimal
lu unsigned long Dezimal
Formatzeichen Ganzzahlen
Recommended