Grundlagen der Programmierung - Friedrich-Schiller

Werbung
Grundlagen der
Programmierung
Friedrich-Schiller-Universität
Jena
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
1
1
Einleitung
Was sind Programme?
Einfache und schnelle
Lösung mathematischen
Problemen
Warum programmieren?
Erarbeitung eines
Algorithmus
Erstellung einer
Abarbeitungsvorschrift
(Programm) für den
Computer in einer
speziellen Sprache
Übersetzen des
Algorithmus in die
Maschinensprache
Abarbeitung des
Programms im Computer
Ergebnis
Friedrich-Schiller-Universität
Jena
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
2
2
Klassifikation nach Sprachtypen
C#
2000
Visual
Basic
Delphi
Java
1990
Ada
1980
C++
C
Pascal
1970
Algol 68
Basic
Friedrich-Schiller-Universität
Jena
1960
Cobol
Algol 60
Fortran
Universitätsrechenzentrum
Multimediazentrum
Prozedurale Sprachen
1950
Objektorientierte Sprachen
C-Programmierung 2003/2004
3
3
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
Friedrich-Schiller-Universität
Jena
Problemen abgestimmt (Datenbankabfragen)
- das Programm bestimmt eine logische Beziehung
zwischen den einzelnen Daten
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
4
4
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
Friedrich-Schiller-Universität
Jena
Fünfte Generation:
Künstliche Intelligenz
- Lisp, Prolog, Smalltalk
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
5
5
Entwicklung und Ausführung eines Programms
Problem
Lösung mittels eines
Algorithmus
Modul 1
Modul 2
Compiliertes Modul 1
Compiler
Modul 3
Friedrich-Schiller-Universität
Jena
Ausführbares
Programm
mit absoluten
Adressen
mehrere Module
Compiliertes Modul 2
Compiliertes Modul 3
Lader
Fertiges
Programm mit
relativen
Adressen
(Lademodul)
Linker
(Verbinder)
Interpreter
Programm
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
6
6
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
Friedrich-Schiller-Universität
Jena
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 Standardbibliotheken.
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
7
7
Microsoft Visual C++ 6.0
Friedrich-Schiller-Universität
Jena
Universitätsrechenzentrum
Multimediazentrum
C-Programmierung 2003/2004
8
8
Programmieren in C
C-Programmierung 2003/2004
9
9
Inhaltsverzeichnis
1.
2.
3.
4.
5.
6.
7.
8.
8.1.
8.2.
8.3.
8.4.
8.5.
9.
10.
10.1.
10.2.
10.3.
Grundlagen
Funktionen
Variablentyp int
Eingabe mit scanf
Grundrechenarten
Entscheidung if
Gültigkeitsbereich von Variablen
Funktionen mir Parameterübergabe
Parameterübergabe
Wertrückgabe
Übergabe mehrerer Parameter
Prototypen parametrisierter Funktionen
spezielle Hinweise zu Funktionen mit Parameterübergabe
Die for-Schleife
Schleifen mit Ein- und Austrittsbedingungen
Schleifen mit Eintrittsbedingung
Schleifen mit Austrittsbedingung
Continue-Anweisung
C-Programmierung 2003/2004
10
10
11.
12.
13.
14.
15.
15.1.
15.2.
15.3.
16.
17.
18.
19.
20.
21.
21.1.
21.2.
21.3.
21.4
21.5
21.6
22.
Logische Operatoren
Variablen vom Typ float
Fallunterscheidungen
Der Variablentyp char
Zeiger und Vektoren
Adressen als Funktionsparameter
Zeiger auf Funktionen
Zeiger auf Zeiger
Variablenfelder
Zeichenketten - String
Strukturen
Arbeit mit Dateien
Präprozessor-Befehle
Programmier-Technologien
Eigene Header Dateien
Rekursion
Listen
Sortierverfahren
Suchalgorithmen
Datenkomprimierung
Zusammenfassung
C-Programmierung 2003/2004
11
11
1. Grundlagen
Das 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
C-Programmierung 2003/2004
12
12
- 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
C-Programmierung 2003/2004
13
13
- 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 !!!
C-Programmierung 2003/2004
14
14
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.
C-Programmierung 2003/2004
15
15
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>
Programm01
void main(void)
{
Ausgabe am Bildschirm:
printf ("Ausgabe-1\n");
Ausgabe-1
printf ("Ausgabe-2");
Ausgabe-2
}
C-Programmierung 2003/2004
16
16
Alternativ (Ausgabe in einer printf-Anweisung)
#include <stdio.h>
vioid main(void)
{
printf ("Ausgabe-1\nAusgabe-2");
}
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
C-Programmierung 2003/2004
17
17
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");
}
C-Programmierung 2003/2004
18
18
void main(void)
{
funktion1( );
funktion2( );
}
funktion1
funktion2
{
printf ("Ausgabe-1\n");
}
{
printf ("Ausgabe-2\n");
}
Start
main
funktion1
funktion2
Ende
Funktionsaufruf
C-Programmierung 2003/2004
main
19
19
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).
C-Programmierung 2003/2004
20
20
Funktionsdeklarationen und Prototypen
#include <stdio.h>
void funktion1(void);
void funktion2(void);
Prototyp
void main(void)
{
funktion1();
funktion2();
}
void funktion1(void)
{
printf("Ausgabe-Text-Funktion1\n");
}
void funktion2(void)
{
printf("Ausgabe-Text-Funktion2\n");
}
C-Programmierung 2003/2004
Funktionsdeklaration
21
21
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.
Varianten von Integer-Variablen
Typ
Größe
Zahlenbereich
FZ
int
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
- 128 bis + 127
hi
0 bis 255
hu
1 Byte
unsigned short 1 Byte
FZ = Formatzeichen
C-Programmierung 2003/2004
22
22
Die angegebenen Längen von Integer Variablen sind Mindestgrößen, die ein Compiler
benutzen muss, es können aber auch mehr sein.
C-Programmierung 2003/2004
23
23
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
C-Programmierung 2003/2004
24
24
#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
C-Programmierung 2003/2004
25
25
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.
Vor dem Gleichheitszeichen dürfen keine konstanten Ausdrücke stehen
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;
C-Programmierung 2003/2004
26
26
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
C-Programmierung 2003/2004
27
27
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
C-Programmierung 2003/2004
28
28
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
C-Programmierung 2003/2004
29
29
scanf("%u",&zahl);
Formatzeichen
Adresse von Zahl
(&=Addreßoperator
scanf("Bitte eine Zahl eingeben %u", &zahl);
Text wird ignoriert !!!!!
printf ("Bitte eine Zahl eingeben:");
scanf ("%i",&zahl);
Richtig !!!!!
C-Programmierung 2003/2004
30
30
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).
C-Programmierung 2003/2004
31
31
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).
C-Programmierung 2003/2004
32
32
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.
33 / 8 = 4
4 * 8 = 32 Rest 1
schublade=zahl%8;
Æ Schublade 1
C-Programmierung 2003/2004
33
33
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
"+".
C-Programmierung 2003/2004
34
34
zahl=zahl*wert1+wert2 ;
zahl*=wert1+wert2;
falsch
Achtung: Es erfolgt immer erst die Berechnung rechts und dann die Zuweisung !!!!!
C-Programmierung 2003/2004
35
35
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.
C-Programmierung 2003/2004
36
36
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");
C-Programmierung 2003/2004
37
37
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.
C-Programmierung 2003/2004
38
38
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 ?????
C-Programmierung 2003/2004
39
39
Weil in beiden Programmen die Variablen während dem
Inkrementieren / Dekrementieren nicht benutzt wurden. Der Vorgang
wurde separat ausgeführt
C-Programmierung 2003/2004
40
40
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
C-Programmierung 2003/2004
41
41
Programm 02
Programm 02_2
Fragen:
1.) Ist x+=2 gleich x++2 ???
2.) Worin liegt der Vorteil von ++ gegenüber von +=1 ???
C-Programmierung 2003/2004
42
42
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: ==
C-Programmierung 2003/2004
43
43
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.
C-Programmierung 2003/2004
44
44
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.
C-Programmierung 2003/2004
45
45
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 =<
C-Programmierung 2003/2004
46
46
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))
C-Programmierung 2003/2004
47
47
#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
C-Programmierung 2003/2004
48
48
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;
Programm 04
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.
C-Programmierung 2003/2004
49
49
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.
C-Programmierung 2003/2004
50
50
Die Abfrage auf gleich Null kann damit durch folgende
Anweisung realisiert werden.
if (!x)
Programm 6.cpp
{
}
Das man mit Bedingungen rechnen kann, das wurde im
Beispielprogramm bereits bewiesen.
C-Programmierung 2003/2004
51
51
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>
Fehler beim compilieren, Variable x ist
nicht definiert
void aendern(void)
{
x=10;
}
void main(void)
{int x=4;
printf("x = %i\n",x);
aendern();
printf("x = %i\n",x);
}
C-Programmierung 2003/2004
52
52
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?
C-Programmierung 2003/2004
?
53
53
#include <stdio.h>
void main(void)
{
int wert;
printf("Bitte Zahl eingeben :");
scanf("%i",&wert);
if(wert<=20)
{
int quadrat;
Variable quadrat ist innerhalb des
if-Blocks definiert und nur dort
gültig
quadrat=wert*wert;
printf("Das Qudrat von %i ist %i\n",wert,quadrat);
}
printf("Quadrat hat den Wert %i",quadrat);
}
Fehler beim compilieren, da Variable quadrat nicht definiert ist !!!!
Lokale Variablendefinitionen müssen immer die ersten Anweisungen des Blockes sein,
in dem sie stehen !!!
C-Programmierung 2003/2004
54
54
Globale Variablen
#include <stdio.h>
Die Variable x ist als globale Variable
definiert
int x=4;
void aendern(void)
{
x=10;
}
void main(void)
{
printf("x = %i\n",x);
aendern();
printf("x = %i\n",x);
}
Variablen, die außerhalb einer Funktion definiert werden, sind global und können
somit in jeder Funktion benutzt werden.
C-Programmierung 2003/2004
55
55
Globale und lokale Variablen können in einem Programm zusammen genutzt werden.
Dabei sind gleiche Namen durchaus erlaubt.
#include <stdio.h>
Variable a und b global definiert
int a,b;
void aendern(void)
{
int a;
a=0;
if(a==0)
Variable a lokal definiert
{
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);
}
C-Programmierung 2003/2004
56
56
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.
Achtung
void main(void)
{
int a;
int a;
Es dürfen nicht zwei Variablen mit gleichem
Namen und dem gleichen Gültigkeitsbereich
definiert werden
a=10;
}
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 Programmrealisierung gibt.
C-Programmierung 2003/2004
57
57
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 ?
111
C-Programmierung 2003/2004
?
58
58
#include <stdio.h>
void test(void)
{
static int a=1;
Definition von a als statische
Variable
printf("a=%i\n",a);
a++;
}
void main(void)
{
test();
test();
test();
}
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
C-Programmierung 2003/2004
erhalten.
59
59
#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
?
Programm 05
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.
C-Programmierung
2003/2004
60
60
8. Funktionen mit Parameterübergabe
8.1 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.
C-Programmierung 2003/2004
61
61
#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);
Parameterübergabe an quadrat
Wert wird an die Funktion
übergeben
}
C-Programmierung 2003/2004
62
62
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 quadrat
initialisiert.
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).
C-Programmierung 2003/2004
63
63
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.
C-Programmierung
2003/2004
64
64
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 quadrat
wird nicht benötigt
C-Programmierung 2003/2004
65
65
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));
}
Kann entfallen
Funktionsaufruf ist direkt in die printfAnweisung integriert
Wird der Rückgabewert einer Funktion nicht angegeben, geht der Compiler davon
aus, dass ein int-Wert zurückgegeben
wird.
C-Programmierung 2003/2004
66
66
Wie würde das Programm aussehen, wenn die eben besprochene Tatsache zur
Anwendung kommt???
Test
#include <stdio.h>
/*Programm 9 */
Das int vor der Funktion kann
quadrat (int x)
weggelassen werden
{
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));
}
C-Programmierung 2003/2004
67
67
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)
Was realisiert dieses
Programm?????
{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));
}
C-Programmierung 2003/2004
68
68
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
C-Programmierung 2003/2004
69
69
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 ????
C-Programmierung 2003/2004
70
70
int testfkt (int x)
{ if (x==20)
return (x+12); else { return (x*x) };
}
C-Programmierung 2003/2004
71
71
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
}
C-Programmierung 2003/2004
72
72
for (anweisung1 ; bedingung ; anweisung2)
{ anweisungsblock}
Anweisung1
Bedingung wahr?
Anweisungs-block
ja
nein
Anweisung2
C-Programmierung 2003/2004
73
73
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
C-Programmierung 2003/2004
74
74
#include <stdio.h>
Anweisung1 bedingung anweisung2
Programm 10
void main(void)
{
int x;
for(x=1; x<=3; x++)
{
printf("Aktueller Wert :%i\n",x);
}
}
anweisungsblock
C-Programmierung 2003/2004
75
75
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>
Programm 11
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 ???
C-Programmierung 2003/2004
?
76
76
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.
C-Programmierung 2003/2004
77
77
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?
ja
anweisungsblock
nein
C-Programmierung 2003/2004
78
78
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>
void main(void)
{
int zahl;
Programm 11-01
Was realisiert dieses Programm?
?
zahl=0;
while(zahl!=200)
{
printf("Bitte geben Sie 200 ein:");
scanf("%i",&zahl);
}
}
C-Programmierung 2003/2004
79
79
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++;
}
C-Programmierung 2003/2004
80
80
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-02
int getzahl(void)
{ int zahl;
printf("Bitte geben Sie eine Zahl ein:");
scanf("%i",&zahl);
return(zahl);
}
void main(void)
{
while(getzahl()!=200);
}
C-Programmierung 2003/2004
81
81
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);
C-Programmierung 2003/2004
82
82
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 Programm hinter while fort
Anweisungs-Block
Bedingung
wahr?
ja
nein
C-Programmierung 2003/2004
83
83
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
Keine Anfangsinitialisierung
von „zahl“ notwendig
{
printf("Bitte geben Sie 200 ein:");
scanf("%i",&zahl);
}
while(zahl!=200);
Programm 11_03
„Eingabeprüfung“
}
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.
C-Programmierung 2003/2004
84
84
10.3 Continue-Anweisung
x=0;
while (x<20)
Programm 991
{
x++
if (x==10)
continue;
printf ("x=%i\n",x);
}
Continue springt immer an den Anfang der innersten Schleife!!
C-Programmierung 2003/2004
85
85
Beginn
1
x=0
Ausgabe von x
solangeX<20
Schleifenende
x=x+1
Ende
x==10
nein
ja
In diesem Fall tritt
die continue
Anweisung in Aktion
1
C-Programmierung 2003/2004
86
86
Welche Auswirkung hat while (1) auf den Programmablauf?
?
Die Bedingung while ist immer wahr, d.h. es ist eine Endlosschleife
C-Programmierung 2003/2004
87
87
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
C-Programmierung 2003/2004
88
88
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
C-Programmierung 2003/2004
89
89
Der logische Operator ||
Der logische Operator || wird auch als ODER bzw. OR Operator bezeichnet. Er
realisiert folgende Verknüpfungen.
Bedingung1 Bedingung2 Bedingung1 || Bedingung2
falsch
falsch
falsch
falsch
wahr
wahr
wahr
falsch
wahr
wahr
wahr
wahr
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
C-Programmierung 2003/2004
90
90
Der && Operator und der || Operator können auch gemeinsam innerhalb eines Ausdruckes
auftreten.
do
Programm 12
{
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!!!!
C-Programmierung 2003/2004
91
91
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
C-Programmierung 2003/2004
92
92
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 speicherintensiver als int Variablen sind
C-Programmierung 2003/2004
93
93
#include <stdio.h>
void main(void)
{
unsigned long n=3,max;
//unsigned long 4 Byte
Programm 13
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.
C-Programmierung 2003/2004
94
94
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)
C-Programmierung 2003/2004
95
95
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;
C-Programmierung 2003/2004
96
96
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
C-Programmierung 2003/2004
97
97
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
C-Programmierung 2003/2004
98
98
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
C-Programmierung 2003/2004
99
99
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 zahl
ergebnis=sqrt(zahl);
printf ("Ergebnis von Quadratwurzel aus %f ist: %f \n",zahl,ergebnis);
}
C-Programmierung 2003/2004
100
100
tan
double tan (double a);
Berechnet den Tangens von a im Bogenmaß.
sin
double 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
C-Programmierung 2003/2004
101
101
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
C-Programmierung 2003/2004
102
102
Formatzeichen Gleitkommazahlen
FZ
Typ
Zahlensystem
f
double
Dezimal
*.*****
Lf
long double Dezimal
*.*****
e
double
Dezimal
*.***E**
Le
long double Dezimal
*.***E**
E
double
*.***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
Dezimal
Besonderheit
C-Programmierung 2003/2004
103
103
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.
C-Programmierung 2003/2004
104
104
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
C-Programmierung 2003/2004
105
105
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.
C-Programmierung 2003/2004
106
106
Sollen nach dem Ansprung einer case Marke die anderen nachfolgenden Case
Anweisungen nicht abgearbeitet werden, so muß break verwendet werden.
Break springt immer hinter die innerste for, switch oder while Anweisung.
Beginn
case 1 ?
Switch/case ohne break
ja
Ausgabe
1
nein
ja
case 2 ?
Ausgabe
2
nein
case 3 ?
ja
Ausgabe
3
nein
Ende
C-Programmierung 2003/2004
107
107
Beginn
Switch/case mit break
ja
Ausgabe
1
case 1 ?
nein
case 2 ?
ja
Ausgabe
2
nein
case 3 ?
ja
Ausgabe
3
nein
Ende
C-Programmierung 2003/2004
108
108
#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;
}
}
C-Programmierung 2003/2004
109
109
Mehrere case Anweisungen mit gleichem Sprungziel
Beginn
Es können beliebig viele case-Anweisungen das
gleiche Sprungziel haben.
ja
case 1 ?
nein
ja
case 2 ?
Ausgabe
2
nein
case 3 ?
ja
Ausgabe
3
nein
Ende
C-Programmierung 2003/2004
110
110
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 default
angesprungen. Damit kann der Sachverhalt, dass eine begrenzte Anzahl caseAnweisungen für bestimmte Bedingungen und ein Standard für "sonstiges", abgedeckt
werden.
Keine Sprungmarke für einen Wert
default (wenn vorhanden)
C-Programmierung 2003/2004
111
111
#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;
}
}
C-Programmierung 2003/2004
112
112
14. Der Variablentyp char
Der 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!!!!!
C-Programmierung 2003/2004
113
113
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);
?
Programm 15_02
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)
{
ASCII Tabelle Teil-1
case 'a':
printf (" Ein kleines a\n");
break;
case 'b':
ASCII Tabelle Teil-2
printf ("Ein kleines b\n");
break;
}
C-Programmierung 2003/2004
114
114
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
C-Programmierung 2003/2004
115
115
#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");
}
}
C-Programmierung 2003/2004
116
116
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.
C-Programmierung 2003/2004
117
117
Erläuterungen der einzelnen Funktionen
isalnum
int isalnum (int a);
Liefert einen wahren Wert, wenn a ein Zeichen aus folgendem Wertevorrat ist: a-z, A-Z, 0-9
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
C-Programmierung 2003/2004
118
118
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.
C-Programmierung 2003/2004
119
119
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).
C-Programmierung 2003/2004
120
120
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.
C-Programmierung 2003/2004
121
121
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
Speicheradresse
Wert
Variablenname
Eine Variable ist durch folgende 4 Angaben eindeutig identifiziert:
• Adresse (Position)
• Name (Variablenname)
• Inhalt (Wert)
• Größe (belegter Speicherplatz)
C-Programmierung 2003/2004
122
122
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);
}
Formatzeichen für Adressen
Was liefert das Programm für Ausgaben ?
?
C-Programmierung 2003/2004
Adreßoperator &
123
123
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
C-Programmierung 2003/2004
124
124
int x, *b;
Zeiger auf einen int-Wert
x=99;
b=&x;
Dem Zeiger wird ein Vektor zugewiesen.
C-Programmierung 2003/2004
125
125
Zeiger speichern Adresse, Variable speichern Werte.
000000002323432A
!
X
412
Zeiger auf eine Variable
000BAC32D2FF2A
b
000000002323432A
int x, *b;
x=99;
b ist der Zeiger auf die Variable x
b=&x;
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.
C-Programmierung 2003/2004
126
126
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???
?
#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);
}
C-Programmierung 2003/2004
127
127
Definition der int Variablen x und eines Zeigers z.
Der Variablen x wird der Wert 10 zugewiesen und dieser wird in der folgenden printfAnweisung 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;
C-Programmierung 2003/2004
128
128
000000002323432A
X
412
000BAC32D2FF2A
b
b
000000002323432A
000000002323432A
000000002323432A
X
*b
412
000BAC32D2FF2A
b
412
000000002323432A
C-Programmierung 2003/2004
129
129
000000002323432A
X
&b
412
000BAC32D2FF2A
b
000BAC32D2FF2A
000000002323432A
C-Programmierung 2003/2004
130
130
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 Dereferenzierung
auf 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.
C-Programmierung 2003/2004
131
131
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 */
Programm 19_01
void quadrat(int *wert)
{
Zeiger auf eine Variable wird
*wert=(*wert)*(*wert);
übergeben
}
void main(void)
{
int x;
printf("Bitte eine Zahl eingeben:");
scanf("%i",&x);
Adresse von x wird übergeben
quadrat(&x);
printf("Das Quadrat ist %i\n",x);
}
C-Programmierung 2003/2004
132
132
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
Syntax:
rtype (*fkt) (para1,para2,….)
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 Eingabeund Ausgabeparameter haben
C-Programmierung 2003/2004
133
133
#include <stdio.h>
/* Programm 990 */
void ausgabe(void) //Funktion ausgabe
{
printf("Bitte geben Sie eine Zahl ein:");
Programm 990_1
}
(Ohne Funktionsadressen)
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;
Der Name einer Funktion ohne Klammern
repräsentiert ihre Adresse
fkt1();
scanf("%i",&x);
(fkt1)();
scanf("%i",&y);
printf("Die Summe ist %i\n",fkt2(x,y));
}
C-Programmierung 2003/2004
134
134
15.3 Zeiger auf Zeiger
Syntax
typ **name
#include <stdio.h>
void main(void)
{
int x,y,*xptr,**ptrptr;
x=10;
y=10;
printf("x = %i\n",x);
/* Programm 992 */
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);
}
C-Programmierung 2003/2004
135
135
Übung !!!
Arbeiten mit Adressen;
Übergabe von Adressen an Funktionen;
Übergabe mehrerer Adressen an Funktionen
C-Programmierung 2003/2004
136
136
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];
Felddefinition mit 20 int Werten
testfeld[3]=12;
Wert 3 des Feldes wird mit 12
initialisiert und Wert 17 mit 99
testfeld[17]=99;
Der Feldindex beginnt immer mit 0 und reicht bis n-1, bei einem Feld mit n Elementen.
C-Programmierung 2003/2004
!
137
137
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);
}
C-Programmierung 2003/2004
138
138
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 Dereferenzierungsoperator
angewendet werden.
C-Programmierung 2003/2004
139
139
#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",
}
void main(void)
{
int x[10];
input(x);
calc(x);
output(x);
}
C-Programmierung 2003/2004
y+1,a[y]);
140
140
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.
C-Programmierung 2003/2004
141
141
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}};
1
2
1
4
5
2
5
4
3
6
3
4
7
2
Zeile
2 Spalten
4 Zeilen
Spalte
C-Programmierung 2003/2004
142
142
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
C-Programmierung 2003/2004
143
143
17. Zeichenketten - String
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)
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.
C-Programmierung 2003/2004
144
144
#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]);
}
C-Programmierung 2003/2004
145
145
Das Formatzeichen %s für Strings kann auch bei scanf genutzt werden, um ganze
Zeichenketten einzulesen.
#include <stdio.h>
//Programm 24
void main(void)
{char a[81];
printf("Bitte einen max. 80 Zeichen langen text eingeben:");
scanf("%s",a);
printf("Sie gaben \"%s\" ein.\n",a);
}
?
Debugger
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]);
Ein Character-Feld hat eine besondere Stellung. Scanf betrachtet das gesamte Feld als einen
Variablentyp, als String.
C-Programmierung 2003/2004
146
146
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>
//Programm25
void 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.
C-Programmierung 2003/2004
147
147
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!
C-Programmierung 2003/2004
148
148
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 vergleichen
strcpy
String kopieren
strerror
Umwandlung eines Feldes in verbale Form
strlen
Länge eines String ermitteln
C-Programmierung 2003/2004
149
149
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
C-Programmierung 2003/2004
150
150
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 Headerdatei
genutzt 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)
C-Programmierung 2003/2004
151
151
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);
}
C-Programmierung 2003/2004
152
152
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.
C-Programmierung 2003/2004
153
153
#include <stdio.h>
#include <string.h>
//Programm27
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);
}
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);
}
ersetzen
Das Original von a bleibt
erhalten!!!!!
C-Programmierung 2003/2004
154
154
Ein String kann auch zeichenweise ausgegeben werden.
a=0;
Programm27_1
while (x[a])
printf ("%c", x[a++]);
Ein String wird immer mit 0 als Endekennung abgeschlossen, damit bricht die whileSchleife 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 (Variablenname
eines String verkörpert die Adresse). Durch Dereferenzierung wird auf das Zeichen an
der Adresse zugegriffen, die der Zeiger gespeichert hat.
C-Programmierung 2003/2004
155
155
String-Felder
Mehrere Strings können zu einem Stringfeld zusammengefasst werden.
char test[5][10];
5 String zu je 10 Zeichen
Programm 28
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]);
ein Index
Achtung!!
Der Name eines Stringfeldes mit einem Index weniger als in der Definition, repräsentiert die
Adresse eines speziellen String.
C-Programmierung 2003/2004
156
156
18. Strukturen
Variablen 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 Strukturen
bedeutend eleganter lösen.
C-Programmierung 2003/2004
157
157
struct personaldaten
Struktur Personaldaten
{char name[40];
char vorname[40];
int gehalt;
Abschluß immer mit Semikolon
int alter;};
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.
C-Programmierung 2003/2004
158
158
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.
C-Programmierung 2003/2004
159
159
#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);
}
C-Programmierung 2003/2004
160
160
Strukturen können auch direkt bei ihrer Definition initialisiert werden.
struct personaldaten arbeiter1={"Otto","Mueller",6700,34};
C-Programmierung 2003/2004
161
161
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;
#include "stdafx.h"
struct feld
{int wert[10];};
Programm Test_1
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;
}
C-Programmierung 2003/2004
162
162
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;
C-Programmierung 2003/2004
163
163
Normaler Zugriff auf Elemente von Strukturvariablen
arbeiter1.alter=99;
Zugriff über Zeiger auf ein Element einer Strukturvariablen
arbeiter1zgr->alter=99;
"zeigt auf"
Es wird nur die Variable alter aus der Struktur arbeiter1 geändert, da arbeiter1zgr auf die
Struktur arbeiter1 zeigt.
struct personaldaten maurer,*x;
Programm 30
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.
C-Programmierung 2003/2004
164
164
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;
C-Programmierung 2003/2004
165
165
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;
C-Programmierung 2003/2004
166
166
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;
C-Programmierung 2003/2004
167
167
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; };
C-Programmierung 2003/2004
168
168
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
p-adressen
p-adressen
Kopie
personaldaten
p-adressen
C-Programmierung 2003/2004
169
169
Ä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; };
Zeiger
personaldaten
C-Programmierung 2003/2004
adressen
170
170
struct p-adressen homedaten;
struct personaldaten daten;
daten.adressen=&homedaten;
Zugriff auf die Werte:
daten.adressen->plz=07551;
Kopieren von verschachtelten Strukturen (flache Kopie)
Zeiger
personaldaten
adressen
Kopie
Zeiger
Personaldaten_1
Zeiger
C-Programmierung 2003/2004
171
171
Kopieren von verschachtelten Strukturen (tiefe Kopie)
personaldaten
Zeiger
adressen
Kopie
Kopie
Zeiger
personaldaten_1
adressen_1
C-Programmierung 2003/2004
172
172
Unions
Wenn 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;
Speicherplatzverschwendung,wenn nur ein Typ
abgelegt wird
char charwerte[20];
}
union werte
{int intzahl;
Es kann nur ein Typ gespeichert werden,
float floatzahl;
entweder intzahl oder floatzahl oder charwerte
charwerte[20];
}
C-Programmierung 2003/2004
173
173
#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);
Bei einer union benutzen alle
Elemente den gleichen Speicherplatz.
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);
}
C-Programmierung 2003/2004
174
174
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))
C-Programmierung 2003/2004
175
175
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.
C-Programmierung 2003/2004
!
176
176
#include "stdafx.h"
enum wochentage{MO,DI,MI,DO,FR,SA,SO};
Programm 31_1
Programm 31_1 .NET
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;
}
C-Programmierung 2003/2004
177
177
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;
C-Programmierung 2003/2004
178
178
Für Strukturen gilt dies analog:
typdef struct Adresse
{
int privatnr;
int dienstnr;
char ort[20];
}SAdressen;
SAdressen adr;
C-Programmierung 2003/2004
179
179
19. Arbeiten mit Dateien
Datei
Text-Datei
Binär-Datei
Um eine Datei zu öffnen wird die Funktion fopen benutzt. Eine Datei wird mit fclose
geschlossen. 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
C-Programmierung 2003/2004
180
180
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.
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.
C-Programmierung 2003/2004
181
181
Text-Dateien
Modus
Beschreibung
"r"
öffnet eine Textdatei zum lesen
"w"
erstellt eine Textdatei zum Schreiben. Der Inhalt einer
unter diesem Namen bereits existierenden Datei wird
gelö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 Dateipositionszeiger
steht am der Datei, dadurch werden neue Daten
hinten angehängt.
C-Programmierung 2003/2004
182
182
Ö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.
C-Programmierung 2003/2004
183
183
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.
fgets (name,länge,fileptr);
fputs (name,fileptr);
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);
C-Programmierung 2003/2004
184
184
#include <stdio.h>
#include <string.h>
#define DATNAME "test.txt"
//Programm 32
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");
Problem
getchar();
Tastaturpuffer
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");
}
}
C-Programmierung 2003/2004
185
185
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");
}
}
C-Programmierung 2003/2004
186
186
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");
}
}
}
C-Programmierung 2003/2004
187
187
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 eingeschlossen 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
Zuerst lesen, wenn EOF, dann
wird Schleife nicht abgearbeitet.
{
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 Dateipositionszeiger immer hinter das zuletzt geschriebene Zeichen.
C-Programmierung 2003/2004
188
188
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.
Programm32_1
fscan (fhd, "%i %s", x, s);
C-Programmierung 2003/2004
189
189
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 FileStruktur 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 fhd
zugeordnet ist. Danach enthält die Variable zeichen das eingelesene Zeichen.
C-Programmierung 2003/2004
190
190
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.
C-Programmierung 2003/2004
191
191
Modus
Beschreibung
"rb"
öffnet eine Binärdatei zum Lesen
"wb"
erstellt eine Binärdatei zum Schreiben. Der Inhalt einer bereits
bestehenden 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. Der
Inhalt 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.
C-Programmierung 2003/2004
192
192
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.
C-Programmierung 2003/2004
193
193
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.
C-Programmierung 2003/2004
194
194
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 Variablentypes
ermittelt und mit printf ausgegeben.
C-Programmierung 2003/2004
195
195
#include <stdio.h>
//Programm 33
#include <string.h>
#define DATNAME "test.txt"
#define MAXVORNAME 25
#define MAXNACHNAME 20
void 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");
}}
C-Programmierung 2003/2004
196
196
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);
}
}
C-Programmierung 2003/2004
197
197
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");
}
}
}
C-Programmierung 2003/2004
198
198
Dateipositionsanzeiger
Für Binärdateien gibt es die Möglichkeit ein spezielles Element aus der Datei zu bearbeiten. 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.
C-Programmierung 2003/2004
199
199
Programm 33_1
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);
}
}
C-Programmierung 2003/2004
200
200
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.
C-Programmierung 2003/2004
201
201
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 position
geschrieben. Ist die Funktion erfolgreich ausgeführt, dann gib die Funktion den Wert
0 zurück, welcher dann in der Variablen a gespeichert ist
C-Programmierung 2003/2004
202
202
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.
C-Programmierung 2003/2004
203
203
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.
C-Programmierung 2003/2004
204
204
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 */
}
C-Programmierung 2003/2004
205
205
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
C-Programmierung 2003/2004
206
206
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+");
C-Programmierung 2003/2004
207
207
Für die Aufgabe der Erzeugung einer temporären Datei kann auch die Funktion tmpfile
genutzt 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.
C-Programmierung 2003/2004
208
208
Anwendung der Funktion system zum löschen des Konsolenfensters.
#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();
}
}
C-Programmierung 2003/2004
209
209
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 Parameter
Die 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)
C-Programmierung 2003/2004
210
210
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+80
void main (void)
{int x;
x=WERTE*2; ...........;}
#define WERTE (80+80)
void main (void)
{int x;
x=WERTE*2;...........;}
C-Programmierung 2003/2004
211
211
#define mit Parameter
Es 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.
C-Programmierung 2003/2004
212
212
#undef
Mit 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"
#include
Die #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").
C-Programmierung 2003/2004
213
213
Die #include-Anweisung kann natürlich auch in Verbindung mit #define benutzt werden.
#define STD <stdio.h>
#define EIG "eigen.h"
#include STD
#include EIG
C-Programmierung 2003/2004
214
214
#if und #endif
Die #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.
C-Programmierung 2003/2004
215
215
#include <stdio.h>
// Programm 34
#define DEUTSCH 1
#define ENGLISCH 2
#define WERT DEUTSCH
void main(void)
{
int zahl;
#if WERT == DEUTSCH
printf("Bitte Wert eingeben:");
#endif
#if WERT == ENGLISCH
printf("Please enter a value:");
#endif
scanf("%i",&zahl);
}
C-Programmierung 2003/2004
216
216
Vordefinierte Makros
__DATE__
Makro steht für eine Stringkonstante mmm tt jjjj
Programm 43
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)
C-Programmierung 2003/2004
217
217
21. Programmier-Technologien
C-Programmierung 2003/2004
218
218
Headerdatei-1.h
xx-1.cpp
Headerdatei-2.h
Headerdatei-3.h
xx-2.cpp
Headerdatei-4.h
xx-3.cpp
xx-4.cpp
xx-3. obj
xx-4. obj
Compiler
xx-1. obj
xx-2. obj
Linker
Programm xx.exe
C-Programmierung 2003/2004
219
219
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>
Programm 40
#include <string.h>
#include "eigene-header-datei.h"
C-Programmierung 2003/2004
220
220
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
Namenskonventionen von C
#include …….
.
.
#endif
siehe auch Programm 40
C-Programmierung 2003/2004
221
221
Statische Variablen und Funktionen
Statische Variablen
Programm 41
static int rekfakul (int x, int y)
Programm 42
{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));
C-Programmierung 2003/2004
222
222
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
C-Programmierung 2003/2004
223
223
21.2. Rekursion
Von Rekursionen spricht man, wenn sich Funktionen selbst aufrufen.
//
//
#include <stdio.h>
Rekursion01.cpp
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();
}
Absturz des Programms durch Stack-Übrlauf
void main(void)
{
• immer neue Rücksprungadresse von rekfunk
rekfunk();
• immer neue Lokale Variable x
}
C-Programmierung 2003/2004
224
224
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.cpp
void main(void)
{int x;
Berechnung ohne rekursiven
do
Funktionsaufruf
{
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);
C-Programmierung 2003/2004
225
225
Berechnung auch wie folgt möglich:
#include <stdio.h>
x!=x*(x-1)! ; mit 0!=1
// 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));
}
C-Programmierung 2003/2004
226
226
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
C-Programmierung 2003/2004
227
227
Türme von Hanoi
0
A
B
C
1
A
B
C
2
A
B
C
3
A
B
C
4
A
B
C
5
A
B
C
6
A
B
C
7
A
C-Programmierung 2003/2004
B
C
228
228
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 notwendige
freie zusammenhängende Platz ist nicht größer als die Größe eines einzelnen Elementes
C-Programmierung 2003/2004
229
229
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
};
C-Programmierung 2003/2004
230
230
C-Programmierung 2003/2004
231
231
C-Programmierung 2003/2004
232
232
C-Programmierung 2003/2004
233
233
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);
C-Programmierung 2003/2004
234
234
Nutzung von malloc und free
#include <stdio.h>
#include <stdlib.h>
//Speicher01.cpp
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);
}
}
C-Programmierung 2003/2004
235
235
- 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)
C-Programmierung 2003/2004
236
236
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);
}
C-Programmierung 2003/2004
237
237
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.
C-Programmierung 2003/2004
238
238
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);
}
C-Programmierung 2003/2004
239
239
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);
}
C-Programmierung 2003/2004
240
240
Funktion zum Löschen der Liste und freigeben des Speichers
void ListDelAll(struct ListHead *hd)
{
struct Knot *cur=hd->head, *nex;
//ListDelAll ***************
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.
C-Programmierung 2003/2004
241
241
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);
}
}
C-Programmierung 2003/2004
242
242
Die Funktion zum Anzeigen der Liste:
void ListShow(struct ListHead *hd)
{
struct Knot *cur=hd->head;
//ListShow ******************
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;
}
}
C-Programmierung 2003/2004
243
243
Die main-Funktion
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);}
}
C-Programmierung 2003/2004
244
244
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
C-Programmierung 2003/2004
245
245
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
C-Programmierung 2003/2004
246
246
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
kann entfallen !!!
11 23 84 99
Austauschen, wenn a>b
kann entfallen !!!
11 23 84 99
Sortierung fertig
kann enffallen !!!
- 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
C-Programmierung 2003/2004
247
247
// 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;
}
C-Programmierung 2003/2004
248
248
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
C-Programmierung 2003/2004
249
249
21.6. Datenkomprimierung
- Lauflängencodierung
- Kodierung mit variabler Länge
- Huffmann Codierung
-
C-Programmierung 2003/2004
250
250
22. Zusammenfassung
C-Programmierung 2003/2004
251
251
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
C-Programmierung 2003/2004
252
252
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
C-Programmierung 2003/2004
253
253
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
C-Programmierung 2003/2004
254
254
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
C-Programmierung 2003/2004
255
255
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
C-Programmierung 2003/2004
256
256
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
a^b
exclusiv ODER Bitzuweisung 14
a|=b
ODER Bitzuweisung
14
a,b
Komma
15
14
C-Programmierung 2003/2004
257
257
Formatzeichen Gleitkommazahlen
FZ
Typ
Zahlensystem
f
double
Dezimal
*.*****
Lf
long double Dezimal
*.*****
e
double
Dezimal
*.***E**
Le
long double Dezimal
*.***E**
E
double
*.***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.
Dezimal
Besonderheit
C-Programmierung 2003/2004
258
258
Formatzeichen Strings
FZ
Typ
Besonderheit
c
char
einzelnes Zeichen
s
char[ ]
String mit abschließender 0
%
gibt % selbst aus
Formatzeichen Zeiger
FZ
Typ
n
int *
hn
short *
ln
long *
P
void *
Besonderheit
C-Programmierung 2003/2004
259
259
Formatzeichen Ganzzahlen
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
C-Programmierung 2003/2004
260
260
Ende
C-Programmierung 2003/2004
261
261
Zugehörige Unterlagen
Herunterladen