Programmierkurs C - Sommersemester 2011, 3. Vorlesung

Transcrição

Programmierkurs C - Sommersemester 2011, 3. Vorlesung
Programmierkurs C
Sommersemester 2011, 3. Vorlesung
Stuttgart, den 13. April 2011
Heiko Schulz
University of Stuttgart, Math. department
Rückschau
L
Operatoren: Vergleichsoperatoren, Zusammengesetze
Zuweisungsoperatoren, Inkrement- und Dekrementoperatoren.
L
Funktionen: Deklaration in Denition.
L
Variablen: Gültigkeit.
L
Kontrolluss: Bedingte Ausführung und Schleifen.
L
Bedingte Ausführung: if, case, bedingte Auswertung.
L
Schleifen: for, while, do...while, break, continue.
L
Dateneingabe mit scanf.
78
Programm: fehlersuche.c
79
Lösungen zum Aufgabenblatt 2:
#include
3 int
4
int
1
< s t d i o . h>
2
main ( )
5
{
i , j ,k;
p r i n t f ( " Moechten
(2) :
6
s c a n f ( "% i " ,
7
if
8
9
10
( k ==1
Sie
addieren
(1)
oder
multiplizieren
") ;
||
&k ) ;
k ==2)
{
p r i n t f ( " Geben
Sie
die
erste
") ;
11
s c a n f ( "% i " ,
12
p r i n t f ( " Und
die
13
s c a n f ( "% i " ,
&j ) ;
&i ) ;
Zweite :
") ;
natuerliche
Zahl
ein :
Programm: fehlersuche.c
14
if
15
16
17
}
18
}
22
{
else
{
return
else
return
+ %d
= %d
\n" ,
i ,
j ,
i+j ) ;
*
= %d
\n" ,
i ,
j ,
i
%d
0;
{
p r i n t f (" Falsche
23
25 }
1)
}
20
24
==
p r i n t f ( "%d
p r i n t f ( "%d
19
21
(k
80
}
1;
Eingabe !\ n" ) ;
*j);
Programm: mitternacht.c
/
*
mitternacht . c
#include
#include
int
float
main
81
*/
< s t d i o . h>
<m ath . h >
()
{
a ,b,c ,d;
printf (" Bitte
getrennt :
Werte
von
a ,b,c
eingeben ,
durch
Komma
") ;
s c a n f ( "%f ,% f ,% f " ,& a ,& b ,& c ) ;
d= s q r t ( b
* b 4* a * c ) ;
p r i n t f ( " Loesungen :
) /(2.0
}
return
0;
*a)) ;
%f
u n d %f \ n " , (
b+d ) / ( 2 . 0 * a ) ,
(
bd
Flieÿkommazahlen oat und double
L
Flieÿkommazahlen (auch Gleitkommazahl oder Gleitpunktzahl;
engl. oating point number) sind eine approximative Darstellung
der reellen Zahlen.
L
Festkommazahlen: meistens begrenzte Ziernfolge, an festgelegter
Stelle wird das Komma angenommen. Bei gröÿeren Rechnungen
Überläufe. Schlecht.
L
Mantisse m und dem Exponenten
1 B m @ b.
L
x > R mit zwei Werten: der
e: x
m be bezüglich Basis b.
Flieÿkomma: Darstellung einer Zahl
Bei Rechnungen mit Gleitkommazahlen wird jede Zahl und jedes
Zwischenergebnis individuell skaliert. Folge: Approximationsfehler,
Auslöschungseekte.
Ô
Ungültigkeit des Assoziativ- und Distributivitätsgesetzes!
82
Beispiel zur Stellenauslöschung
L
Die Gleichung
ax 2 bx c
x1~2
Für
a
D
Über
1, b
º
200, c
b2 4ac
R
0
hat die Lösungen
b
0.000015
º
83
º
b2 4ac
.
2a
gilt
2002 4 1 0.000015
200.00000015...,
sind die Lösungen also
x1
x2
ˆ200 200.00000015~2
ˆ200 200.00000015~2
0.000000075,
200.000000075.
Aber für 10-stellige Flieÿpunktzahlen erhält man:
x1
x2
ˆ200 200.0000001~2
ˆ200 200.0000001~2
0.00000005,
200.00000005.
Besserer Algorithmus
L
84
4
Grund: Stellenauslöschung bei Subtraktion. Beispiel (
über
R ˆ104 1 104
Stellen):
1
Aber:
ˆ1.000e4 1.000e0 1.000e4
1.0001e4 1.000e4
ˆ1.000e4 0.0001e4 1.000e4
1.000e4 1.000e4
0.
L
Beobachtung: Die betragsmäÿig gröÿere Lösung ist genauer.
L
Die Lösungen
b
º
x1
b2 4ac
2a
und
genügen der Identität
x1 x2
L
x2
2c
b
º
b2 4ac
c
.
a
Idee: betragsmäÿig gröÿere Lösung nden und mit Identität andere
bestimmen, keine Subtraktion. Im Beispiel (mit 10 Stellen):
x2
c ~ˆ200.00000005
0.000000075.
Modultechnik I
L
85
Ein Modul besteht aus der von auÿen sichtbaren Schnittstelle und
aus der von auÿen nicht sichtbaren Implementierung (Realisierung).
L
Die Implementierung kann von auÿen nicht verändert werden.
L
Alle Deklarationen und Denitionen, welche nicht Bestandteil der
Schnittstelle sind, sind von auÿen nicht sichtbar.
L
Das Verbergen der Implementierung nennt man information
hiding, Datenkapselung. Das ist als Schutz vor ungefugtem
Zugri von Bedeutung, aber auch für Übersichtlichkeit und
Trennung von Programmier-Verantwortlichkeiten.
L
Ein Programm kann unter Benutzung der Modultechnik aus
mehreren Modulen bestehen, welche untereinander nur über
Schnittstellen kommunizieren.
Modultechnik Beispiel
Präprozessor
86
stdio.h
programm.c
void printf(...);
#include <stdio.h>
#include <math.h>
math.h
double sqrt(double x);
double sin(double x);
int main() {...}
Compiler
programm.o (Objekt)
math.o
Linker
ausführebare Datei programm
(Windows: programm.exe)
stdio.o
Modultechnik II
L
87
Die Schnittstelle enthält Deklarationen von Typen, Konstanten und
Funktionen, welche für die Verwendung des Moduls benötigt
werden.
L
In C: sogenannte Header-Dateien, Endung: .h.
L
Die Implementierung enthält einerseits Deklarationen und
Denitionen von ausschlieÿlich intern verfügbaren Typen,
Konstanten und Funktionen und andererseits die Denitionen der
nach auÿen sichtbaren Routinen.
Modultechnik III
L
88
Jedes Modul kann einzeln compiliert werden. Kommuniziert es mit
anderen Modulen, so müssen lediglich deren Schnittstellen bekannt
sein. Dies erreicht man durch Einbinden der Header-Dateien der
entsprechenden Module mittels #include.
L
Ein Modul ist für sich alleine nicht ablauähig, da es nur einen Teil
des Programms darstellt (es fehlt
main-Funktion!).
Um ein
Programm zu erstellen, müssen die einzelnen Module mithilfe des
Linkers miteinander verbunden werden.
L
Der Programmierer muss entscheiden, wie er die Zerlegung eines
Programms in Module sinnvoll erreicht. Dabei sollen beispielsweise
Daten und zugehorige Aufgaben oder Aufgaben, die später an
anderer Stelle benötigt werden, gekapselt werden.
Funktionen: Rekursion
L
89
Rekursion (lat. recurrere zurücklaufen) ist die Technik, eine
Funktion durch sich selbst auf der Basis eines Anfangswertes zu
denieren.
L
Prominentes Beispiel: Fakultät,
L
Es gibt Problemstellungen, welche sich auf natürliche Weise einfach
n!
n ˆn 1!
per Rekursion lösen lassen.
L
Jede rekursive Funktion kann äquivalent über eine Schleife
berechnet werden (Beispiele: fakultät; Fibonnacci-Zahlen).
Rekursion Beispiel: Fakultät
int
int
return
else
return
fak (
if
}
}
n)
( n <=0)
{
{
1;
{
n
* f a k ( n 1) ;
}
oder noch kürzer
int
}
int
return
fak (
n)
n <=0
{
?
1
:
n
* f a k ( n 1) ;
90
Eindimensionale Felder I
L
91
Oft benötigt man einen zusammengehörigen Block von Variablen
gleichen Typs, wie beispielsweise die Komponenten eines Vektors.
Dafür verwendet man häug Felder, auch als Arrays oder
Vektoren
bezeichnet.
L
Ein Feld ist die Zusammenfassung einer Anzahl von Objekten des
gleichen Datentyps. Objekte heiÿen Elemente oder Einträge.
L
Syntax:
Deklaration:
datentyp arrayname [ dim ];
mit
dim>0
ganzzahlig
array[0]=1; array[i]=2;
Länge1!
Zugri mit dem Index-Operator []:
L
Achtung: Index immer von
L
Beispiel:
int
int
for
}
0
bis
i ;
vektor [10];
( i =0; i <10;
//
definiert
i ++)
vektor [ i ]:= i
*i
;
Feld
der
Laenge
{
// a l l e
Quadratzahlen
<=81
10
Eindimensionale Felder II
L
92
Man unterscheidet statische und variable Felder. Statische: Die
Dimension ist konstant, variabel: Dimension ist durch eine Variable
gegeben:
int
int
int
L
array1 [10];
// s t a t i s c h
dim =20;
a r r a y [ dim ] ;
// v a r i a b e l
Für statische Felder muss die Gröÿe also vor Programmstart
festgelegt werden, unexibel.
L
Oftmals ist es erforderlich, die Gröÿe eines Feldes während des
Programmverlaufs festzulegen.
L
Ô
Felder mit variabler Länge.
Ausblick: echte dynamische Felder, deren Gröÿe während des
Programmlaufs jederzeit angepasst werden kann, sind durch
Zeiger realisierbar.
Eindimensionale Felder Hinweise
L
93
Nur bei der Deklaration ist eine gesammelte Zuweisung der Form
int
int
intarray2 [4]
intarray3 []
=
=
{0 ,1 ,2 ,3};
{0 ,1 ,2 ,3};
// a e q u i v a l e n t
zu
intarray2
möglich, sonst nur elementweise. Bei einer Deklaration mit
kombinierter Zuweisung kann die Gröÿe weggelassen werden.
L
Noch ein Beispiel mit gesammelter Zuweisung:
L
Der von einem Feld benötigten Speicherplatz in Bytes kann mithilfe
des sizeof-Operators bestimmt werden:
1
2
char
sizeof
chararray [10];
(
chararray
) ;
// l i e f e r t
den
Wert
10
Eindimensionale Felder Beispiel
/
/
*
*
" Inneres
Produkt "
innerproduct3 . c
#include
int
int
double
double
int
*/
zweier
Vektoren
94
aus
R^3
*/
< s t d i o . h>
main
()
{
DIM = 3 ;
v 1 [ DIM ]
,
v 2 [ DIM ] ;
ip ;
i ;
printf
(" Skalarprodukt
printf
(" Bitte
for
( i =0;
printf
scanf
printf
scanf
}
geben
i <DIM ;
( "a_%d
( "% l f " ,
( "b_%d
( "% l f " ,
i ++)
=
zweier
sie
{
die
// e i n l e s e n
" , i ) ;
&v 1 [ i ] ) ;
=
Vektoren \n" ) ;
Vektoren
" , i ) ;
&v 2 [ i ] ) ;
der
a ,b
e i n : \ n" ) ;
Vektoren
Eindimensionale Felder Beispiel
//
Berechnen
ip
for
=
//
Ausgeben
Skalarprodukts
0.0;
( i =0;
i <DIM ;
ip
v1 [ i ]
printf
+=
return
des
( "\ nDer
betraegt :
}
des
95
0;
*
i ++)
v2 [ i ] ;
Eregnisses
Wert
des
%f \ n " , i p ) ;
Skalarprodukts
von
a
und
b
Eindimensionale Felder Beispiel
/
/
*
*
" Inneres
Produkt "
*/
innerproduct . c
#include
int
int
double
int
zweier
Vektoren
96
in
R^d
*/
< s t d i o . h>
main
()
{
DIM = 3 ;
ip ;
i ;
printf
(" Skalarprodukt
printf
(" Bitte
ein :
scanf
double
geben
die
Vektoren \n" ) ;
Dimension
der
Vektoren
") ;
( "% i " ,
&DIM ) ;
v 1 [ DIM ]
,
v 2 [ DIM ] ;
p r i n t f ( " s i z e o f ( v1 )
printf
zweier
sie
(" Bitte
= % l i \n" ,
geben
sie
die
sizeof
( v1 ) ) ;
Vektoren
a ,b
e i n : \ n" ) ;
Eindimensionale Felder Beispiel
for
( i =0;
i <DIM ;
printf
scanf
( "% l f " ,
printf
scanf
i ++)
( "a_%d
( "b_%d
( "% l f " ,
=
{
// e i n l e s e n
97
der
Vektoren
" , i ) ;
&v 1 [ i ] ) ;
=
" , i ) ;
&v 2 [ i ] ) ;
}
//
Berechnen
ip
for
=
//
Ausgeben
( i =0;
i <DIM ;
ip
v1 [ i ]
printf
+=
return
des
( "\ nDer
betraegt :
}
des
Skalarprodukts
0.0;
0;
*
i ++)
v2 [ i ] ;
Eregnisses
Wert
des
%f \ n " , i p ) ;
Skalarprodukts
von
a
und
b
Mehrdimensionale Felder
L
98
Oftmals kommt man mit eindimensionalen Feldern nicht aus,
beispielsweise bei der Verwendung von Matrizen.
L
Für solche Fälle ist die Denition mehrdimensionaler Felder
möglich. Beispiel:
double matrix [7][6];
deniert ein Feld mit
7 Zeilen und 6 Spalten.
L
Analog: höherdimensionale Felder.
L
C kennt (intern) nur eindimensionale Felder. Beispielsweise wird ein
zweidimensionales Feld dadurch simuliert, dass jedes Feldelement
eines zweidimensionalen Feldes wieder ein eindimensionales Feld ist.
L
Eigene Simulation von mehrdimensionalen Feldern durch
eindimensionale:
int matrix[m*n]; statt int matrix[i][j];,
matrix[i*n+j] statt matrix[i][j]
Deklaration:
Zugri:
Mehrdimensionale Felder Beispielprogramm
/
*
matadd . c
#include
int
int
double
*/
< s t d i o . h>
main
()
{
DIM = 3 ;
printf
for
m a t r i x 1 [ DIM ] [ DIM ] ,
m a t r i x 2 [ DIM ] [ DIM ] ,
sum [ DIM ] [ DIM ] ;
(" Addition
int
for int
(
i
=0;
(
printf
scanf
printf
scanf
j
i
zweier
Matrizen
< DIM ;
i
=0;
j
< DIM ;
( "A[% d ,% d ]
( "% l f " ,
=
\n\n" ) ;
{
j
++)
{
" ,
i +1
,
j +1) ;
&m a t r i x 1 [ i ] [ j ] ) ;
( "B[% d ,% d ]
( "% l f " ,
++)
=
" ,
i +1
,
j +1) ;
&m a t r i x 2 [ i ] [ j ] ) ;
sum [ i ] [ j ] = m a t r i x 1 [ i ] [ j ] + m a t r i x 2 [ i ] [ j ] ;
}
p r i n t f ( "\n" ) ;
}
}
99
Zeiger (englisch: pointer)
L
100
Der Inhalt einer Zeigervariable ist eine Adresse im Speicher des
Computers.
L
Ein Zeiger zeigt also auf eine Adresse im Speicher.
L
Die Deklaration von Zeigern erfolgt durch Hinzunahme eines Sterns
als Präx zum Variablennamen. Z.B. wird durch
int
*zeiger
;
ein Zeiger deklariert, die auf
L
int-Speicherplätze
zeigen kann.
Der Typ und die Gröÿe des Objektes, auf welches ein Zeiger zeigen
kann, sind in der Deklaration festgelegt.
L
1
Problem: Zuweisung der Form
z e i g e r =123;
sind gültig, verändert aber nur die Adresse, auf die gezeigt wird,
was evtl. nicht die Absicht des Programmierers war.
Zeiger Referenzierung und Dereferenzierung
L
101
Zugri auf den Wert, auf den gezeigt wird, hat man mit dem
Dereferenzierungs-Operator *. Umgekehrt liefert der
Referenzierungs-Operator & die Adresse einer Variablen, welche
dann einem Zeiger zugewiesen werden kann. Beispiel:
1
float
float
// f
hat
// z
zeigt
irgendwohin
5 z=& f ;
// nun
zeigt
z
6
// d e r
Speicherstelle ,
7
// d e r
float
8
// f
2
3
f ;
*z ;
irgendeinen
4 f =5.0;
*z =1.0;
hat
nun
auf
f ,
Wert
*z
hat
auf
den
die
z
Wert
1.0
zugewiesen
also
den
Wert
1.0
Wert
5.0
zeigt ,
wird
Zeiger Typisierung
L
So wie man sich Variablen als benannte Speicherbereiche vorstellen
kann, so kann man sich Zeiger als benannte Speicheradressen
vorstellen.
L
Referenziert man eine Variable, so erhält man den zugehörigen
Zeiger, dereferenziert man einen Zeiger, so erhalten wir den Wert
der zugehörigen Variable.
L
102
Der Typ des Zeigers legt dabei fest, wie groÿ der Speicherbereich,
auf den der Zeiger zeigt ist, und wie der Inhalt dieses
Speicherbereichs interpretiert wird.
Zeiger und Felder
L
103
In C besteht ein enger Zusammenhang zwischen Feldern und
Zeigern: Der Name eines Felds ist ein konstanter Zeiger auf das
erste Feld-Element (Referenz auf das erste Feld-Element).
int
int
int
zahl ;
vektor [3]
*zeiger
zeiger
zahl
=
=
=
{1 ,2 ,3};
;
vektor ;
*zeiger
;
// o d e r :
zeiger
// o d e r :
zahl
=
* vektor
// o d e r :
zahl
=
vektor [0]
// a l s o
L
zahl
jetzt
*( z e i g e r +1) ;
Allgemeiner sind
;
den
zeiger auf das erste Element eines Felds,
zeiger+1 auf das zweite Element dieses Felds:
Zeigt
zahl =
L
hat
= &v e k t o r [ 0 ] ;
dann zeigt
*( v e k t o r +1) ;
// o d e r :
zahl =
// o d e r :
zahl=vektor [ 1 ] ;
vektor[n]
und
Wert
*(vektor+n)
die gleichen
Elemente. Der Feld-Zugrisoperator [] ist auch für Zeiger
verwendbar.
1
Zeiger und Felder Beispielprogramm
/
*
array . c
#include
int
int
double
for
*/
< s t d i o . h>
main
()
i ,
{
n =3;
array [ n ] ;
( i =0;
i <n ;
a r r a y [ i ]= i
i ++)
*i
{
;
p r i n t f ( " a r r a y [% d ]
}
}
return
0;
= %f \ n " , i ,
*(
array+i ) ) ;
104
Zeiger Hinweise und Gefahren
L
Zeiger sind mächtig (und) gefährlich uninitialisierte Zeiger sind
die gröÿte Fehlerquelle in C-Programmen.
L
Zeigerdeklaration führt nur zur Bereitstellung des Speichers,
welcher die Adresse enthält! Der Speicher für das Objekt, auf das
der Zeiger zeigt, muss gegebenenfalls noch beschat (alloziert)
werden. Vergisst man die Zuweisung von Speicher für das Objekt,
wie in
int
*iptr ;
* i p t r = 5;
führt dies zum Überschreiben einer zufälligen Speicheradresse.
L
Zur Vermeidung solcher Fehler ist eine Initialisierung von Zeigern
mit 0 bzw. NULL (Zeigernull) nützlich.
105
Zeiger Hinweise und Gefahren
L
106
Eine weitere Gefahr bei Zeigern auf Felder besteht im
Darüberhinausschreiben über Feldgrenzen:
int
*iptr
,
arr [20]=0;
arr [20];
// F e h l e r !
iptr=arr ;
*(
i p t r +20) =0;
iptr [20]=0;
L
// g l e i c h e r
// g l e i c h e r
Fehler !
Fehler !
Eine Feldgrenzen-Verletzung ist meist schwieriger zu nden als eine
fehlende Initialisierung (Angezeigter Fehler: segmentation fault,
deutsch: Speicherzugrisfehler, Zugrisverletzung,
Schutzverletzung).
Zeiger fehlerhaftes Beispiel
Der folgende Quelltext lässt sich problemlos kompilieren
/
*
wrongarray . c
#include
int
main
*/
< s t d i o . h>
()
int
double
for
i ,
{
n =3;
* array
( i =0;
;
i <n ;
i ++)
*( a r r a y + i )= i * i
}
}
return
0;
;
{
107
Zeiger fehlerhaftes Beispiel
108
Man compiliert mit:
$ gcc -std=c99 wrongarray.c -o wrongarray
Nach dem Programmstart erhält man aber die folgende Fehlermeldung:
$ ./ array
segmentation fault ./ array
Was ist passiert?
Es wurde auf einen Speicherbereich zugegrien, der nicht vorher
alloziert wurde.
Zeichenketten
109
L
Zeichenketten (Strings) werden in C mit Hilfe von Feldern realisiert.
L
Der Datentyp eines Zeichens ist char (Ganzzahl-Datentyp).
Zahl
L
Zeichen über ASCII-Tabelle.
Ein C-String ist ein char-Feld und wird durch das Sonderzeichen \0
abgeschlossen.
L
Während char-Konstanten in Hochkommata geschrieben werden
(z.B. 'a'), a wird eine String-Konstante in Anführungszeichen
geschrieben (z.B. abc). Beachte: 'a' und a sind nicht gleich:
'a' ist gleich a, a ist gleich a\0.
L
Eine Zeichenkette der Länge n benötigt also ein char-Feld der
Gröÿe n + 1. Der leere String benötigt ein Byte Speicherplatz.
Regular ASCII Chart (character codes 0 127)
000d
001d
002d
003d
004d
005d
006d
007d
008d
009d
010d
011d
012d
013d
014d
015d
00h
01h
02h
03h
04h
05h
06h
07h
08h
09h
0Ah
0Bh
0Ch
0Dh
0Eh
0Fh
128d
129d
130d
131d
132d
133d
134d
135d
136d
137d
138d
139d
140d
141d
142d
143d
80h
81h
82h
83h
84h
85h
86h
87h
88h
89h
8Ah
8Bh
8Ch
8Dh
8Eh
8Fh
␀
␁
␂
␃
␄
␅
␆
␇
␈
␊
␋
␍
␎
␏
(nul)
(soh)
(stx)
(etx)
(eot)
(enq)
(ack)
(bel)
(bs)
(tab)
(lf)
(vt)
(np)
(cr)
(so)
(si)
016d
017d
018d
019d
020d
021d
022d
023d
024d
025d
026d
027d
028d
029d
030d
031d
10h
11h
12h
13h
14h
15h
16h
17h
18h
19h
1Ah
1Bh
1Ch
1Dh
1Eh
1Fh
144d
145d
146d
147d
148d
149d
150d
151d
152d
153d
154d
155d
156d
157d
158d
159d
90h
91h
92h
93h
94h
95h
96h
97h
98h
99h
9Ah
9Bh
9Ch
9Dh
9Eh
9Fh
␐
␑
␒
␓
␔
␕
␖
␗
␘
␙
␛
␜
␝
␞
␟
(dle)
(dc1)
(dc2)
(dc3)
(dc4)
(nak)
(syn)
(etb)
(can)
(em)
(eof)
(esc)
(fs)
(gs)
(rs)
(us)
032d
033d
034d
035d
036d
037d
038d
039d
040d
041d
042d
043d
044d
045d
046d
047d
20h
21h
22h
23h
24h
25h
26h
27h
28h
29h
2Ah
2Bh
2Ch
2Dh
2Eh
2Fh
!
"
#
$
%
&
'
(
)
*
+
'
.
/
048d
049d
050d
051d
052d
053d
054d
055d
056d
057d
058d
059d
060d
061d
062d
063d
30h
31h
32h
33h
34h
35h
36h
37h
38h
39h
3Ah
3Bh
3Ch
3Dh
3Eh
3Fh
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
064d
065d
066d
067d
068d
069d
070d
071d
072d
073d
074d
075d
076d
077d
078d
079d
40h
41h
42h
43h
44h
45h
46h
47h
48h
49h
4Ah
4Bh
4Ch
4Dh
4Eh
4Fh
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
080d
081d
082d
083d
084d
085d
086d
087d
088d
089d
090d
091d
092d
093d
094d
095d
50h
51h
52h
53h
54h
55h
56h
57h
58h
59h
5Ah
5Bh
5Ch
5Dh
5Eh
5Fh
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
_
096d
097d
098d
099d
100d
101d
102d
103d
104d
105d
106d
107d
108d
109d
110d
111d
60h
61h
62h
63h
64h
65h
66h
67h
68h
69h
6Ah
6Bh
6Ch
6Dh
6Eh
6Fh
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
112d
113d
114d
115d
116d
117d
118d
119d
120d
121d
122d
123d
124d
125d
126d
127d
70h
71h
72h
73h
74h
75h
76h
77h
78h
79h
7Ah
7Bh
7Ch
7Dh
7Eh
7Fh
p
q
r
s
t
u
v
w
x
y
z
{
|
}
␡
D0h
D1h
D2h
D3h
D4h
D5h
D6h
D7h
D8h
D9h
DAh
DBh
DCh
DDh
DEh
DFh
Ð
Ñ
Ò
Ó
Ô
Õ
Ö
Ö
Ø
Ù
Ú
Û
Ü
Ý
Þ
ÿ
224d
225d
226d
227d
228d
229d
230d
231d
232d
233d
234d
235d
236d
237d
238d
239d
E0h
E1h
E2h
E3h
E4h
E5h
E6h
E7h
E8h
E9h
EAh
EBh
ECh
EDh
EEh
EFh
à
á
â
ã
ä
å
æ
ç
è
é
ê
ë
ì
í
î
ï
240d
241d
242d
243d
244d
245d
246d
247d
248d
249d
250d
251d
252d
253d
254d
255d
F0h
F1h
F2h
F3h
F4h
F5h
F6h
F7h
F8h
F9h
FAh
FBh
FCh
FDh
FEh
FFh
ð
ñ
ò
ó
ô
õ
ö
ö
ø
ù
ú
û
ü
ý
þ
¸
Extended ASCII Chart (character codes 128 255) Latin1/CP1252
e
f
...
„
…
^
%
’
×
š
Hexadecimal to Binary
0
1
2
3
0000
0001
0010
0011
4
5
6
7
0100
0101
0110
0111
8
9
A
B
1000
1001
1010
1011
`
'
ˆ
~
—
²
÷
º
˜
160d
161d
162d
163d
164d
165d
166d
167d
168d
169d
170d
171d
172d
173d
174d
175d
A0h
A1h
A2h
A3h
A4h
A5h
A6h
A7h
A8h
A9h
AAh
ABh
ACh
ADh
AEh
AFh
½
¢
¿
¤
¥
¦
Ÿ
¨
©
ª
¬
®
¯
176d
177d
178d
179d
180d
181d
182d
183d
184d
185d
186d
187d
188d
189d
190d
191d
B0h
B1h
B2h
B3h
B4h
B5h
B6h
B7h
B8h
B9h
BAh
BBh
BCh
BDh
BEh
BFh
°
±
²
³
´
µ
¶
·
¹
º
¼
½
¾
¾
192d
193d
194d
195d
196d
197d
198d
199d
200d
201d
202d
203d
204d
205d
206d
207d
C0h
C1h
C2h
C3h
C4h
C5h
C6h
C7h
C8h
C9h
CAh
CBh
CCh
CDh
CEh
CFh
À
Á
Â
Ã
Ä
Å
Æ
Ç
È
É
Ê
Ë
Ì
Í
Î
Ï
208d
209d
210d
211d
212d
213d
214d
215d
216d
217d
218d
219d
220d
221d
222d
223d
Groups of ASCII-Code in Binary
C
D
E
F
1100
1101
1110
1111
Bit 6
0
0
1
1
Bit 5
0
1
0
1
Group
Control Characters
Digits and Punctuation
Upper Case and Special
Lower Case and Special
2009 Michael Goerz
This work is licensed under the Creative Commons
Attribution-Noncommercial-Share Alike 3.0 License.
To view a copy of this license, visit
http://creativecommons.org/licenses/by-nc-sa/
Zeichenketten Beispiel
char
char
char
int
for
111
a r r a y 1 [ 5 ] = { 'H ' , ' e ' , ' l ' , ' l ' , ' o ' } ;
array2 [8]={ ' , ' , '
// k e i n
String
' , 'w ' , ' o ' , ' r ' , ' l ' , ' d ' , ' \0 ' } ;
string1 [50];
i ;
( i = 0 ; i < 5 ; i ++)
{
// k o p i e r e
array1
nach
string
array2
nach
string
s t r i n g 1 [ i ]= a r r a y 1 [ i ] ;
}
for
( i = 0 ; i < 8 ; i ++)
{
// k o p i e r e
s t r i n g 1 [ i +5]= a r r a y 2 [ i ] ;
}
p r i n t f ( "%s \ n " , s t r i n g 1 ) ;
// d a s
char
gleiche :
s t r i n g 2 []= " Hello ,
world " ;
p r i n t f ( "%s \ n " , s t r i n g 2 ) ;
printf
( "%c %d \ n " ,
111
aus
string1 [8] ,
string1 [8]) ;
//
gibt
o
und
Funktionen für den Umgang mit Strings
L
112
Das elementweise Arbeiten wie mit Feldern ist möglich, aber
umständlich.
L
In der Standardbibliothek gibt es Funktionen für die wichtigsten
String-Operationen. Diese sind in string.h deklariert.
L
Beispiele: Kopieren (strcpy, strncpy), Anfügen (strcat), Vergleichen
(strcmp), Länge ermitteln (strlen).
L
Vorsicht: Strings sind char-Felder, d.h. beim Kopieren und
Anhängen muss das Zielfeld groÿ genug sein! Siehe auch strncpy.
Zeichenketten vergleichen strcmp
L
113
strcmp() dient zum Vergleich zweier Strings. Beschreibung:
int strcmp ( const char * string1 , const char *
string2 )
L
Die Funktion strcmp() vergleicht die beiden Zeichenketten
byteweise. Sie liefert einen positiven Wert für
einen negativen Wert für
string1
<
string2
string1
>
string2,
und 0, falls die
Strings identisch sind.
L
Vorsicht: Ein Vergleich der Art
if (string1==string2)
prüft nicht alphabetisch auf Zeichengleichheit, es werden lediglich
die Anfangsadressen verglichen.
Zeichenketten Beispielprogramm
/
*
stringsvergleich .c
#include
#include
int
char
char
int
114
*/
< s t d i o . h>
< s t r i n g . h>
main ( ) {
s 1 [ ] = " Pommes
von
Burger
s 2 [ ] = " Pommes
von
McDonalds " ;
King " ;
x;
p r i n t f ( " Welche
Pommes
sind
b e s s e r ?\ n " ) ;
x= s t r c m p ( s1 , s 2 ) ;
if
}
( x <0)
{
p r i n t f ( "%s ! \ n " , s 2 ) ;
else i f
else
( x >0)
{
p r i n t f ( "%s ! \ n " , s 1 ) ;
}
{
p r i n t f ( " D i e %s
}
u n d %s
sind
gleich
gut . \ n" ,
s1 ,
s2 ) ;
Zeichenketten Beispielprogramm
p r i n t f ( "\ nAber
int
int
if
else i f
else
welche
Pommes
sind
115
l a e n g e r ?\ n " ) ;
l a e n g e 1= s t r l e n ( s1 ) ;
l a e n g e 2= s t r l e n ( s2 ) ;
( laenge1 <laenge2 )
p r i n t f ( " D i e %s
}
sind
{
l a e n g e r !\ n" , s1 ) ;
{
p r i n t f ( " D i e %s
s2 ) ;
}
l a e n g e r !\ n" , s2 ) ;
( laenge1 >laenge2 )
p r i n t f ( " D i e %s
}
{
sind
u n d %s
sind
gleich
l a n g . \ n\n" ,
s1 ,
Zeichenketten Beispielprogramm
char
ungesund [ 1 0 0 ] ;
s t r c p y ( ungesund ,
s t r c a t ( ungesund ,
s1 ) ;
s t r c a t ( ungesund ,
"
s t r c a t ( ungesund ,
s2 ) ;
s t r c a t ( ungesund ,
"
p r i n t f ( "%s \ n " ,
//
Einfacher :
char
mit
( String )
als
sowohl
auch
sind
lang
genug ?
") ;
") ;
ungesund . " ) ;
ungesund ) ;
sprintf :
ungesund2 [ 8 0 ] ;
s p r i n t f ( ungesund2 ,
" Aber
ungesund . " ,
s1 ) ;
p r i n t f ( "%s \ n " ,
}
//
"\ nAber
116
return
0;
s2 ,
s o w o h l %s
ungesund2 ) ;
als
a u c h %s
sind
Call by value und Call by reference
L
In C ist für Funktionen ist nur ein Rückgabewert erlaubt.
L
Eine Möglichkeit diese Einschränkung zu umgehen, ist die
117
Verwendung globaler Variablen - schlechter Stil, unübersichtlich,
fehleranfällig.
L
Eine weitere, bessere Möglichkeit ist die folgende: Man übergibt
anstelle des Wertes einer Variablen (Call by value) die Adresse
dieser Variablen (Call by reference).
L
Die Funktion kann dann den Wert
an
dieser Adresse verändern und
er steht danach an bekannter Stelle zur Verfügung.
L
Beispiel:
scanf:
s c a n f ( "% i " ,
&k ) ;
Call by value und Call by reference Beispiel
/
*
118
*/
callref1 .c
#include
void
float
if
return
< s t d i o . h>
betrag (
( x <0.0)
;
{
x=
x)
x ;
{
// v e r a e n d e r t
nichts !
}
// o p t i o n a l
}
int
main ( )
float
x=
{
x ,
*z ;
1.5;
betrag (x ) ;
// w i r
uebergeben
value
p r i n t f ( "%f \ n " , x ) ;
z=&x ;
betrag (
// d a s
// e s
gleiche
* z ) ; // w i r
wird
wie
uebergeben
value
p r i n t f ( "%f \ n " , x ) ;
return
0;
// e s
wird
den
Wert
1.5
1.5
x ,
call
by
ausgegeben
zuvor ,
den
von
x
Wert
wird
von
veraendert
z ,
ausgegeben
call
by
Call by value und Call by reference Beispiel
/
*
119
*/
callref2 .c
#include
void
float *
if *
*
return
< s t d i o . h>
betrag (
(
x <0.0)
;
{
x)
x=
{
* x ;
}
// o p t i o n a l
}
int
main ( )
float
x=
{
*z ;
x ,
1.5;
b e t r a g (& x ) ;
den
// w i r
Wert ,
p r i n t f ( "%f \ n " , x ) ;
z=&x ;
// d a s
* z = 2;
uebergeben
call
by
// e s
gleiche
b e t r a g (& x ) ;
p r i n t f ( "%f
%f \ n " , x ,
ausgegeben
return
0;
die
Adresse
von
x ,
nicht
reference
*z) ;
wird
wie
1.5
ausgegeben
zuvor ,
// e s
wird
x
wird
2.0
und
veraendert :
2.0
Sinnvolles Beispielprogramm
120
Zeiger ermöglichen das Ändern von Funktionsargumenten:
1 /*
2
3
4 //
5
6
double
*a
*b
9
=
der
double
swap (
tmp
8
< s t d i o . h>
Vertauschen
void
7
*/
swap . c
#include
tmp ;
Werte *a
,
von
double
a
*b
*a ;
=
*b ;
=
tmp ;
10 }
11
12
13
int
main
()
double
14
x =2.0;
15
y =3.1;
{
x
,
y;
16
17
p r i n t f ( " x=% l f ,
18
s w a p (& x ,& y ) ;
19
return
20
p r i n t f ( " x=% l f ,
0;
}
y=% l f \ n " , x , y ) ;
y=% l f \ n " , x , y ) ;
und
)
{
b
Vielen Dank...
... für Ihre Aufmerksamkeit und bis
morgen...
121